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 org.apache.log4j.Logger;
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 SciEnergyResultSet extends WepsResultSet {

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

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

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

    /**
     *
     */
    public static final String COLUMN_SCI = "sci";

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

    /**
     *
     */
    public static final String COLUMN_OMFACTOR = "omfactor";

    /**
     *
     */
    public static final String COLUMN_ERFACTOR = "erfactor";

    /**
     *
     */
    public static final String COLUMN_FOFACTOR = "fofactor";

    /**
     *
     */
    public static final String COLUMN_RENNEROM = "rennerom";

    /**
     *
     */
    public static final String COLUMN_RENNERWATER = "rennerwater";

    /**
     *
     */
    public static final String COLUMN_RENNERWIND = "rennerwind";

    /**
     *
     */
    public static final String COLUMN_RENNERSTIR = "rennerstir";

    /**
     *
     */
    public static final String COLUMN_AVGBIOMASS = "avgbiomass";

    /**
     *
     */
    public static final String COLUMN_WINDEROS = "winderos";

    /**
     *
     */
    public static final String COLUMN_WATEREROS = "watereros";

    /**
     *
     */
    public static final String COLUMN_AVGALLSTIR = "avgallstir";

    /**
     *
     */
    public static final String COLUMN_TEXTUREMULT = "texturemult";
    private final WepsConnection c_con;
    private boolean c_filled;

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

        //Columns expected in the sci file
        addColumn(COLUMN_SCI, Types.DOUBLE, 10, 5);
        addColumn(COLUMN_ENERGY, Types.DOUBLE, 10, 5);

        addColumn(COLUMN_OMFACTOR, Types.DOUBLE, 10, 5);
        addColumn(COLUMN_ERFACTOR, Types.DOUBLE, 10, 5);
        addColumn(COLUMN_FOFACTOR, Types.DOUBLE, 10, 5);

        addColumn(COLUMN_RENNEROM, Types.DOUBLE, 10, 5);
        addColumn(COLUMN_RENNERWATER, Types.DOUBLE, 10, 5);
        addColumn(COLUMN_RENNERWIND, Types.DOUBLE, 10, 5);
        addColumn(COLUMN_RENNERSTIR, Types.DOUBLE, 10, 5);

        addColumn(COLUMN_AVGBIOMASS, Types.DOUBLE, 10, 5);
        addColumn(COLUMN_WINDEROS, Types.DOUBLE, 10, 5);
        addColumn(COLUMN_WATEREROS, Types.DOUBLE, 10, 5);
        addColumn(COLUMN_AVGALLSTIR, Types.DOUBLE, 10, 5);

        addColumn(COLUMN_TEXTUREMULT, Types.DOUBLE, 10, 5);
    }

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

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

            Object[] row = createNewRow(true);
            setRowValue(row, RunsResultSet.COLUMN_RUNID, i);

            //Stir energy file specific
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new TFileReader(output));
                String line;
                String[] values;

                //first line
                line = getLine(reader);
                if (line == null) {
                    return;
                }
                values = line.split("\\|", -1);
                if (values.length == 2) {
                    try {
                        Double sci = Double.valueOf(values[0].trim());
                        if(Math.abs(sci * 1000) <= .5) sci = Math.abs(sci);
                        setRowValue(row, COLUMN_SCI, sci);
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse sci value in file: " + output.getAbsolutePath());
                    }

                    try {
                        Double energy = Double.valueOf(values[1].trim());
                        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());
                    } catch (ConversionNotFoundException cnf) {
                        LOGGER.warn("Unable to convert energy value in file: " + output.getAbsolutePath());
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse energy value in file: " + output.getAbsolutePath());
                    }

                } else {
                    LOGGER.error("Unexpected number of values on line 1 in file: " + output.getAbsolutePath());
                }

                //second line
                line = getLine(reader);
                values = line.split("\\|", -1);
                if (values.length == 3) {
                    try {
                        Double om = Double.valueOf(values[0].trim());
                        setRowValue(row, COLUMN_OMFACTOR, om);
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse " + COLUMN_OMFACTOR + " value in file: " + output.getAbsolutePath());
                    }

                    try {
                        Double er = Double.valueOf(values[1].trim());
                        setRowValue(row, COLUMN_ERFACTOR, er);
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse " + COLUMN_ERFACTOR + " value in file: " + output.getAbsolutePath());
                    }

                    try {
                        Double fo = Double.valueOf(values[2].trim());
                        setRowValue(row, COLUMN_FOFACTOR, fo);
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse " + COLUMN_FOFACTOR + " value in file: " + output.getAbsolutePath());
                    }
                } else {
                    LOGGER.error("Unexpected number of values on line 2 in file: " + output.getAbsolutePath());
                }

                //third line
                line = getLine(reader);
                values = line.split("\\|", -1);
                if (values.length == 4) {
                    try {
                        Double rennerom = Double.valueOf(values[0].trim());
                        setRowValue(row, COLUMN_RENNEROM, rennerom);
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse " + COLUMN_RENNEROM + " value in file: " + output.getAbsolutePath());
                    }

                    try {
                        Double rennerwater = Double.valueOf(values[1].trim());
                        setRowValue(row, COLUMN_RENNERWATER, rennerwater);
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse " + COLUMN_RENNERWATER + " value in file: " + output.getAbsolutePath());
                    }

                    try {
                        Double rennerwind = Double.valueOf(values[2].trim());
                        setRowValue(row, COLUMN_RENNERWIND, rennerwind);
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse " + COLUMN_RENNERWIND + " value in file: " + output.getAbsolutePath());
                    }

                    try {
                        Double rennerstir = Double.valueOf(values[3].trim());
                        setRowValue(row, COLUMN_RENNERSTIR, rennerstir);
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse " + COLUMN_RENNERSTIR + " value in file: " + output.getAbsolutePath());
                    }

                } else {
                    LOGGER.error("Unexpected number of values on line 3 in file: " + output.getAbsolutePath());
                }

                //fourth line
                line = getLine(reader);
                values = line.split("\\|", -1);
                if (values.length == 4) {
                    try {
                        Double avgbiomass = Double.valueOf(values[0].trim());
                        setRowValue(row, COLUMN_AVGBIOMASS, avgbiomass);
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse " + COLUMN_AVGBIOMASS + " value in file: " + output.getAbsolutePath());
                    }

                    try {
                        Double winderos = Double.valueOf(values[1].trim());
                        if (isUSUnits()) {
                            winderos = ConversionCalculator.convert(winderos, "kg/m^2", "t/ac");
                        }
                        setRowValue(row, COLUMN_WINDEROS, winderos);
                    } catch (UnitNotFoundException | ConversionNotFoundException unf) {
                        LOGGER.warn("Unable to convert " + COLUMN_WINDEROS + " value in file: " + output.getAbsolutePath());
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse " + COLUMN_WINDEROS + " value in file: " + output.getAbsolutePath());
                    }

                    try {
                        Double watereros = Double.valueOf(values[2].trim());
                        if (isUSUnits()) {
                            watereros = ConversionCalculator.convert(watereros, "kg/m^2", "t/ac");
                        }
                        setRowValue(row, COLUMN_WATEREROS, watereros);
                    } catch (UnitNotFoundException | ConversionNotFoundException unf) {
                        LOGGER.warn("Unable to convert " + COLUMN_WINDEROS + " value in file: " + output.getAbsolutePath());
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse " + COLUMN_WATEREROS + " value in file: " + output.getAbsolutePath());
                    }

                    try {
                        Double avgallstir = Double.valueOf(values[3].trim());
                        setRowValue(row, COLUMN_AVGALLSTIR, avgallstir);
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse " + COLUMN_AVGALLSTIR + " value in file: " + output.getAbsolutePath());
                    }

                } else {
                    LOGGER.error("Unexpected number of values on line 4 in file: " + output.getAbsolutePath());
                }

                //fifth line
                line = getLine(reader);
                values = line.split("\\|", -1);
                if (values.length == 1) {
                    try {
                        Double texturemult = Double.valueOf(values[0].trim());
                        setRowValue(row, COLUMN_TEXTUREMULT, texturemult);
                    } catch (NumberFormatException nfe) {
                        LOGGER.warn("Unable to parse sci value in file: " + output.getAbsolutePath());
                    }

                } else {
                    LOGGER.error("Unexpected number of values on line 5 in file: " + output.getAbsolutePath());
                }

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

        }

    }

    //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) {
        switch (columnName) {
            case COLUMN_ENERGY:
                if (us) {
                    return "gal diesel/ac";
                } else {
                    return "L diesel/ha";
                }
            case COLUMN_WATEREROS:
            case COLUMN_WINDEROS:
                if (us) {
                    return "t/ac";
                } else {
                    return "kg/m\u00B2";
                }
        }
        return null;
    }
}
