package usda.weru.weps.reports.query.parse;

import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.TFileReader;
import java.io.BufferedReader;
import java.io.IOException;
import java.sql.SQLException;
import java.sql.Types;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.Logger;
import usda.weru.util.Util;
import usda.weru.weps.reports.query.CropRotationResultSet;
import usda.weru.weps.reports.query.Set_CI_DataStruct;
import usda.weru.weps.reports.query.WepsConnection;
import usda.weru.weps.reports.query.WepsResultSet;

/**
 * This class will assemble the cover crop result set using the parsers.
 *
 * @author jonathanhornbaker
 */
public class ParsedRotationResultSet extends WepsResultSet {

    private static final Logger LOGGER = Logger.getLogger(ParsedRotationResultSet.class);

    public static final String NAME = "crop_rotation";
    public static final String COLUMN_RUNID = "runid";

    public static final String COLUMN_STARTDATE = "startdate";

    public static final String COLUMN_ENDDATE = "enddate";

    public static final String COLUMN_CROP = "crop";

    public static final String COLUMN_CROPNUMBER = "cropnumber";

    public static final String COLUMN_DAYS = "days";
    private static final String SQL = "SELECT \"runid\", \"manage\" FROM weps('runs') ORDER BY \"runid\";";

    private final WepsConnection c_con;
    private final HydrobalParser hydro;
    private boolean c_filled;

    public static int num_rotation_years = 0;

    public ParsedRotationResultSet(WepsConnection con) {
        c_con = con;
        hydro = con.getHydroParser();
        c_filled = false;
        //added to query to tie back to runs when multiple are int the connection
        addColumn(COLUMN_RUNID, Types.INTEGER, 10, 0);
        //Columns expected in the file
        addColumn(COLUMN_CROPNUMBER, Types.INTEGER, 10, 0);
        addColumn(COLUMN_CROP, Types.VARCHAR, 50, 0);
        addColumn(COLUMN_STARTDATE, Types.DATE, 0, 0);
        addColumn(COLUMN_ENDDATE, Types.DATE, 0, 0);
        addColumn(COLUMN_DAYS, Types.INTEGER, 0, 0);
    }

    @Override
    public void fill() throws SQLException {
        if (c_filled) {
            return;
        }
        for (int runIndex = 0; runIndex < c_con.getRunFiles().length; runIndex++) {
            int rot_nums = 0;
            try {
                TFile manfile = new TFile(c_con.getRunFiles()[runIndex], "mandate.out");
                BufferedReader man_f = new BufferedReader(new TFileReader(manfile));
                String man_line1 = null;
                man_line1 = man_f.readLine();
                if (man_line1 != null) {
                    String[] line1 = man_line1.split(" ", -1);
                    int index = 0;
                    while (line1[index].equals("")) {
                        index++;
                    }
                    rot_nums = Integer.parseInt(line1[index]);
                }
            } catch (IOException ioe) {
                LOGGER.error("Failed to find rotation years in mandate.out.  Defaulting to 0.");
            }

            String[] seasonLine = {};
            try {
                TFile seasonFile = new TFile(c_con.getRunFiles()[0], "season.out");

                if (seasonFile.exists()) {
                    //Reads text from a character-input stream, 
                    //buffering characters so as to provide for the efficient reading of characters, arrays, and lines. 
                    BufferedReader season_f = new BufferedReader(new TFileReader(seasonFile));
                    String season_l = Interval.getLine(season_f);
                    if (season_l == null) {
                        return;
                    }
                    seasonLine = season_l.split("\\|", -1);
                }
            } catch (IOException ioe) {
            }

            List<Interval> intervals = Interval.generateProperIntervals(seasonLine, rot_nums);

            /* check if init_pasture exist followed by N Harvests. AND...
            * NO OTHER INTERVALS
            * if init_pasture does exist, we have a siutaiton where a 
            * "plant" date in season that has no corresponding "plant" in 
            * the hydrobal file, if this condition exist, we want to exit; there
            * would technically be no interval at this point
             */
            if (intervals.size() == 1) {
                String s = hydro.getData(1, intervals.get(0).getPlant(), "cropName", 0);
                if (s == null) {
                    //no crop interval discovered. 
                    return;
                }
            }

            for (int index = 0; index < intervals.size(); index++) //We statt base one indexing for proper cycle number.
            {
                Object[] cropIntervalRow = this.createNewRow(true);
                Interval inter = intervals.get(index);
                this.setRowValue(cropIntervalRow, COLUMN_ENDDATE, new java.sql.Date(inter.getTermin().getTime()));
                this.setRowValue(cropIntervalRow, COLUMN_STARTDATE, new java.sql.Date(inter.getBegin().getTime()));
                this.setRowValue(cropIntervalRow, COLUMN_RUNID, runIndex);
                this.setRowValue(cropIntervalRow, COLUMN_CROP, inter.getCrop());
                this.setRowValue(cropIntervalRow, COLUMN_CROPNUMBER, index);

                long milis;
                if (inter.getBegin().after(inter.getTermin()) | inter.getBegin().equals(inter.getTermin())) {
                    DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
                    milis = 0;
                    try {
                        Date last = dateFormat.parse("31/12/" + rot_nums);
                        milis += TimeUnit.DAYS.convert(last.getTime()
                                - inter.getBegin().getTime(), TimeUnit.MILLISECONDS);
                        milis -= Interval.getLeap(last, inter.getBegin());
                    } catch (ParseException pe) {
                        System.out.println("Failed to parse:  " + "31/12/" + rot_nums);
                    }
                    try {
                        Date first = dateFormat.parse(" 1/ 1/ 1");
                        milis += TimeUnit.DAYS.convert(inter.getTermin().getTime()
                                - first.getTime(), TimeUnit.MILLISECONDS);
                        milis -= Interval.getLeap(inter.getTermin(), first);
                    } catch (ParseException pe) {
                        System.out.println("Failed to parse:  " + " 1/ 1/ 1");
                    }
                    milis++;
                } else {
                    milis = TimeUnit.DAYS.convert(inter.getTermin().getTime()
                            - inter.getBegin().getTime(), TimeUnit.MILLISECONDS);
                    milis -= Interval.getLeap(inter.getBegin(), inter.getTermin());
                }
                this.setRowValue(cropIntervalRow, COLUMN_DAYS, milis);
            }
        }
    }

    @Override
    public String getName() {
        return NAME;
    }

}
