package usda.weru.weps.reports.query;

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.Date;
import java.util.ArrayList;
import org.apache.log4j.Logger;

import usda.weru.util.Util;
import usda.weru.weps.reports.query.WepsConnection;
import usda.weru.weps.reports.query.WepsResultSet;

/**
 *
 * @author joelevin
 */
public class HarvestsResultSetArchive extends WepsResultSet {

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

    public static final String NAME = "harvests";
    public static final String COLUMN_RUNID = "runid";
    public static final String COLUMN_CYCLENUMBER = "cyclenumber";
    public static final String COLUMN_HARVESTDATE = "harvestdate";
    public static final String COLUMN_PREVIOUSDATA = "previousdate";
    public static final String COLUMN_DURATION = "duration";
    public static final String COLUMN_CROPINDEX = "cropindex";
    public static final String COLUMN_CROP = "crop";
    public static final String COLUMN_DRYYIELD = "dryyield";
    public static final String COLUMN_RESIDUE = "residue";
    public static final String COLUMN_INDEX = "index";
    public static final String COLUMN_YIELD = "yield";
    public static final String COLUMN_YIELDUNITS = "yieldunits";
    public static final String COLUMN_MOISTURE = "moisture";
    public static final String COLUMN_RAIN = "rain";
    public static final String COLUMN_IRRIG = "irrig";
    public static final String COLUMN_INITSWC = "initswc";
    public static final String COLUMN_FINALSWC = "finalswc";
    public static final String COLUMN_DELTASWC = "deltaswc";
    public static final String COLUMN_TRANSP = "transp";
    public static final String COLUMN_UNITS = "units";

    private final WepsConnection c_con;
    private boolean c_filled;

    /**
     *
     * @param con
     * @throws SQLException
     */
    public HarvestsResultSetArchive(WepsConnection con) throws SQLException {
        c_con = con;
        addColumn(COLUMN_RUNID, Types.INTEGER, 10, 0);
        addColumn(COLUMN_CYCLENUMBER, Types.INTEGER, 10, 0);
        addColumn(COLUMN_HARVESTDATE, Types.DATE, 10, 0);
        //addition of plant data
        addColumn(COLUMN_PREVIOUSDATA, Types.DATE, 10, 0);
        //addition of plant-plant duration
        addColumn(COLUMN_DURATION, Types.INTEGER, 10, 0);
        addColumn(COLUMN_CROPINDEX, Types.INTEGER, 10, 0);
        addColumn(COLUMN_CROP, Types.VARCHAR, 255, 0);
        addColumn(COLUMN_DRYYIELD, Types.DOUBLE, 10, 3);
        addColumn(COLUMN_RESIDUE, Types.DOUBLE, 10, 3);
        addColumn(COLUMN_INDEX, Types.DOUBLE, 10, 3);
        addColumn(COLUMN_YIELD, Types.DOUBLE, 10, 3);
        addColumn(COLUMN_YIELDUNITS, Types.VARCHAR, 255, 0);
        addColumn(COLUMN_MOISTURE, Types.DOUBLE, 10, 3);
        addColumn(COLUMN_RAIN, Types.DOUBLE, 10, 3);
        addColumn(COLUMN_IRRIG, Types.DOUBLE, 10, 3);
        addColumn(COLUMN_INITSWC, Types.DOUBLE, 10, 3);
        addColumn(COLUMN_FINALSWC, Types.DOUBLE, 10, 3);
        addColumn(COLUMN_DELTASWC, Types.DOUBLE, 10, 3);
        addColumn(COLUMN_TRANSP, Types.DOUBLE, 10, 3);
        addColumn(COLUMN_UNITS, Types.BOOLEAN, 10, 3);
    }

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

    /**
     *
     * @return
     */
    protected boolean isUSUnits() {
        return Util.USUnits.equals(c_con.getUnits());
    }

    /**
     *
     * @throws SQLException
     */
    @Override
    public synchronized void fill() throws SQLException {
        if (c_filled) {
            return;
        }
        TFile[] files = c_con.getRunFiles();
        DateFormat harvestDateFormat = new SimpleDateFormat("dd/MM/yyyy");new SimpleDateFormat("dd/MM/y");

        for (int runIndex = 0; runIndex < files.length; runIndex++) {
            TFile runDir = files[runIndex];
            String harvestFileName = isUSUnits() ? "harvest_en.out" : "harvest_si.out";
            TFile harvestFile = new TFile(runDir, harvestFileName);
            String hydrobalFileName = "hydrobal.out";
            TFile hydrobalFile = new TFile(runDir, hydrobalFileName);

            if (harvestFile.exists() && hydrobalFile.exists()) {
                BufferedReader in = null;
                BufferedReader in2 = null;
                try {
                    in = new BufferedReader(new TFileReader(harvestFile));
                    in2 = new BufferedReader(new TFileReader(hydrobalFile));
                    int cycleNumber = 0;
                    String line;
                    String line2;

                    while (((line = getLine(in)) != null) && ((line2 = getLine(in2)) != null)) {
                        //each line is a new cycle
                        cycleNumber++;
                        String[] parts = line.split("\\|", -1);
                        String[] parts2 = line2.split("\\|", -1);
                        String[] parts3 = line2.split("\\|Harvest", -1);
                        String[] parts4 = line2.split("\\|Graze", -1);  //Need to check for additional harvest name - LEW
                        String[] parts5 = line2.split("\\|Bale", -1);  //Need to check for additional harvest name - LEW
                        //each crop is 12 columns apart
                        int cropCount = (parts.length - 1) / 12;
                        //System.out.printf("CropCount: %d\n", cropCount);

                        //each hydro crop  is 36 columns apart - Usually
                        //but they don't start at the same place, etc.
                        //so we can't use it and must use the "Harvests" stuff below - LEW
                        //int cropCount2 = (parts2.length - 1) / 36;
                        int HarvestCount = parts3.length - 1;
                        int GrazeCount = parts4.length - 1;
                        int BaleCount = parts5.length - 1;
                        int AllHarvestCount = HarvestCount + GrazeCount + BaleCount;
                        // System.out.printf("HarvestCount|GrazeCount|BaleCount|AllHarvestCount: %d %d %d %d\n",HarvestCount,GrazeCount,BaleCount,AllHarvestCount);                    

                        ArrayList<String[]> Harvests = new ArrayList<String[]>();
                        for (int i = 0; i < AllHarvestCount; i++) {
                            if (i < HarvestCount) {
                                Harvests.add(i, parts3[i + 1].split("\\|", -1));
                            } else if (i < HarvestCount + GrazeCount) {  // include all "Graze" harvests as well
                                Harvests.add(i, parts4[i - HarvestCount + 1].split("\\|", -1));
                            } else { // include all "Bale" harvests as well
                                Harvests.add(i, parts5[i - HarvestCount - GrazeCount + 1].split("\\|", -1));
                            }
                        }

                        /* if (cycleNumber == 1) {
                         System.out.printf("line2 is:%s\n",line2);

                         System.out.printf("parts2[0]: %s\n",parts2[0]);
                         System.out.printf("parts2[1]: %s\n",parts2[1]);
                         System.out.printf("parts2[2]: %s\n",parts2[2]);
                         System.out.printf("parts2[3]: %s\n",parts2[3]);
                         // System.out.printf("parts3: %s\n",parts3);
                         // [0] is ignored.  [1-n] are the "Harvest" pieces
                         System.out.printf("parts3[0]: %s\n",parts3[0]);
                         System.out.printf("parts3[1]: %s\n",parts3[1]);
                         System.out.printf("parts3[2]: %s\n",parts3[2]);
                         System.out.printf("parts2.length: %d\n",parts2.length-1);
                         System.out.printf("parts3.length: %d\n",parts3.length-1);
                         int j=0;                    
                         String[] parts4 = parts3[j+1].split("\\|", -1);
                         String[] parts5 = parts3[j+2].split("\\|", -1);
                         System.out.printf("parts4[1]: %s\n",parts4[1]);
                         System.out.printf("parts5[1]: %s\n",parts5[1]);
                            
                         System.out.printf("parts4[1]: %s\n",parts4[3]);
                         System.out.printf("parts5[1]: %s\n",parts5[3]);
                            
                         for (int i=0; i<HarvestCount; i++) {
                         //Harvests.add(i,parts3[i+1].split("\\|", -1));
                         System.out.printf("Harvest: %d, SWCi: %s\n", i, Harvests.get(i)[3]);
                         System.out.printf("Harvest: %d, SWCf: %s\n", i, Harvests.get(i)[7]);
                         System.out.printf("Harvest: %d, Rain: %s\n", i, Harvests.get(i)[10]);
                         System.out.printf("Harvest: %d, Transp: %s\n", i, Harvests.get(i)[13]);
                         System.out.printf("Harvest: %d, SWCdiff: %f\n", i,
                         Double.valueOf(Harvests.get(i)[7])-Double.valueOf(Harvests.get(i)[3]));
                         }
                         } */
                        //loop over each crop (or harvest in the hydrobal file)
                        for (int cropIndex = 0; cropIndex < cropCount; cropIndex++) {
                            int cropOffset = cropIndex * 12;
                            int cropOffset2 = cropIndex * 36; //Should no longer be used - LEW                           
                            Object[] row = createNewRow(true);
                            setRowValue(row, COLUMN_RUNID, runIndex);
                            setRowValue(row, COLUMN_CYCLENUMBER, cycleNumber);
                            setRowValue(row, COLUMN_CROPINDEX, cropIndex);
                            setRowValue(row, COLUMN_UNITS, this.isUSUnits());
                            //harvest date
                            try {
                                String dateString = parts[cropOffset + 0].trim();
                                Date harvestDate = harvestDateFormat.parse(dateString);
                                setRowValue(row, COLUMN_HARVESTDATE, new java.sql.Date(harvestDate.getTime()));
                            } catch (ParseException pe) {
                                LOGGER.error("Error parsing harvest date.", pe);
                            }

                            //harvest date
                            try {
                                String dateString = parts[cropOffset + 0].trim();
                                Date harvestDate = harvestDateFormat.parse(dateString);
                                setRowValue(row, COLUMN_PREVIOUSDATA, new java.sql.Date(harvestDate.getTime()));
                            } catch (ParseException pe) {
                                LOGGER.error("Error parsing harvest date.", pe);
                            }

                            setRowValue(row, COLUMN_DURATION, 0);
                            //crop name
                            try {
                                String cropName = parts[cropOffset + 1].trim();
                                setRowValue(row, COLUMN_CROP, cropName);
                            } catch (SQLException e) {
                                LOGGER.error("Error reading crop name.", e);
                            }

                            //dry yield
                            try {
                                Double dryYield = Double.valueOf(parts[cropOffset + 2].trim());
                                setRowValue(row, COLUMN_DRYYIELD, dryYield);
                            } catch (NumberFormatException nfe) {
                                LOGGER.error("Error parsing dry yield.", nfe);
                            }

                            //residue
                            try {
                                Double residue = Double.valueOf(parts[cropOffset + 4].trim());
                                setRowValue(row, COLUMN_RESIDUE, residue);
                            } catch (NumberFormatException nfe) {
                                LOGGER.error("Error parsing residue.", nfe);
                            }

                            //harvest index
                            try {
                                Double harvestIndex = Double.valueOf(parts[cropOffset + 6].trim());
                                setRowValue(row, COLUMN_INDEX, harvestIndex);
                            } catch (NumberFormatException nfe) {
                                LOGGER.error("Error parsing harvest index.", nfe);
                            }

                            //yield
                            try {
                                Double yield = Double.valueOf(parts[cropOffset + 8].trim());
                                setRowValue(row, COLUMN_YIELD, yield);
                            } catch (NumberFormatException nfe) {
                                LOGGER.error("Error parsing harvest yield.", nfe);
                            }

                            //yield units
                            try {
                                String yieldUnits = parts[cropOffset + 9].trim();
                                setRowValue(row, COLUMN_YIELDUNITS, yieldUnits);
                            } catch (SQLException e) {
                                LOGGER.error("Error reading yield units.", e);
                            }

                            //% water
                            try {
                                Double moisture = Double.valueOf(parts[cropOffset + 10].trim());
                                setRowValue(row, COLUMN_MOISTURE, moisture);
                            } catch (NumberFormatException nfe) {
                                LOGGER.error("Error parsing % moisture.", nfe);
                            }
                            // Rain (and Irrig)
                            try {
                                //Double rain = Double.valueOf(parts2[cropOffset2 + 29].trim());
                                Double rain = Double.valueOf(Harvests.get(cropIndex)[10]);
                                // rain = isUSUnits() ? rain/25.4 : rain; /* Got to be a better way to do this - LEW */
                                rain = isUSUnits() ? rain * 0.03937 : rain;
                                setRowValue(row, COLUMN_RAIN, rain);
                            } catch (NumberFormatException nfe) {
                                LOGGER.error("Error parsing rain.", nfe);
                            }

                            try {
                                setRowValue(row, COLUMN_IRRIG, Double.NaN);
                            } catch (NumberFormatException nfe) {
                                LOGGER.error("Error parsing irrig.", nfe);
                            }
                            // Initial SWC
                            try {
                                //Double initswc = Double.valueOf(parts2[cropOffset2 + 22].trim());
                                Double initswc = Double.valueOf(Harvests.get(cropIndex)[3]);
                                // initswc = isUSUnits() ? initswc/25.4 : initswc; /* Got to be a better way to do this - LEW */
                                initswc = isUSUnits() ? initswc * 0.03937 : initswc;
                                setRowValue(row, COLUMN_INITSWC, initswc);
                            } catch (NumberFormatException nfe) {
                                LOGGER.error("Error parsing Initial SWC.", nfe);
                            }
                            // Final SWC
                            try {
                                //Double finalswc = Double.valueOf(parts2[cropOffset2 + 26].trim());
                                Double finalswc = Double.valueOf(Harvests.get(cropIndex)[7]);
                                // finalswc = isUSUnits() ? finalswc/25.4 : finalswc; /* Got to be a better way to do this - LEW */
                                finalswc = isUSUnits() ? finalswc * 0.03937 : finalswc;
                                setRowValue(row, COLUMN_FINALSWC, finalswc);
                            } catch (NumberFormatException nfe) {
                                LOGGER.error("Error parsing Final SWC.", nfe);
                            }
                            // Change in SWC (used/gained)
                            try {
                                //Double deltaswc = Double.valueOf(parts2[cropOffset2 + 26].trim()) -
                                //        Double.valueOf(parts2[cropOffset2 + 22].trim());
                                Double deltaswc = Double.valueOf(Harvests.get(cropIndex)[7])
                                        - Double.valueOf(Harvests.get(cropIndex)[3]);
                                // deltaswc = isUSUnits() ? deltaswc/25.4 : deltaswc; /* Got to be a better way to do this - LEW */
                                deltaswc = isUSUnits() ? deltaswc * 0.03937 : deltaswc;
                                setRowValue(row, COLUMN_DELTASWC, deltaswc);
                            } catch (NumberFormatException nfe) {
                                LOGGER.error("Error parsing Delta SWC.", nfe);
                            }
                            // Transpiration
                            try {
                                //Double transp = Double.valueOf(parts2[cropOffset2 + 32].trim());
                                Double transp = Double.valueOf(Harvests.get(cropIndex)[13]);
                                // transp = isUSUnits() ? transp/25.4 : transp; /* Got to be a better way to do this - LEW */
                                transp = isUSUnits() ? transp * 0.03937 : transp;
                                setRowValue(row, COLUMN_TRANSP, transp);
                            } catch (NumberFormatException nfe) {
                                LOGGER.error("Error parsing Transpiration.", nfe);
                            }
                        }
                    }

                } catch (IOException ioe) {
                    LOGGER.error("Error reading harvest file or hydrobal.out file: " + harvestFile.getAbsolutePath()
                            + hydrobalFile.getAbsolutePath(), ioe);
                } finally {
                    if (in != null) {
                        try {
                            in.close();
                        } catch (IOException e) {
                            LOGGER.error("Error closing harvest file: " + harvestFile.getAbsolutePath(), e);
                        }
                    }
                    if (in2 != null) {
                        try {
                            in2.close();
                        } catch (IOException e) {
                            LOGGER.error("Error closing hydrobal.out file: " + hydrobalFile.getAbsolutePath(), e);
                        }
                    }
                }
            }
        }
        c_filled = true;
    }

    //Skip comments and blank lines
    private String getLine(BufferedReader in) throws IOException {
        String temp;
        while ((temp = in.readLine()) != null) {
            temp = temp.trim();
            if (temp.length() == 0) {
                //blank line
                continue;
            }
            if (temp.charAt(0) != '#') {
                //not a comment
                return temp;
            }
        }
        return null;
    }

}
