/*
 * The MIT License
 *
 * Copyright © 2014 Filip Plesinger, Juraj Jurco.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * 
 * Authors: 
 * 
 * Filip Plesinger <fplesinger@isibrno.cz>
 * Institute of Scientific Instruments of the ASCR, v. v. i.
 * Brno, Czech Republic
 * 
 * Juraj Jurco <xjuraj@isibrno.cz>
 * Institute of Scientific Instruments of the ASCR, v. v. i.
 * Brno, Czech Republic
 */

package cz.academyofscience.upt.challenge2014;

import java.util.List;

/**
 *
 * @author xjuraj
 */
public class Statistics {

    public String channelName;
    public String markerInfo;
    public int dataStart;
    public int dataEnd;
    public int n;
    public int nNAN;
    public float avg;
    public float min;
    public float max;
    public float med;
    public float dev;
    public float perc25;
    public float perc75;

    public float kurtosis;

    public List<Float> dataCache;

    public static Double correlation(double[] Xs, double[] Ys) {
        double sumX = 0.0;
        double sumX2 = 0.0;
        double sumY = 0.0;
        double sumY2 = 0.0;
        double sumXY = 0.0;

        int n = Xs.length < Ys.length ? Xs.length : Ys.length;

        for (int i = 0; i < n; ++i) {
            double x = Xs[i];
            double y = Ys[i];

            sumX += x;
            sumX2 += x * x;
            sumY += y;
            sumY2 += y * y;
            sumXY += x * y;
        }

        double stdX = (double) Math.sqrt(sumX2 / (double) n - sumX * sumX / (double) n / (double) n);
        double stdY = (double) Math.sqrt(sumY2 / (double) n - sumY * sumY / (double) n / (double) n);
        double covariance = (double) (sumXY / (double) n - sumX * sumY / (double) n / (double) n);

        double result = covariance / stdX / stdY;

        if (Double.isNaN(result) || Double.isNaN(result)) {
            result = -1.0;
        }
        return result;
    }

    public static double getMean(double[] data) {
        double sum = 0.0;
        for (double a : data) {
            sum += a;
        }
        return sum / (double)data.length;
    }

    public static double getVariance(double[] data) {
        double mean = getMean(data);
        double temp = 0;
        for (double a : data) {
            temp += Math.pow(mean - a, 2.0);
        }
        return temp / (double) data.length;
    }

    public static double getStdDev(double[] data) {
        return Math.sqrt(getVariance(data));
    }

    public static double getMeanSubarray(double[] data, int from, int to) {
        double sum = 0.0;
        for (int i = from; i < to; i++) {
            sum += data[i];
        }
        return sum / (double)(to-from);
    }

    public static double getVarianceSubarray(double[] data, int from, int to) {
        double mean = getMeanSubarray(data, from, to);
        double temp = 0;
        for (int i = from; i < to; i++) {
            temp += Math.pow(mean - data[i], 2.0);
        }
        return temp / (double) (to-from);
    }

    public static double getStdDevSubarray(double[] data, int from, int to) {
        return Math.sqrt(getVarianceSubarray(data, from, to));
    }
//
//    public void statistics(List<Float> data, Integer dataL, Integer dataR, String minf) {//signalViewer.graphPanel ach, - input parameter
//
//        markerInfo = minf;
//
//        if (channel != null) {
//
//            channel = ach;
//            channelName = ach.channelName;
//        }
//
//        dataStart = dataL;
//        dataEnd = dataR;
//
//        n = data.Count(r =  > !Single.IsNaN(r));
//        nNAN = data.Count(r =  > Single.IsNaN(r));
//
//        if (n > 0) {
//            avg = data.Where(r =  > !Single.IsNaN(r)).Average();
//            max = data.Where(r =  > !Single.IsNaN(r)).Max();
//            min = data.Where(r =  > !Single.IsNaN(r)).Min();
//        } else {
//            avg = Float.NaN;
//            max = Float.NaN;
//            min = Float.NaN;
//        }
//
//            //---stdDev
//        dev = Float.NaN;
//
//        if (n > 4) {
//
//            //--proměnné pro kurtosis--
//            float sumM4 = 0;
//            float sumM2 = 0;
//            float m4 = 0;
//            float m2 = 0;
//
//            dev = 0;
//            for (int i = 0; i < data.size(); i++) {
//                if (data.get(i).equals(Float.NaN)) {
//                    continue;
//                }
//                float d = data.get(i) - avg;
//
//                float d2 = d * d;
//
//                dev += d2;
//
//                sumM4 += (float) Math.pow(d, 4);
//            }
//
//            dev = (float) Math.sqrt(dev / (float) n);
//
//            //---kurtosis---
//            m4 = sumM4 / (float) n;
//            m2 = dev * dev;
//
//            kurtosis = m4 / m2 - 3;
//
//            //---median
//            Collections.sort(data);
//            Float[] ordered = data.toArray(new Float[0]);
//
//            int cnt = ordered.length;
//
//            if (cnt % 2 == 0) //---sudý počet prvků
//            {
//                int L = (int) (cnt / 2);
//                med = (ordered[L] + ordered[L + 1]) / 2;
//                perc25 = (ordered[cnt / 4] + ordered[cnt / 4 + 1]) / 2;
//                perc75 = (ordered[cnt / 2 + cnt / 4] + ordered[cnt / 2 + cnt / 4 + 1]) / 2;
//            } else //--lichý počet prvků
//            {
//                med = ordered[cnt / 2];
//                perc25 = ordered[cnt / 4];
//                perc75 = ordered[cnt / 2 + cnt / 4];
//            }
//        }
//
//    }
    public String getChannelName() {
        return channelName;
    }

    public void setChannelName(String channelName) {
        this.channelName = channelName;
    }

    public String getMarkerInfo() {
        return markerInfo;
    }

    public void setMarkerInfo(String markerInfo) {
        this.markerInfo = markerInfo;
    }

    public int getDataStart() {
        return dataStart;
    }

    public void setDataStart(int dataStart) {
        this.dataStart = dataStart;
    }

    public int getDataEnd() {
        return dataEnd;
    }

    public void setDataEnd(int dataEnd) {
        this.dataEnd = dataEnd;
    }

    public int getN() {
        return n;
    }

    public void setN(int n) {
        this.n = n;
    }

    public int getnNAN() {
        return nNAN;
    }

    public void setnNAN(int nNAN) {
        this.nNAN = nNAN;
    }

    public float getAvg() {
        return avg;
    }

    public void setAvg(float avg) {
        this.avg = avg;
    }

    public float getMin() {
        return min;
    }

    public void setMin(float min) {
        this.min = min;
    }

    public float getMax() {
        return max;
    }

    public void setMax(float max) {
        this.max = max;
    }

    public float getMed() {
        return med;
    }

    public void setMed(float med) {
        this.med = med;
    }

    public float getDev() {
        return dev;
    }

    public void setDev(float dev) {
        this.dev = dev;
    }

    public float getPerc25() {
        return perc25;
    }

    public void setPerc25(float perc25) {
        this.perc25 = perc25;
    }

    public float getPerc75() {
        return perc75;
    }

    public void setPerc75(float perc75) {
        this.perc75 = perc75;
    }

    public float getKurtosis() {
        return kurtosis;
    }

    public void setKurtosis(float kurtosis) {
        this.kurtosis = kurtosis;
    }

    public List<Float> getDataCache() {
        return dataCache;
    }

    public void setDataCache(List<Float> dataCache) {
        this.dataCache = dataCache;
    }
}
