/*
 * The Broad Institute
 * SOFTWARE COPYRIGHT NOTICE AGREEMENT
 * This is copyright (2007-2008) by the Broad Institute/Massachusetts Institute 
 * of Technology.  It is licensed to You under the Gnu Public License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *    http://www.opensource.org/licenses/gpl-2.0.php
 *
 * This software is supplied without any warranty or guaranteed support
 * whatsoever. Neither the Broad Institute nor MIT can be responsible for its
 * use, misuse, or functionality.
 */

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.broad.igv.preprocess;

import cern.colt.list.DoubleArrayList;
import cern.jet.stat.quantile.DoubleQuantileFinder;
import cern.jet.stat.quantile.QuantileFinderFactory;
import java.util.LinkedHashMap;

/**
 *
 * @author jrobinso
 */
public class ProcessingUtils {
    
    public static float computeMean(float [] data) {
        if(data == null || data.length == 0) {
            return Float.NaN;
        }
        float sum = 0;
        for(int i=0; i<data.length; i++) {
            sum += data[i];
        }
        return sum / data.length;
    }

    /**
     * Compute some statistics for the input data
     *   TODO move to a utility class
     *   TODO take statis desired as input
     * @param data
     * @return
     */
    public static DataStatistics computeStats(float[] data) {

        // Check for null or missing data.  Float.NaN is interpreted
        // as a placeholder for "no data.

        boolean noData = true;
        if (data != null && data.length > 0) {
            for (int i = 0; i < data.length; i++) {
                if (!Float.isNaN(data[i])) {
                    noData = false;
                    break;
                }
            }
        }


        if (noData) {
            return DataStatistics.nullDataStat;
        } else {

            DataStatistics stats = new DataStatistics();

            // Check for array of NaNs
            DoubleArrayList al = new DoubleArrayList(2);
            al.add(0.1);
            al.add(0.5);
            al.add(0.9);
            al.add(0.98);
            DoubleQuantileFinder qf =
                QuantileFinderFactory.newDoubleQuantileFinder(true, data.length,
                0.001, 0.001, al.size(), null);


            double minStat = Double.MAX_VALUE;
            double maxStat = -Double.MAX_VALUE;
            double meanStat = 0;
            for (int i = 0; i < data.length; i++) {
                if (isValidData(data[i])) {
                    qf.add(data[i]);
                    minStat = Math.min(minStat, data[i]);
                    maxStat = Math.max(maxStat, data[i]);
                    meanStat += data[i];
                }
            }

            if (qf.size() > 0) {

                meanStat /= qf.size();
                double err2 = 0;
                for (int i = 0; i < data.length; i++) {
                    if (isValidData(data[i])) {
                        err2 += (data[i] - meanStat) * (data[i] - meanStat);
                    }
                }
                double stdDev = Math.sqrt(err2 / qf.size());

                DoubleArrayList quantiles2 = qf.quantileElements(al);
                stats.setMin(minStat);
                stats.setMax(maxStat);
                stats.setMean(meanStat);
                stats.setPercentile10(quantiles2.get(0));
                stats.setMedian(quantiles2.get(1));
                stats.setPercentile90(quantiles2.get(2));
                stats.setPercentile98(quantiles2.get(3));
                stats.setStdDev(stdDev);
            }

            return stats;

        }
    }

    /**
     * 
     * @param data
     * @return
     */
    public static double computeMedian(float[] data) {

        if (data.length > 0) {
            DoubleArrayList al = new DoubleArrayList();
            al.add(0.5);
            DoubleQuantileFinder qf =
                QuantileFinderFactory.newDoubleQuantileFinder(true, data.length,
                0.001, 0.001, al.size(), null);


            for (int i = 0; i < data.length; i++) {
                if (isValidData(data[i])) {
                    qf.add(data[i]);

                }
            }

            if (qf.size() > 0) {

                DoubleArrayList quantiles2 = qf.quantileElements(al);
                return quantiles2.get(0);
            }
        }
        return 0;
    }

    private static boolean isValidData(float data) {
        return !Float.isNaN(data);
    }

    public static LinkedHashMap<String, String> parseArgs(String[] args) {
        return parseArgs(args, 0);
    }

    public static LinkedHashMap<String, String> parseArgs(String[] args, int startIndex) {
        LinkedHashMap<String, String> argMap = new LinkedHashMap();

        for (int i = startIndex; i < args.length; i++) {
            String key = args[i].trim();

            if (args[i].trim().startsWith("-")) {
                String value = "";
                if (i < args.length - 1) {
                    i++;

                    if (args[i].trim().startsWith("-")) {
                        value = "";
                        i--;
                    } else {
                        value = args[i].trim();
                    }
                    System.out.println(key + " = " + value);
                    argMap.put(key, value);
                } else {
                    argMap.put(key, "");
                }
            } else {
                System.out.println(key);
                argMap.put(key, key);
            }
        }

        return argMap;
    }
}
