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);
            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()))
                {
                    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; }
    
}
