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.Date;
import java.sql.SQLException;
import java.sql.Types;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import usda.weru.util.ConversionCalculator;
import usda.weru.util.ConversionUnit;
import usda.weru.util.Util;
import usda.weru.util.table.Column;
import usda.weru.util.table.DataAdjustment;
import usda.weru.util.table.DataLimit;
import usda.weru.util.table.WepsTableMeta;
import usda.weru.weps.RunFileData;

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

    private static final String PATH_META = "tables/detail.xml";
    private static final Logger LOGGER = Logger.getLogger(OutputResultSet.class);

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

    /**
     * Index for the run.
     */
    public static final String COLUMN_RUNID = "runid";
    /**
     * Line number in the file.  0 is the header.  1 is the first line of data.  Line 0 is not included in the resultset.
     */
    public static final String COLUMN_LINE = "line";

    /**
     * Line key indicates the type of record the row represents.
     */
    public static final String COLUMN_KEY = "key";

    private static final String COLUMN_SDEDMOYR = "sd ed mo yr";
    //these three fields are used for special handling of the "sd ed mo yr" column

    /**
     *
     */
    public static final String COLUMN_STARTDATE = "startdate";

    /**
     *
     */
    public static final String COLUMN_ENDDATE = "enddate";

    /**
     *
     */
    public static final String COLUMN_PERIOD = "period";

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

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

    /**
     *
     */
    public static final String COLUMN_AVE_NO_EVNT = "ave_no_evnt";

    /**
     *
     */
    public static final String COLUMN_TOT_NO_EVNT = "tot_no_evnt";

    /**
     *
     */
    public static final String COLUMN_GLOSS_PER_EVNT = "gloss_per_evnt";

    /**
     *
     */
    public static final String COLUMN_NLOSS_PER_EVNT = "nloss_per_evnt";

    /**
     *
     */
    public static final String COLUMN_GROSS_LOSS = "gross_loss";

    /**
     *
     */
    public static final String COLUMN_TOT_LOSS = "tot_loss";

    /**
     *
     */
    public static final String COLUMN_CRPSALT = "crp+salt";

    /**
     *
     */
    public static final String COLUMN_SUSPEN = "suspen";

    /**
     *
     */
    public static final String COLUMN_PM10 = "pm10";

    /**
     *
     */
    public static final String COLUMN_CS1 = "cs1";

    /**
     *
     */
    public static final String COLUMN_CS2 = "cs2";

    /**
     *
     */
    public static final String COLUMN_CS3 = "cs3";

    /**
     *
     */
    public static final String COLUMN_CS4 = "cs4";

    /**
     *
     */
    public static final String COLUMN_SS1 = "ss1";

    /**
     *
     */
    public static final String COLUMN_SS2 = "ss2";

    /**
     *
     */
    public static final String COLUMN_SS3 = "ss3";

    /**
     *
     */
    public static final String COLUMN_SS4 = "ss4";

    /**
     *
     */
    public static final String COLUMN_PM1 = "pm1";

    /**
     *
     */
    public static final String COLUMN_PM2 = "pm2";

    /**
     *
     */
    public static final String COLUMN_PM3 = "pm3";

    /**
     *
     */
    public static final String COLUMN_PM4 = "pm4";

    /**
     *
     */
    public static final String COLUMN_SALT_LOSS = "salt_loss";

    /**
     *
     */
    public static final String COLUMN_LOSS_AREA = "loss_area";

    /**
     *
     */
    public static final String COLUMN_LOSS_FRAC = "loss_frac";

    /**
     *
     */
    public static final String COLUMN_SALT_DEP = "salt_dep";

    /**
     *
     */
    public static final String COLUMN_DEP_AREA = "dep_area";

    /**
     *
     */
    public static final String COLUMN_DEP_FRAC = "dep_frac";

    /**
     *
     */
    public static final String COLUMN_FLUX_RATE = "flux_rate";

    /**
     *
     */
    public static final String COLUMN_FLUX_AREA = "flux_area";

    /**
     *
     */
    public static final String COLUMN_FLUX_FRAC = "flux_frac";

    /**
     *
     */
    public static final String COLUMN_SHELT_AREA = "shelt_area";

    /**
     *
     */
    public static final String COLUMN_SHELT_FRAC = "shelt_frac";

    /**
     *
     */
    public static final String COLUMN_PRECIP = "precip";

    /**
     *
     */
    public static final String COLUMN_W_ENERGY = "w_energy";

    /**
     *
     */
    public static final String COLUMN_SNOW_COVER = "snow_cover";

    /**
     *
     */
    public static final String COLUMN_L_CAN_COV = "l_can_cov";

    /**
     *
     */
    public static final String COLUMN_L_SIL_AREA = "l_sil_area";

    /**
     *
     */
    public static final String COLUMN_L_ST_MASS = "l_st_mass";

    /**
     *
     */
    public static final String COLUMN_L_RT_MASS = "l_rt_mass";

    /**
     *
     */
    public static final String COLUMN_L_ST_HT = "l_st_ht";

    /**
     *
     */
    public static final String COLUMN_L_NO_STEM = "l_no_stem";

    /**
     *
     */
    public static final String COLUMN_D_FL_COV = "d_fl_cov";

    /**
     *
     */
    public static final String COLUMN_D_ST_SIL = "d_st_sil";

    /**
     *
     */
    public static final String COLUMN_D_FL_MASS = "d_fl_mass";

    /**
     *
     */
    public static final String COLUMN_D_ST_MASS = "d_st_mass";

    /**
     *
     */
    public static final String COLUMN_D_BG_MASS = "d_bg_mass";

    /**
     *
     */
    public static final String COLUMN_D_RT_MASS = "d_rt_mass";

    /**
     *
     */
    public static final String COLUMN_D_ST_HT = "d_st_ht";

    /**
     *
     */
    public static final String COLUMN_D_NO_STEM = "d_no_stem";

    /**
     *
     */
    public static final String COLUMN_B_F_FL_COV = "b_f_fl_cov";

    /**
     *
     */
    public static final String COLUMN_B_F_ST_SIL = "b_f_st_sil";

    /**
     *
     */
    public static final String COLUMN_B_M_FL_COV = "b_m_fl_cov";

    /**
     *
     */
    public static final String COLUMN_B_M_ST_SIL = "b_m_st_sil";

    /**
     *
     */
    public static final String COLUMN_B_M_BG_ALL = "b_m_bg_all";

    /**
     *
     */
    public static final String COLUMN_RDG_OR = "rdg_or";

    /**
     *
     */
    public static final String COLUMN_RDG_HT = "rdg_ht";

    /**
     *
     */
    public static final String COLUMN_RDG_SP = "rdg_sp";

    /**
     *
     */
    public static final String COLUMN_RR = "rr";

    /**
     *
     */
    public static final String COLUMN_SURF_84 = "surf_84";

    /**
     *
     */
    public static final String COLUMN_SURF_AS = "surf_AS";

    /**
     *
     */
    public static final String COLUMN_SURF_SURF_AG_DEN = "surf_ag_den";

    /**
     *
     */
    public static final String COLUMN_SURF_SURF_AG_CA = "surf_ag_CA";

    /**
     *
     */
    public static final String COLUMN_SURF_CRUST = "surf_crust";

    /**
     *
     */
    public static final String COLUMN_SURF_CRUST_AS = "crust_AS";

    /**
     *
     */
    public static final String COLUMN_SURF_CRUST_LM = "crust_LM";

    /**
     *
     */
    public static final String COLUMN_SURF_CRUST_THICK = "crust_thick";

    /**
     *
     */
    public static final String COLUMN_SURF_CRUST_DEN = "crust_den";

    /**
     *
     */
    public static final String COLUMN_SURF_CRUST_LF = "crust_LF";

    /**
     *
     */
    public static final String COLUMN_SURF_CRUST_CA = "crust_CA";

    /**
     *
     */
    public static final String COLUMN_DAYS = "days";

    /**
     *
     */
    public static final String COLUMN_LOWER_LIMIT = "_lowerlimit";

    /**
     *
     */
    public static final String COLUMN_UPPER_LIMIT = "_upperlimit";

    private final WepsConnection c_con;
    private boolean c_filled;
    private final Map<String, ConversionUnit> c_siUnits;
    private final Map<String, ConversionUnit> c_usUnits;

    private WepsTableMeta c_meta;

    /**
     *
     * @param con
     * @throws SQLException
     */
    public OutputResultSet(WepsConnection con) throws SQLException {
        c_con = con;
        addColumn(COLUMN_RUNID, Types.INTEGER, 10, 0);
        addColumn(COLUMN_LINE, Types.INTEGER, 10, 0);
        addColumn(COLUMN_KEY, Types.CHAR, 1, 0);
        addColumn(COLUMN_STARTDATE, Types.DATE, 0, 0);
        addColumn(COLUMN_ENDDATE, Types.DATE, 0, 0);
        addColumn(COLUMN_PERIOD, Types.INTEGER, 10, 0);
        addColumn(COLUMN_OPERATION, Types.VARCHAR, 255, 0);
        addColumn(COLUMN_CROP, Types.VARCHAR, 255, 0);
        addColumn(COLUMN_DAYS, Types.INTEGER, 0, 0);

        //create the unit maps
        c_siUnits = new HashMap<String, ConversionUnit>();
        c_usUnits = new HashMap<String, ConversionUnit>();
        addColumn(COLUMN_GROSS_LOSS, Types.DOUBLE, 10, 3, "kg/m^2", "t/ac");
        addColumn(COLUMN_GROSS_LOSS + COLUMN_LOWER_LIMIT, Types.INTEGER, 10, 0);
        addColumn(COLUMN_GROSS_LOSS + COLUMN_UPPER_LIMIT, Types.INTEGER, 10, 0);

        addColumn(COLUMN_TOT_LOSS, Types.DOUBLE, 10, 3, "kg/m^2", "t/ac");
        addColumn(COLUMN_TOT_LOSS + COLUMN_LOWER_LIMIT, Types.INTEGER, 10, 0);
        addColumn(COLUMN_TOT_LOSS + COLUMN_UPPER_LIMIT, Types.INTEGER, 10, 0);

        addColumn(COLUMN_CRPSALT, Types.DOUBLE, 10, 3, "kg/m^2", "t/ac");
        addColumn(COLUMN_CRPSALT + COLUMN_LOWER_LIMIT, Types.INTEGER, 10, 0);
        addColumn(COLUMN_CRPSALT + COLUMN_UPPER_LIMIT, Types.INTEGER, 10, 0);

        addColumn(COLUMN_SUSPEN, Types.DOUBLE, 10, 3, "kg/m^2", "t/ac");
        addColumn(COLUMN_SUSPEN + COLUMN_LOWER_LIMIT, Types.INTEGER, 10, 0);
        addColumn(COLUMN_SUSPEN + COLUMN_UPPER_LIMIT, Types.INTEGER, 10, 0);

        addColumn(COLUMN_PM10, Types.DOUBLE, 10, 3, "kg/m^2", "t/ac");
        addColumn(COLUMN_PM10 + COLUMN_LOWER_LIMIT, Types.INTEGER, 10, 0);
        addColumn(COLUMN_PM10 + COLUMN_UPPER_LIMIT, Types.INTEGER, 10, 0);

        addColumn(COLUMN_AVE_NO_EVNT, Types.DOUBLE, 10, 3, "fraction", "fraction");
        addColumn(COLUMN_TOT_NO_EVNT, Types.DOUBLE, 10, 3, "fraction", "fraction");

        addColumn(COLUMN_GLOSS_PER_EVNT, Types.DOUBLE, 10, 3, "kg/m^2", "t/ac");
        addColumn(COLUMN_NLOSS_PER_EVNT, Types.DOUBLE, 10, 3, "kg/m^2", "t/ac");

        addColumn(COLUMN_CS1, Types.DOUBLE, 10, 3, "kg/m", "tn/1000ft");
        addColumn(COLUMN_CS2, Types.DOUBLE, 10, 3, "kg/m", "tn/1000ft");
        addColumn(COLUMN_CS3, Types.DOUBLE, 10, 3, "kg/m", "tn/1000ft");
        addColumn(COLUMN_CS4, Types.DOUBLE, 10, 3, "kg/m", "tn/1000ft");

        addColumn(COLUMN_SS1, Types.DOUBLE, 10, 3, "kg/m", "tn/1000ft");
        addColumn(COLUMN_SS2, Types.DOUBLE, 10, 3, "kg/m", "tn/1000ft");
        addColumn(COLUMN_SS3, Types.DOUBLE, 10, 3, "kg/m", "tn/1000ft");
        addColumn(COLUMN_SS4, Types.DOUBLE, 10, 3, "kg/m", "tn/1000ft");

        addColumn(COLUMN_PM1, Types.DOUBLE, 10, 3, "kg/m", "tn/1000ft");
        addColumn(COLUMN_PM2, Types.DOUBLE, 10, 3, "kg/m", "tn/1000ft");
        addColumn(COLUMN_PM3, Types.DOUBLE, 10, 3, "kg/m", "tn/1000ft");
        addColumn(COLUMN_PM4, Types.DOUBLE, 10, 3, "kg/m", "tn/1000ft");

        addColumn(COLUMN_SALT_LOSS, Types.DOUBLE, 10, 3, "kg/m^2", "t/ac");
        addColumn(COLUMN_LOSS_AREA, Types.DOUBLE, 10, 3, "ha", "ac");
        addColumn(COLUMN_LOSS_FRAC, Types.DOUBLE, 10, 3, "fraction", "fraction");

        addColumn(COLUMN_SALT_DEP, Types.DOUBLE, 10, 3, "kg/m^2", "t/ac");
        addColumn(COLUMN_DEP_AREA, Types.DOUBLE, 10, 3, "ha", "ac");
        addColumn(COLUMN_DEP_FRAC, Types.DOUBLE, 10, 3, "fraction", "fraction");

//        addColumn(COLUMN_FLUX_RATE, Types.DOUBLE, 10, 3, "kg/m^2", "t/ac");  
        addColumn(COLUMN_FLUX_AREA, Types.DOUBLE, 10, 3, "ha", "ac");
        addColumn(COLUMN_FLUX_FRAC, Types.DOUBLE, 10, 3, "fraction", "fraction");
//
        addColumn(COLUMN_SHELT_AREA, Types.DOUBLE, 10, 3, "ha", "ac");
        addColumn(COLUMN_SHELT_FRAC, Types.DOUBLE, 10, 3, "fraction", "fraction");

        addColumn(COLUMN_PRECIP, Types.DOUBLE, 10, 3, "mm", "in");
        addColumn(COLUMN_W_ENERGY, Types.DOUBLE, 10, 3, "KJ/m^2/day", "KJ/m^2/day");
        addColumn(COLUMN_SNOW_COVER, Types.DOUBLE, 10, 3, "fraction", "fraction");

        addColumn(COLUMN_L_CAN_COV, Types.DOUBLE, 10, 3, "fraction", "fraction");
        addColumn(COLUMN_L_SIL_AREA, Types.DOUBLE, 10, 3, "fraction", "fraction");
        addColumn(COLUMN_L_ST_MASS, Types.DOUBLE, 10, 3, "kg/m^2", "lb/ac");
        addColumn(COLUMN_L_RT_MASS, Types.DOUBLE, 10, 3, "kg/m^2", "lb/ac");
        addColumn(COLUMN_L_ST_HT, Types.DOUBLE, 10, 3, "mm", "in");
        addColumn(COLUMN_L_NO_STEM, Types.DOUBLE, 10, 3, "#/m^2", "#/ac");

        addColumn(COLUMN_D_FL_COV, Types.DOUBLE, 10, 3, "fraction", "fraction");
        addColumn(COLUMN_D_ST_SIL, Types.DOUBLE, 10, 3, "fraction", "fraction");
        addColumn(COLUMN_D_FL_MASS, Types.DOUBLE, 10, 3, "kg/m^2", "lb/ac");
        addColumn(COLUMN_D_ST_MASS, Types.DOUBLE, 10, 3, "kg/m^2", "lb/ac");
        addColumn(COLUMN_D_BG_MASS, Types.DOUBLE, 10, 3, "kg/m^2", "lb/ac");
        addColumn(COLUMN_D_RT_MASS, Types.DOUBLE, 10, 3, "kg/m^2", "lb/ac");
        addColumn(COLUMN_D_ST_HT, Types.DOUBLE, 10, 3, "mm", "in");
        addColumn(COLUMN_D_NO_STEM, Types.DOUBLE, 10, 3, "#/m^2", "#/ac");

        addColumn(COLUMN_B_F_FL_COV, Types.DOUBLE, 10, 3, "fraction", "fraction");
        addColumn(COLUMN_B_F_ST_SIL, Types.DOUBLE, 10, 3, "fraction", "fraction");
        addColumn(COLUMN_B_M_FL_COV, Types.DOUBLE, 10, 3, "kg/m^2", "lb/ac");
        addColumn(COLUMN_B_M_ST_SIL, Types.DOUBLE, 10, 3, "kg/m^2", "lb/ac");
        addColumn(COLUMN_B_M_BG_ALL, Types.DOUBLE, 10, 3, "kg/m^2", "lb/ac");

        addColumn(COLUMN_RDG_OR, Types.DOUBLE, 10, 3, "degree", "degree");
        addColumn(COLUMN_RDG_HT, Types.DOUBLE, 10, 3, "mm", "in");
        addColumn(COLUMN_RDG_SP, Types.DOUBLE, 10, 3, "mm", "in");
        addColumn(COLUMN_RR, Types.DOUBLE, 10, 3, "mm", "in");

        addColumn(COLUMN_SURF_84, Types.DOUBLE, 10, 3, "fraction", "fraction");
        addColumn(COLUMN_SURF_AS, Types.DOUBLE, 10, 3, "ln(J/m^2)", "ln(J/m^2)");
        addColumn(COLUMN_SURF_SURF_AG_DEN, Types.DOUBLE, 10, 3, "Mg/m^3", "lb/ft^3");
        addColumn(COLUMN_SURF_SURF_AG_CA, Types.DOUBLE, 10, 3, "fraction", "fraction");
        addColumn(COLUMN_SURF_CRUST_AS, Types.DOUBLE, 10, 3, "ln(J/m^2)", "ln(J/m^2)");
//
        addColumn(COLUMN_SURF_CRUST, Types.DOUBLE, 10, 3, "fraction", "fraction");
        addColumn(COLUMN_SURF_CRUST_LM, Types.DOUBLE, 10, 3, "Mg/m^3", "lb/ft^3");
        addColumn(COLUMN_SURF_CRUST_THICK, Types.DOUBLE, 10, 3, "mm", "in");
        addColumn(COLUMN_SURF_CRUST_DEN, Types.DOUBLE, 10, 3, "Mg/m^3", "lb/ft^3");
        addColumn(COLUMN_SURF_CRUST_LF, Types.DOUBLE, 10, 3, "fraction", "fraction");
        addColumn(COLUMN_SURF_CRUST_CA, Types.DOUBLE, 10, 3, "1/m", "1/ft");

    }

    private void addColumn(String columnName, int type, int p, int s, String si, String us) throws SQLException {
        try {
            ConversionUnit siUnit = ConversionCalculator.getUnitFromTag(si);
            ConversionUnit usUnit = ConversionCalculator.getUnitFromTag(us);
            c_siUnits.put(columnName, siUnit);
            c_usUnits.put(columnName, usUnit);
            addColumn(columnName, type, p, s);
        } catch (ConversionCalculator.UnitNotFoundException e) {
            //fail fast
            throw new SQLException("Unsupported units.", e);
        }

    }

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

        if (c_meta == null) {
            c_meta = new WepsTableMeta();
            c_meta.fromFile(new TFile(PATH_META));
        }

        TFile[] files = c_con.getRunFiles();

        for (int i = 0; i < files.length; i++) {
            TFile runDir = files[i];
            TFile outputFile = new TFile(runDir, RunFileData.WepsOutput);

            if (outputFile.exists()) {

                BufferedReader in = null;
                try {
                    in = new BufferedReader(new TFileReader(outputFile));

                    //first line is the headers.  We create a list of the column headers so we know what column to deal with.  The order is not likely to change.  Therefore, instead of dealing with column 1, we deal with the column mapped to "sd ed mo yr";
                    List<String> columns = new LinkedList<String>();
                    String headerLine = in.readLine();
                    if (headerLine == null) {
                        return;
                    }
                    String[] headerParts = headerLine.split("\\|", -1);
                    for (String columnName : headerParts) {
                        //trim and add each column to the list
                        columnName = columnName.trim();
                        columns.add(columnName);
                    }

                    int keyIndex = columns.indexOf(COLUMN_KEY);
                    String line;
                    int lineIndex = 0; //0 = header, not included in resultset
                    while ((line = in.readLine()) != null) {
                        //blank line
                        if (line.trim().length() == 0) {
                            continue;
                        }
                        //split the line into the value parts
                        String[] parts = line.split("\\|", -1);
                        if (parts.length != columns.size()) {
                            //little sanity check
                            LOGGER.error("Mismatched column count.  Line: " + lineIndex + " of file: " + outputFile.getAbsolutePath());
                            continue;
                        }

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

                        //Add the line index for sorting convienence
                        lineIndex++;
                        setRowValue(row, COLUMN_LINE, lineIndex);

                        //handle the key column
                        String key = parts[keyIndex].trim();
                        setRowValue(row, COLUMN_KEY, key);

                        for (int ci = 1; ci < parts.length; ci++) {
                            String columnName = columns.get(ci);
                            if (columnName.length() == 0) {
                                continue;
                            }
                            String part = parts[ci].trim();
                            handleColumn(row, key, columnName, part);
                        }

                    }

                } catch (IOException ioe) {
                    LOGGER.error("Error reading output file: " + outputFile.getAbsolutePath(), ioe);
                } finally {
                    if (in != null) {
                        try {
                            in.close();
                        } catch (IOException e) {
                            LOGGER.error("Error closing output file: " + outputFile.getAbsolutePath(), e);
                        }
                    }
                    c_filled = true;
                }
            }
        }

    }
    private static final MessageFormat FORMAT_PERIODDATES = new MessageFormat("{0}-{1}/{2}/{3}");
    private static final MessageFormat FORMAT_ROTATIONYEARPERIOD = new MessageFormat("Rot. yr:{0}");
    private static final MessageFormat FORMAT_MONTHPERIOD = new MessageFormat("Month:{0}");
    private static final MessageFormat FORMAT_YEARPERIOD = new MessageFormat("Year:{0}");

    private void handleColumn(Object[] row, String key, String columnName, String text) throws SQLException {
        if (COLUMN_SDEDMOYR.equals(columnName)) {
            //handle the dates
            switch (key) {
                case "P":
                    try {
                        //Period row, sd-ed/mo/yr
                        Object[] parts = FORMAT_PERIODDATES.parse(text);

                        int start = Integer.valueOf(parts[0].toString().trim());
                        int end = Integer.valueOf(parts[1].toString().trim());
                        int month = Integer.valueOf(parts[2].toString().trim());
                        month--;    //java months are 0 based
                        int year = Integer.valueOf(parts[3].toString().trim());

                        Calendar cal = Calendar.getInstance();
                        cal.set(year, month, start);
                        setRowValue(row, COLUMN_STARTDATE, new Date(cal.getTimeInMillis()));

                        cal.set(year, month, end);
                        setRowValue(row, COLUMN_ENDDATE, new Date(cal.getTimeInMillis()));
                        //      setRowValue(row,COLUMN_DAYS,0);
                    } catch (ParseException pe) {
                        LOGGER.error("Error parsing period date: " + text, pe);
                    }
                    break;
                case "Y":
                    //rotation year row, Rot. yr: #
                    try {
                        Object[] parts = FORMAT_ROTATIONYEARPERIOD.parse(text);
                        Integer period = Integer.valueOf(parts[0].toString().trim());
                        setRowValue(row, COLUMN_PERIOD, period);
                    } catch (ParseException pe) {
                        LOGGER.error("Error parsing rotation year period: " + text, pe);
                    }
                    break;
                case "m":
                    //month row, Month:    #
                    try {
                        Object[] parts = FORMAT_MONTHPERIOD.parse(text);
                        Integer period = Integer.valueOf(parts[0].toString().trim());
                        setRowValue(row, COLUMN_PERIOD, period);
                    } catch (ParseException pe) {
                        LOGGER.error("Error parsing rotation year period: " + text, pe);
                    }
                    break;
                case "y":
                    //year row, Year:     #
                    try {
                        Object[] parts = FORMAT_YEARPERIOD.parse(text);
                        Integer period = Integer.valueOf(parts[0].toString().trim());
                        setRowValue(row, COLUMN_PERIOD, period);
                    } catch (ParseException pe) {
                        LOGGER.error("Error parsing rotation year period: " + text, pe);
                    }
                    break;
            }
        } else if (COLUMN_OPERATION.equals(columnName)) {
            if (text != null && text.length() > 0) {
                setRowValue(row, COLUMN_OPERATION, text);
            }

        } else if (COLUMN_CROP.equals(columnName)) {
            if (text != null && text.length() > 0) {
                setRowValue(row, COLUMN_CROP, text);
            }
        } else {
            try {
                Double value = Double.valueOf(text);
                Column column = c_meta.getColumn(columnName);

                //apply adjustments, some soil loss values need to be multiplied by -1
                if (column != null && column.getAdjustmentList() != null) {
                    for (DataAdjustment adjust : column.getAdjustmentList()) {
                        value = (Double) adjust.adjust(value);
                    }
                }

                if (isUSUnits() && c_siUnits.containsKey(columnName)) {

                    ConversionUnit siUnit = c_siUnits.get(columnName);
                    ConversionUnit usUnit = c_usUnits.get(columnName);
                    value = ConversionCalculator.convert(value, siUnit, usUnit);
                }
                if (Math.abs(value) == 0) {
                    value = 0d;
                }
                setRowValue(row, columnName, value);

                //handle limits
                if (column != null) {
                    DataLimit limit = column.getLimit(isUSUnits() ? Util.USUnits : Util.SIUnits);
                    if (limit != null && findColumn(columnName + COLUMN_LOWER_LIMIT) > 0) {
                        if (limit.outisdeLowerBound(value)) {
                            setRowValue(row, columnName + COLUMN_LOWER_LIMIT, 1);
                        } else {
                            setRowValue(row, columnName + COLUMN_LOWER_LIMIT, 0);
                        }
                    }
                    if (limit != null && findColumn(columnName + COLUMN_UPPER_LIMIT) > 0) {
                        if (limit.outisdeUpperBound(value)) {
                            setRowValue(row, columnName + COLUMN_UPPER_LIMIT, 1);
                        } else {
                            setRowValue(row, columnName + COLUMN_UPPER_LIMIT, 0);
                        }

                    }
                }

            } catch (NumberFormatException | SQLException nfe) {
            } catch (ConversionCalculator.ConversionNotFoundException e) {
                LOGGER.error("Error converting value.", e);
            }
        }

    }

}
