package br.ufrgs.inf.prosoft.tigris.sampling;

import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class PerformanceBaselineDataSet {

    private Map<Granularity, SummaryStatistics> granularityBaseline = new ConcurrentHashMap<>();
    private SummaryStatistics overallBaseline = new SummaryStatistics();
    private long n;

    public void addItem(Granularity item, long executionTime) {
        SummaryStatistics statistics = new SummaryStatistics();
        if (granularityBaseline.containsKey(item)){
            statistics = granularityBaseline.get(item);
        }
        statistics.addValue(executionTime);
        granularityBaseline.put(item, statistics);
        n++;

        overallBaseline.addValue(executionTime);
    }

    public Apdex getApdexResultsPerEvent(Map<Granularity, DescriptiveStatistics> sampledDataSet){
        long satisfied = 0, tolerated = 0, n = 0;
        for (Granularity granularity : sampledDataSet.keySet()){
            SummaryStatistics stats = granularityBaseline.get(granularity);
            double meanPlusStd = stats.getMean() + stats.getStandardDeviation();
            for (double value: sampledDataSet.get(granularity).getValues()) {
                if (value < meanPlusStd){
                    satisfied++;
                    continue;
                }
                if (value > meanPlusStd &&
                    value < stats.getMean() + (2 * stats.getStandardDeviation())) {
                    tolerated++;
                    continue;
                }
                n++;
            }
        }
        return new Apdex(satisfied, tolerated, n);
    }

    public Apdex getApdexResults(Map<Granularity, DescriptiveStatistics> sampledDataSet){
        long satisfied = 0, tolerated = 0, n = 0;
        for (Granularity granularity : sampledDataSet.keySet()){
            //TODO is it ok to compare with the overall?
            //some methods may be really fast and some really huge
            //should we use getApdexResultsPerEvent?
            double meanPlusStd = getOverallAvg() + getOverallStd();
            for (double value: sampledDataSet.get(granularity).getValues()) {
                if (value < meanPlusStd){
                    satisfied++;
                    continue;
                }
                if (value > meanPlusStd &&
                        value < getOverallAvg() + (2 * getOverallStd())) {
                    tolerated++;
                    continue;
                }
                n++;
            }
        }
        return new Apdex(satisfied, tolerated, n);
    }

    public double getOverallAvg() {
        return overallBaseline.getMean();
    }

    public double getOverallStd() {
        return overallBaseline.getStandardDeviation();
    }

    public long getTotalItems(){
        return n;
    }

    public Set<Granularity> getGranularities(){
        return granularityBaseline.keySet();
    }
}
