package usda.weru.nrmv;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import org.openide.util.Exceptions;

/**
 *
 * @author Benjamin.Todd
 */
public class AverageConverter {

    private final int variableCount;
    private ArrayList<Double> sums, summarySums;
    private final ArrayList<String> myVariables;
    private final ArrayList<ArrayList<Double>> monthSums, yearSums;
    private int currentMonth, totalDaysInMonth, currentYear, totalMonthsInYear;
    private int indexYear;
    private double layerNumber = 1;
    NrmvConverter myNc;
    private String yearlyOutPut, monthlyOutPut;
    private final String type, myPath;

    public AverageConverter(NrmvConverter nc, ArrayList<String> variables, String t, String path) {
        myNc = nc;
        myVariables = new ArrayList<String>(variables);
        variableCount = variables.size() - 1;
        sums = new ArrayList<Double>();

        type = t;
        currentMonth = 1;
        totalMonthsInYear = 1;
        monthSums = new ArrayList<ArrayList<Double>>();
        yearSums = new ArrayList<ArrayList<Double>>();
        initiateArray();
        totalDaysInMonth = 0;
        indexYear = 0;
        currentYear = 2001;
        myPath = path;
    }

    public void increaseMonth() {
        currentMonth++;
        if (currentMonth > 12) {
            currentMonth = 1;
        }

    }

    public void initiateArray() {
        for (int i = 0; i < variableCount; i++) {
            sums.add(i, 0.0);
        }
    }

    public void setArray() {
        sums = new ArrayList<Double>();
        for (int i = 0; i < variableCount; i++) {
            sums.add(i, 0.0);
        }

    }

    public void addToSum(ArrayList<String> al) {
        int yearOfTheList = Integer.parseInt(al.get(0).substring(6, 10));
        int monthOfList = Integer.parseInt(al.get(0).substring(0, 2));
        if (monthOfList != currentMonth) {
            calculateMonthlyAverages();
            increaseMonth();
            monthSums.add(sums);
            this.totalDaysInMonth = 0;
            this.totalMonthsInYear++;
            setArray();
        }

        if (yearOfTheList != currentYear) {
            calculateYearlyAverages();
            this.totalMonthsInYear = 0;
            currentYear = yearOfTheList;

        }

        for (int i = 0; i < variableCount; i++) {
            String s = al.get(i + 1);
            double num = 0.0;
            try {

                num = Double.parseDouble(s);
            } //do nothing for string or blank
            catch (NumberFormatException e) {
            }
            num = num + sums.get(i);
            sums.set(i, num);

        }
        totalDaysInMonth++;
    }

    public void printOut(String monthly, String yearly) {
        this.monthlyOutPut = monthly;
        this.yearlyOutPut = yearly;
        finishPrint(this.monthlyOutPut, true);
        finishPrint(this.yearlyOutPut, false);

    }

    public void printLineCommas(boolean isMonthly, PrintWriter pw, ArrayList<String> aList) {
        for (int i = 0; i < aList.size(); i++) {
            if (i == 0 && isMonthly) {
                //This is needed to put the date in the correct format.
                double d = Double.parseDouble(aList.get(i));

                int cool = (int) d;
                String s = Integer.toString(cool);
                s = s.substring(0, s.length() - 4) + "/" + s.substring(s.length() - 4, s.length());
                pw.print("," + s);
            } else {
                pw.print("," + aList.get(i));
            }
        }
    }

    private void calculateMonthlyAverages() {
        for (int j = 0; j < sums.size(); j++) {
            double factor = 1e5;
            double roundedDouble = sums.get(j) / this.totalDaysInMonth;

            sums.set(j, roundedDouble);
        }
        String bla = Integer.toString(currentMonth) + Integer.toString(currentYear);

        sums.add(0, Double.parseDouble(bla));
    }

    private void calculateYearlyAverages() {
        ArrayList<Double> tmp = new ArrayList<Double>();
        for (int i = 0; i < variableCount + 1; i++) {
            tmp.add(i, 0.0);
        }
        for (int j = indexYear; j < monthSums.size(); j++) {
            for (int k = 0; k < monthSums.get(j).size(); ++k) {
                tmp.set(k, monthSums.get(j).get(k) / (monthSums.size() - indexYear) + tmp.get(k));
            }
        }
        indexYear = monthSums.size();

        tmp.set(0, (double) currentYear);
        this.yearSums.add(tmp);
    }

    void finish() {
        calculateMonthlyAverages();
        monthSums.add(sums);
        calculateYearlyAverages();
        calculateSummaries();
    }

    private void finishPrint(String fileName, boolean isMonthly) {
        FileWriter fw = null;
        ArrayList<ArrayList<Double>> list;
        if (isMonthly) {
            list = monthSums;
        } else {
            list = yearSums;
            //perhaps change this for the future               
        }
        try {

            fw = new FileWriter(fileName);
        } catch (IOException ex) {
            Exceptions.printStackTrace(ex);
        }
        try (PrintWriter pw = new PrintWriter(fw)) {
            String header = fileName.replace(".csv", "");
            header = header.substring(header.lastIndexOf('/') + 1, header.length());
            this.printHeader(header, type, pw);
            this.printLineCommas(false, pw, myVariables);
            myNc.printUnits(pw);
            
            for (ArrayList<Double> mList : list) {

                if (!isMonthly) {
                    
                    double d = mList.get(0);
                    int myInt = (int) d;
                    pw.print("," + myInt);
                    mList.subList(0, 1).clear();
                }
                
                this.printLineCommas(isMonthly, pw, convertToStringList(mList));
                pw.println();
            }
            try {
                fw.close();
            } catch (IOException ex) {
                Exceptions.printStackTrace(ex);
            }
        }
        this.printSummaries();
    }

    public void printSpecificLineMonthly(int spot, PrintWriter layerWriter) {
        ArrayList<Double> out = monthSums.get(spot);
        //ArrayList<Object> out2 = new ArrayList<Object>(out);
        //converts doubles to ints so decimal places are deleted
        //out2.set(1, out.get(1).intValue()); // this is done in printLineCommas

        this.printLineCommas(true, layerWriter, convertToStringList(out));
        layerWriter.println();

    }

    public void printSpecificLineYearly(int spot, PrintWriter layerWriter) {
        ArrayList<Double> out = yearSums.get(spot);
        //ArrayList<Object> out2 = new ArrayList<Object>(out);
        //converts doubles to ints so decimal places are deleted
        // this is done in printLineCommas
        //out2.set(1, new Integer((int) Math.round(Double.parseDouble(Double.toString(out.get(1))))));
        //out2.set(0, new Integer((int) Math.round(Double.parseDouble(Double.toString(out.get(0))))));
        this.printLineCommas(false, layerWriter, convertToStringList(out));
        layerWriter.println();

    }

    public void printSpecificLineSummary(PrintWriter layerWriter) {

        double d = summarySums.get(0);
        int l = (int) Math.round(d);
        layerWriter.print("," + l);

        summarySums.subList(0, 1).clear();
        this.printLineCommas(false, layerWriter, convertToStringList(this.summarySums));
        layerWriter.println();
        layerNumber++;
    }

    public int getNumberOfMonths() {
        return monthSums.size();
    }

    public int getNumberOfYears() {
        return yearSums.size();
    }

    public void printHeader(String name, String type, PrintWriter pw) {

        pw.println("@T, " + type);
        pw.println("type, " + type);
        pw.print("@H");

    }

    public void calculateSummaries() {
        this.summarySums = new ArrayList<Double>();
        int numberOfYears = this.yearSums.size();
        for (String myVariable : this.myVariables) {
            summarySums.add(0.0);
        }
        for (ArrayList<Double> ald : this.yearSums) {
            for (int i = 0; i < ald.size(); i++) {
                double yearSum = summarySums.get(i) + ald.get(i);
                summarySums.set(i, yearSum);
            }
        }
        for (int j = 0; j < summarySums.size(); j++) {
            double d = (summarySums.get(j) / numberOfYears);
            summarySums.set(j, d);
        }
        summarySums.subList(0, 1).clear();
    }

    public void printSummaries() {
        String summaryOutFile = myPath + type + "-summary.csv";
        try {
            FileWriter fw = new FileWriter(summaryOutFile);
            PrintWriter pw = new PrintWriter(fw);
            pw.println("@T," + type);
            pw.println("type," + "\"" + type + "\"");

            pw.print("@H");
            ArrayList<String> tmp = new ArrayList<String>(myVariables);
            tmp.subList(0, 1).clear();
            this.printLineCommas(false, pw, tmp);
            pw.println();

            ArrayList<String> tmp2 = new ArrayList<String>(myNc.units);
            tmp2.subList(0, 1).clear();
            pw.print("Type");
            this.printLineCommas(false, pw, tmp2);
            pw.println();

            ArrayList<Double> tmp1 = new ArrayList<Double>(summarySums);

            this.printLineCommas(false, pw, convertToStringList(tmp1));
            pw.println();
            pw.close();
            fw.close();
        } catch (IOException ex) {
            Exceptions.printStackTrace(ex);
        }

    }
    
    private ArrayList<String> convertToStringList(ArrayList<Double> list) {
        ArrayList<String> listString = new ArrayList<String>();
        for (Double entry : list) {
            listString.add(entry.toString());
        }
        return listString;
    }
}
