/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package qsim.stat;

import gui.ErrorDialog;
import java.awt.Color;
import java.util.ArrayList;
import java.util.List;
import umontreal.iro.lecuyer.charts.XYLineChart;
import umontreal.iro.lecuyer.probdist.NormalDist;

/**
 *
 * @author joe
 */
public class BatchMeansMethod {
    
    private Double expectedValue;
    
    private int numberOfBatches;
    private int batchSize;
    private double confidenceLevel;
    private List<Double> dataList;
    private List<Double> dataFromSimulation;
    private List<Double> batchMeansList;
    
    private int warmup = 20;
    private int warmdown = 20;
    
    private String chartTitle;
    
    public BatchMeansMethod(List<Double> dataFromSimulation, int batchSize, double condidenceLevel, String chartTitle){
        this.dataFromSimulation = dataFromSimulation;
        this.batchSize = batchSize;
        this.confidenceLevel = condidenceLevel;
        this.chartTitle = chartTitle;
        
        this.batchMeansList = new ArrayList<Double>();
    }
    
    public BatchMeansMethod(double[] dataFromSimulation, int batchSize, double condidenceLevel, String chartTitle){
        this.dataFromSimulation = new ArrayList<Double>();
        //System.out.println(dataFromSimulation.length);
        for(Double d : dataFromSimulation){
            this.dataFromSimulation.add(d);
        }
        this.batchSize = batchSize;
        this.confidenceLevel = condidenceLevel;
        this.chartTitle = chartTitle;
        
        this.batchMeansList = new ArrayList<Double>();
    }
    
    

    public Double getExpectedValueFromBatchmeans() {
        if (!setBatchMeansData()){
            return null;
        }

        if (this.dataList == null || this.batchMeansList == null) {
            return null;
        }

        double eV = 0.0;
        for (Double d : batchMeansList) {
            eV += d;
        }
        return eV / numberOfBatches;

    }

    private boolean setBatchMeansData() {
        if (this.dataFromSimulation.size() > (warmup + warmdown + batchSize)) {

            //az adatok listájának generálás, levágjuk az első, és uccsó 20 értékét - warmup miatt...
            dataList = new ArrayList<Double>(dataFromSimulation.subList(warmup, dataFromSimulation.size() - warmdown));

            dataList = dataList.subList(0, (dataList.size() / batchSize) * batchSize);

            //batch-ek számának meghatározása
            numberOfBatches = dataList.size() / batchSize;

            //az egyes intervalumok számtani közepének előállítása
            for (int i = 0; i < numberOfBatches; i++) {
                double count = 0.0;
                for (int j = 0; j < batchSize; j++) {
                    count += dataList.get(i * batchSize + j);
                }
                batchMeansList.add(count / batchSize);
            }
            return true;
        }
        return false;
    }
    
    public double getConfidenceInterval(){
        //ha nincs még beállítva a lista
        if (batchMeansList.size() == 0){
            return 0.0;
        }
        
        double beta = confidenceLevel/100;
        //System.out.println(umontreal.iro.lecuyer.probdist.NormalDist.cdf01(1-beta/2));
        double S2 = 0.0;
        double sum = 0.0;
        
        for(int i=0; i<numberOfBatches; i++){
            sum+=Math.pow(batchMeansList.get(i) - expectedValue, 2);
        }
        
        S2 = sum/(numberOfBatches-1);
        //System.out.println(Math.sqrt(S2)/Math.sqrt(numberOfBatches));
        return NormalDist.inverseF01((1-beta)/2) * (Math.sqrt(S2)/Math.sqrt(numberOfBatches));
    }

    public void drawBachmeansChart() {
        expectedValue = getExpectedValueFromBatchmeans();

        if (expectedValue == null) {
            new ErrorDialog(null, true, "Túl kevés adat áll rendelkezésre a grafikon előállításához!").setVisible(true);
            return;
        }

        XYLineChart chart = new XYLineChart();

        double[][] chartDataRaw = new double[2][this.dataList.size()];
        int i = 0;
        for (Double d : dataList) {
            chartDataRaw[0][i] = (i + 1);
            chartDataRaw[1][i] = d;
            i++;
        }

        double[][] chartDataBatchMeans = new double[2][this.batchMeansList.size()];
        i = 0;
        for (double d : batchMeansList) {
            chartDataBatchMeans[0][i] = (i + 1) * batchSize;
            chartDataBatchMeans[1][i] = d;
            i++;
        }

        double[][] chartDataEstimatedValue = new double[2][2];
        chartDataEstimatedValue[0][0] = 0;
        chartDataEstimatedValue[0][1] = chartDataRaw[0][dataList.size() - 1];
        chartDataEstimatedValue[1][0] = expectedValue;
        chartDataEstimatedValue[1][1] = expectedValue;
        
        double confidenceNumber = getConfidenceInterval();
        //System.out.println(confidenceNumber);
        
        double[][] chartDataConfidencePlus = new double[2][2];
        chartDataConfidencePlus[0][0] = 0;
        chartDataConfidencePlus[0][1] = chartDataRaw[0][dataList.size() - 1];
        chartDataConfidencePlus[1][0] = expectedValue + confidenceNumber;
        chartDataConfidencePlus[1][1] = expectedValue + confidenceNumber;
        
        double[][] chartDataConfidenceMinus = new double[2][2];
        chartDataConfidenceMinus[0][0] = 0;
        chartDataConfidenceMinus[0][1] = chartDataRaw[0][dataList.size() - 1];
        chartDataConfidenceMinus[1][0] = expectedValue - confidenceNumber;
        chartDataConfidenceMinus[1][1] = expectedValue - confidenceNumber;


        chart.add(chartDataConfidenceMinus[0], chartDataConfidenceMinus[1]);
        chart.add(chartDataConfidencePlus[0], chartDataConfidencePlus[1]);
        chart.add(chartDataEstimatedValue[0], chartDataEstimatedValue[1]);
        chart.add(chartDataBatchMeans[0], chartDataBatchMeans[1]);
        chart.add(chartDataRaw[0], chartDataRaw[1]);
        

        chart.getSeriesCollection().setColor(0, new Color(255, 204, 102));
        chart.getSeriesCollection().setColor(1, new Color(255, 204, 102));
        chart.getSeriesCollection().setColor(2, new Color(255, 0, 0));
        chart.getSeriesCollection().setColor(3, new Color(51, 204, 0));
        chart.getSeriesCollection().setColor(4, new Color(170, 225, 234));
        
        
        chart.setTitle(chartTitle + 
                "\nÁtlag: " + expectedValue + 
                "\n" +  
                confidenceLevel + "%-os konfidencia intervallum: (" + 
                (expectedValue+confidenceNumber) + ", " + (expectedValue-confidenceNumber) + ")");
        chart.view(900, 500);
    }
}
