package math.coeff;

public class CoeffUtil {
    private CoeffUtil() {
    }

    /**
     * @param n - liczba gatunków w próbie
     * @param N - łączna liczba osobników (wszystkie gatunki razem
     * @return wskażnik Margalefa
     */
    public static double margalef(double n, double N) {
        return (n - 1) / Math.log(N);
    }

    /**
     * Oblicza wskaźnik Simpsona dla próby
     *
     * @param n to tabela grupująca informację. Liczba gatunków
     *          jest równa długości tabeli. W każdej komórce podano liczbę
     *          osobników danego gatunku
     * @return wskaźnik Simpsona
     */
    public static double simpsonSample(double[] n) {
        double sum1 = 0;
        double sum2 = 0;
        for (double v1 : n) {
            sum1 += v1;
        }
        double nn = sum1 * (sum1 - 1);
        for (double v : n) {
            sum2 += v * (v - 1.0) / nn;
        }
        return 1.0 - sum2;
    }

    /**
     * Oblicza wskaźnik Simpsona dla populacji generalnej
     *
     * @param n to tabela grupująca informację. Liczba gatunków
     *          jest równa długości tabeli. W każdej komórce podano liczbę
     *          osobników danego gatunku
     * @return wskaźnik Simpsona
     */
    public static double simpsonEnviron(double[] n) {
        double sum1 = 0;
        double sum2 = 0;
        for (double v1 : n) {
            sum1 += v1;
        }
        for (double v : n) {
            sum2 += Math.pow(v / sum1, 2);
        }
        return 1.0 - sum2;
    }

    /**
     * Oblicza wskaźnik Shanona - Wienera dla próby oraz jego wartość
     * maksymalną i minimalną
     *
     * @param n to tabela grupująca informację. Liczba gatunków
     *          jest równa długości tabeli. W każdej komórce podano liczbę
     *          osobników danego gatunku
     * @return tablicę zawierającą:
     * [0] - minimalna wartość
     * [1] - wskaźnik Shannona - Wienera
     * [2] - maksymalna wartość
     */
    public static double[] shannonWiener(double[] n) {
        double sum1 = 0;
        double sum2 = 0;
        double[] total = new double[3];
        for (double v1 : n) {
            sum1 += v1;
        }
        for (double v : n) {
            sum2 += (v / sum1) * Math.log(v / sum1);
        }
        total[1] = -1.0 * sum2;
        total[0] = hMin(n.length, sum1);
        total[2] = hMax(n.length);
        return total;
    }

    /**
     * Oblicza maksymalną wielkość wskaźnika Shannona -Wienera
     *
     * @param n - liczba gatunków
     * @return wartość maksymalna wskaźnika Shannona - Wienera
     */
    private static double hMax(double n) {
        return Math.log(n);
    }

    /**
     * Oblicza wartość minimalną wskaźnika Shannona - Wienera
     *
     * @param n - liczba gatunków w próbie
     * @param N - łączna liczba osobników (wszystkie gatunki razem
     * @return wartość minimalna wskaźnika Shannona - Wienera
     */
    private static double hMin(double n, double N) {
        return Math.log(N) - (N - n + 1) * Math.log(N - n + 1) / N;
    }

    /**
     * Oblicza wskaźnik pielou próby oraz jego wartość
     * maksymalną i minimalną
     *
     * @param n to tabela grupująca informację. Liczba gatunków
     *          jest równa długości tabeli. W każdej komórce podano liczbę
     *          osobników danego gatunku
     * @return tablicę zawierającą:
     * [0] - minimalna wartość
     * [1] - wskaźnik Pielou
     * [2] - maksymalna wartość
     */
    public static double[] pielou(double[] n) {
        double[] shan = shannonWiener(n);
        double[] total = new double[3];
        total[0] = shan[0] / shan[2];
        total[1] = shan[1] / shan[2];
        total[2] = 1;
        return total;
    }

    /**
     * Określa gatunkowe podobieństwo środowisk
     *
     * @param na  - liczba gatunków w środowsku a
     * @param nb  - liczba gatunków w środowisku b
     * @param nab - liczba gatunków wspolnych (występujących i w
     *            jednym i w drugim środowisku
     * @return - wskaźnik Jaccarda
     */
    public static double jaccard(double na, double nb, double nab) {
        return nab / (na + nb - nab);
    }

    /**
     * Określa gatunkowe podobieństwo środowisk
     *
     * @param na  - liczba gatunków w środowsku a
     * @param nb  - liczba gatunków w środowisku b
     * @param nab - liczba gatunków wspolnych (występujących i w
     *            jednym i w drugim środowisku
     * @return - wskaźnik Sorensona
     */
    public static double sorenson1(double na, double nb, double nab) {
        return 2 * nab / (na + nb);
    }

    /**
     * Oblicza liczbowe podobieństwo  środowisk
     *
     * @param a - tabela liczebności gatunków w środowisku a
     * @param b - tabela liczebności w środowisku b
     *          Zakłada się, że dany gatunek występuje w obu tabelach na tej
     *          samej pozycji
     * @return wskaźnik Sorensona
     */
    public static double sorenson2(double[] a, double[] b) {
        double suma = 0;
        double sumb = 0;
        double sumc = 0;
        for (int i = 0; i < a.length; i++) {
            suma += a[i];
            sumb += b[i];
            sumc += Math.min(a[i], b[i]);
        }
        return 2 * sumc / (suma + sumb);
    }

    /**
     * Oblicza liczbowe podobieństwo środowisk
     *
     * @param a - tabela liczebności gatunku w środowisku a
     * @param b - tabela liczebności gatunku w środowisku b
     *          Zakłada się, że dany gatunek występuje w obu tabelach na tej
     *          samej pozycji
     * @return wskaźnik Euklidesa
     */
    public static double euklides(double[] a, double[] b) {
        int gat = a.length;
        double sum = 0;
        for (int i = 0; i < gat; i++) {
            sum += Math.pow(a[i] - b[i], 2.0);
        }
        return Math.sqrt(sum / gat);
    }
}
