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.Calendar;
import java.util.Date;
import org.apache.log4j.Logger;
import org.openide.util.Exceptions;
import usda.weru.util.ConfigData;
import usda.weru.util.ConversionCalculator;
import usda.weru.util.ConversionCalculator.ConversionNotFoundException;
import usda.weru.util.ConversionCalculator.UnitNotFoundException;
import usda.weru.util.Util;

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

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

    /**
     *
     */
    public static final String NAME = "stir_energy";

    /**
     *
     */
    public static final String OUTPUT_FILE = "stir_energy.out";

    /**
     *
     */
    public static final String COLUMN_LINE = "line";

    /**
     *
     */
    public static final String COLUMN_STIR = "stir";

    /**
     *
     */
    public static final String COLUMN_ENERGY = "energy";

    /**
     *
     */
    public static final String COLUMN_DATE = "date";

    /**
     *
     */
    public static final String COLUMN_OPERATION = "operation";

    /**
     *
     */
    public static final String COLUMN_CROP = "crop";

    /**
     *
     */
    public static final String COLUMN_FUEL = "fuel";

    /**
     *
     */
    public static final String COLUMN_FUELDEFAULT = "fueldefault";

    /**
     *
     */
    public static final String COLUMN_CROPNUMBER = "cropnumber";

    /**
     *
     */
    public static final String COLUMN_LASTHARVEST = "lastharvest";
    private static final String FORMAT_DATE = "dd/MM/yyyy";
    private final WepsConnection c_con;
    private boolean c_filled;

    /**
     *
     * @param con
     * @throws SQLException
     */
    public StirEnergyResultSet(WepsConnection con) throws SQLException {
        c_con = con;
        addColumn(RunsResultSet.COLUMN_RUNID, Types.INTEGER, 10, 0);

        //stir file specific 
        addColumn(COLUMN_LINE, Types.INTEGER, 10, 0);

        //Columns expected in the file
        addColumn(COLUMN_DATE, Types.DATE, 0, 0);
        addColumn(COLUMN_OPERATION, Types.VARCHAR, 50, 0);
        addColumn(COLUMN_CROP, Types.VARCHAR, 50, 0);
        addColumn(COLUMN_FUEL, Types.VARCHAR, 50, 0);
        addColumn(COLUMN_STIR, Types.DOUBLE, 10, 5);
        addColumn(COLUMN_ENERGY, Types.DOUBLE, 10, 5);
        addColumn(COLUMN_CROPNUMBER, Types.INTEGER, 10, 0);
        addColumn(COLUMN_LASTHARVEST, Types.BOOLEAN, 0, 0);
        addColumn(COLUMN_FUELDEFAULT, Types.BOOLEAN, 0, 0);

    }

    /**
     *
     * @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();

        for (int i = 0; i < files.length; i++) {
            TFile runDir = files[i];
            TFile output = new TFile(runDir, OUTPUT_FILE);
            if (!output.exists()) {
                //no stir_energy file, might be an old run
                continue;
            }

            //Stir energy file specific
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new TFileReader(output));

                //first line, flexible header
                String header = reader.readLine();
                header = header.replaceFirst("#", "");
                String[] columns = header.split("\\|", -1);     //-1 so we grab blank columns, just in case

                String line = getLine(reader); //skip the first non-comment line.
                int lineIndex = -1;
                while ((line = getLine(reader)) != null) {
                    //increment the line index for the next use.
                    lineIndex++;

                    Object[] row = createNewRow(true);
                    //Always add the run id so that joins will work
                    setRowValue(row, RunsResultSet.COLUMN_RUNID, i);

                    //Add the lineIndex so things can be sorted if need be specific to this file
                    setRowValue(row, COLUMN_LINE, lineIndex);

                    // Use -1 as the limit to allow String.split to return all 5 values regardless of whether they are
                    // blank or not.
                    String[] values = line.split("\\|", -1);
                    if (values.length != columns.length) {
                        //something changed in the file output format that is unexpected
                        LOGGER.warn("Unexpected number of columns on line " + lineIndex + "; found "
                                + values.length + ", expected " + columns.length + ". File: " + output.getAbsolutePath());
                        //go to the next line
                        continue;
                    }

                    try {
                        String dateText = values[column(columns, "dd/mm/yyyy")].trim();
                        Calendar cal1 = Calendar.getInstance();
                        String[] date1 = dateText.trim().split("/");
                        cal1.set(Integer.parseInt(date1[2].trim()), Integer.parseInt(date1[1].trim()) - 1, Integer.parseInt(date1[0].trim()));
                        //DateFormat format = new SimpleDateFormat(FORMAT_DATE);
                        //Date date = format.parse(dateText);
                        setRowValue(row, COLUMN_DATE, new java.sql.Date(cal1.getTimeInMillis()));
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse date in file: " + output.getAbsolutePath() + " on line: " + lineIndex);
                    }/* catch (ParseException pe) {
                        LOGGER.warn("Unable to parse date in file: " + output.getAbsolutePath() + " on line: " + lineIndex);
                    }*/

                    String operationText = values[column(columns, "operation")].trim();
                    setRowValue(row, COLUMN_OPERATION, operationText);

                    String cropText = values[column(columns, "crop name")].trim();
                    setRowValue(row, COLUMN_CROP, cropText);

                    if (column(columns, "fuel") >= 0) {
                        String fuelText = values[column(columns, "fuel")].trim();

                        //pull in default fuel if required
                        if (fuelText == null || fuelText.length() == 0) {
                            fuelText = ConfigData.getDefault().getData(ConfigData.FuelDefault);
                            setRowValue(row, COLUMN_FUELDEFAULT, true);
                        } else {
                            setRowValue(row, COLUMN_FUELDEFAULT, false);
                        }

                        setRowValue(row, COLUMN_FUEL, fuelText);
                    } else {
                        String fuelText = ConfigData.getDefault().getData(ConfigData.FuelDefault);
                        setRowValue(row, COLUMN_FUEL, fuelText);
                        setRowValue(row, COLUMN_FUELDEFAULT, true);
                    }

                    try {
                        String stirText = values[column(columns, "stir")].trim();
                        Double stir = Double.valueOf(stirText);
                        setRowValue(row, COLUMN_STIR, stir);
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse stir value in file: " + output.getAbsolutePath()
                                + " on line: " + lineIndex);
                    }

                    try {
                        String energyText = values[column(columns, "energy")].trim();
                        Double energy = Double.valueOf(energyText);
                        if (isUSUnits()) {
                            energy = ConversionCalculator.convert(energy, "L/ha", "gal/ac");
                        }
                        setRowValue(row, COLUMN_ENERGY, energy);
                    } catch (UnitNotFoundException unf) {
                        LOGGER.warn("Unable to convert energy value in file: " + output.getAbsolutePath()
                                + " on line: " + lineIndex);
                    } catch (ConversionNotFoundException cnf) {
                        LOGGER.warn("Unable to convert energy value in file: " + output.getAbsolutePath()
                                + " on line: " + lineIndex);
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse energy value in file: " + output.getAbsolutePath()
                                + " on line: " + lineIndex);
                    }

                    try {
                        String cropSequenceText = values[column(columns, "crop sequence")].trim();
                        Integer cropSequence = Integer.valueOf(cropSequenceText);
                        setRowValue(row, COLUMN_CROPNUMBER, cropSequence - 1);
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse crop sequence value in file: " + output.getAbsolutePath()
                                + " on line: " + lineIndex);
                    }

                    try {
                        String lastHarvestText = values[column(columns, "1 if last")].trim();
                        Boolean lastHarvest = "1".equals(lastHarvestText);
                        setRowValue(row, COLUMN_LASTHARVEST, lastHarvest);
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse last harvest flag in file: " + output.getAbsolutePath()
                                + " on line: " + lineIndex);
                    }
                }
            } catch (IOException ioe) {
                LOGGER.error("Error reading file: " + output.getAbsolutePath(), ioe);
                throw new SQLException("Error reading file: " + output.getAbsolutePath(), ioe);
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        LOGGER.error("Error closing file: " + output.getAbsolutePath(), e);
                    }
                }
            }

        }

        c_filled = true;
    }

    private int column(String[] columns, String startsWith) {
        for (int i = 0; i < columns.length; i++) {
            if (columns[i].toLowerCase().trim().startsWith(startsWith.toLowerCase().trim())) {
                return i;
            }
        }

        return -1;
    }

    //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;
    }

    /**
     *
     * @param columnName
     * @param us
     * @return
     */
    public static String getDisplayUnits(String columnName, Boolean us) {
        if (COLUMN_ENERGY.equals(columnName)) {
            if (us) {
                return "gal diesel/ac";
            } else {
                return "L diesel/ha";
            }
        }
        return null;
    }
}
