/*
 * SimulationPanel.java
 *
 * Created on October 23, 2008, 2:38 PM
 */
package usda.weru.weps;

import com.klg.jclass.util.swing.JCPopupEvent;
import com.klg.jclass.util.swing.JCPopupListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.FileNotFoundException;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import javax.help.CSH;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import org.apache.log4j.Logger;
import usda.weru.mcrew.DisplayCalendar;
import usda.weru.mcrew.JulianCalendar;
import usda.weru.soil.IFC;
import usda.weru.util.ConfigData;
import usda.weru.util.ConvertedValue;
import usda.weru.util.Util;

/**
 *
 * @author Joseph Levin <joelevin@weru.ksu.edu>
 */
public class SimulationPanel extends JPanel implements PropertyChangeListener {

    private static final long serialVersionUID = 1L;

    private static final Logger LOGGER = Logger.getLogger(SimulationPanel.class);

    private boolean c_nrcsInstall = false;

    DateFormat df = new SimpleDateFormat("MMMM dd, yyyy");
    private simCalendarSelector simCalStart;
    private simCalendarSelector simCalEnd;

    //variables for setting condition for preventing run with unordered dates
    //this is used in the weps.java file for preventing the error
    private static boolean datesUnordered = false;

    public static boolean getDatesUnordered() {
        return datesUnordered;
    }

    private static void setDatesUnordered(boolean dateDisjoint) {
        SimulationPanel.datesUnordered = dateDisjoint;
    }

    /**
     * Creates new form SimulationPanel
     */
    public SimulationPanel() {
        initComponents();
        addHelp();

        //    waterField.setChecks(0, WepsTextField.CHECK_INCLUSIVE, 0, WepsTextField.CHECK_DISABLED);
        c_water.addPropertyChangeListener(ConvertedValue.PROP_VALUE, new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                firePropertyChange(RunFileData.WaterErosionLoss, null, c_water.toStringValue());

            }
        });

        //do not allow text box editing
        //this may prevent user input errors
        startDateText.setEditable(false);
        endDateText.setEditable(false);

        simCalStart = new simCalendarSelector(false);
        startDateField.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {
                simCalStart.calanderPopOut();
            }
        });
        startDateField.setVisible(true);

        simCalEnd = new simCalendarSelector(true);
        endDateField.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {
                simCalEnd.calanderPopOut();
            }
        });
        endDateField.setVisible(true);

        //addHelp();
        LOGGER.debug("Simulation panel initilized.");
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        bindingGroup = new org.jdesktop.beansbinding.BindingGroup();

        c_water = new ConvertedValue(Util.SIUnits, "kg/m^2");
        c_water.addDisplayUnits(Util.USUnits, "t/ac");
        c_soilSlopeValue = new ConvertedValue(Util.SIUnits, "m/m");
        c_soilSlopeValue.addDisplayUnits(Util.USUnits, "ft/ft");
        c_soilRockFragmentsValue = new ConvertedValue(Util.SIUnits, "m^2/m^2");
        c_soilRockFragmentsValue.addDisplayUnits(Util.USUnits, "ft^2/ft^2");
        jLayeredPane1 = new javax.swing.JLayeredPane();
        waterField = new usda.weru.util.WepsTextField();
        waterUnitLabel = new javax.swing.JLabel();
        modeLabel = new javax.swing.JLabel();
        cycleCountLabel = new javax.swing.JLabel();
        startDateLabel = new javax.swing.JLabel();
        endDateLabel = new javax.swing.JLabel();
        waterLabel = new javax.swing.JLabel();
        soilSlopeLabel = new javax.swing.JLabel();
        rockFragmentsLabel = new javax.swing.JLabel();
        soilSlopeUnitLabel = new javax.swing.JLabel();
        rockFragmentsUnitLabel = new javax.swing.JLabel();
        cycleCountField = new javax.swing.JSpinner();
        soilSlopeField = new usda.weru.weps.gui.ComboEditorField();
        rockFragmentsField = new usda.weru.weps.gui.ComboEditorField();
        modeField = new javax.swing.JComboBox<>();
        soilRockFragmentsValue = new usda.weru.util.WepsTextField();
        soilSlopeValue = new usda.weru.util.WepsTextField();
        soilSlopeLabel1 = new javax.swing.JLabel();
        soilSlopeLabel2 = new javax.swing.JLabel();
        rockFragmentsUnits1 = new javax.swing.JLabel();
        regionSlopeUnits1 = new javax.swing.JLabel();
        startDateText = new javax.swing.JTextField();
        endDateText = new javax.swing.JTextField();
        startDateField = new javax.swing.JButton();
        endDateField = new javax.swing.JButton();

        c_water.setOutputFormat("#0.0000");

        c_soilSlopeValue.setOutputFormat("#0.0000");

        c_soilRockFragmentsValue.setOutputFormat("#0.0000");

        javax.swing.GroupLayout jLayeredPane1Layout = new javax.swing.GroupLayout(jLayeredPane1);
        jLayeredPane1.setLayout(jLayeredPane1Layout);
        jLayeredPane1Layout.setHorizontalGroup(
            jLayeredPane1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 100, Short.MAX_VALUE)
        );
        jLayeredPane1Layout.setVerticalGroup(
            jLayeredPane1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 100, Short.MAX_VALUE)
        );

        waterField.setToolTipText("");
        waterField.setFormat("#0.00#");
        waterField.setFormatEdit("#0.0000");
        waterField.setInputVerifier(new DoubleInputVerifier());
        waterField.setPreferredSize(new java.awt.Dimension(100, 20));

        org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, c_water, org.jdesktop.beansbinding.ELProperty.create("${displayValue}"), waterField, org.jdesktop.beansbinding.BeanProperty.create("value"));
        bindingGroup.addBinding(binding);

        waterField.setInputVerifier(new DoubleInputVerifier());

        waterUnitLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, c_water, org.jdesktop.beansbinding.ELProperty.create("${displayUnits.abbreviation}"), waterUnitLabel, org.jdesktop.beansbinding.BeanProperty.create("text"));
        binding.setSourceUnreadableValue("units");
        bindingGroup.addBinding(binding);

        modeLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        modeLabel.setText("Run Mode");

        cycleCountLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        cycleCountLabel.setText("Cycle Count");

        startDateLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        startDateLabel.setText("Start Date");

        endDateLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        endDateLabel.setText("End Date");

        waterLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        waterLabel.setText("Water Erosion");

        soilSlopeLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        soilSlopeLabel.setText("Region Slope");

        rockFragmentsLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        rockFragmentsLabel.setText("Rock Fragments");

        soilSlopeUnitLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, soilSlopeField, org.jdesktop.beansbinding.ELProperty.create("${convertedValue.displayUnits.abbreviation}"), soilSlopeUnitLabel, org.jdesktop.beansbinding.BeanProperty.create("text"));
        bindingGroup.addBinding(binding);

        rockFragmentsUnitLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, rockFragmentsField, org.jdesktop.beansbinding.ELProperty.create("${convertedValue.displayUnits.abbreviation}"), rockFragmentsUnitLabel, org.jdesktop.beansbinding.BeanProperty.create("text"));
        bindingGroup.addBinding(binding);

        cycleCountField.setModel(new javax.swing.SpinnerNumberModel(50, 1, null, 1));

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, this, org.jdesktop.beansbinding.ELProperty.create("${cycleCount}"), cycleCountField, org.jdesktop.beansbinding.BeanProperty.create("value"));
        bindingGroup.addBinding(binding);

        soilSlopeField.getConvertedValue().setBaseUnits("m/m");
        soilSlopeField.getConvertedValue().addDisplayUnits(Util.SIUnits, "m/m");
        soilSlopeField.getConvertedValue().addDisplayUnits(Util.USUnits, "ft/ft");
        String[] soilSlopeChoices = {"Override Soil Slope", "Use Soil Slope from Soils Database", "Level Basin, No Runoff", "Slope 0.001 (0.1%)", "Slope 0.01 (1%)", "Slope 0.02 (2%)", "Slope 0.03 (3%)", "Slope 0.05 (5%)", "Slope 0.10 (10%)"};
        double[] soilSlopeValues = {0, -1, -2, 0.001, 0.01, 0.02, 0.03, 0.05, 0.10};
        String[] soilSlopeDisplay = {null, "FROM SOIL DB", "BASIN", null, null, null,null,null, null};
        soilSlopeField.intilize(soilSlopeChoices, soilSlopeValues, soilSlopeDisplay, 0);
        soilSlopeField.setPreferredSize(new java.awt.Dimension(100, 20));

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, this, org.jdesktop.beansbinding.ELProperty.create("${soilSlope}"), soilSlopeField, org.jdesktop.beansbinding.BeanProperty.create("value"));
        bindingGroup.addBinding(binding);

        soilSlopeField.setInputVerifier(new PercentageInputVerifier());

        rockFragmentsField.getConvertedValue().setBaseUnits("m^2/m^2");
        rockFragmentsField.getConvertedValue().addDisplayUnits(Util.SIUnits, "m^2/m^2");
        rockFragmentsField.getConvertedValue().addDisplayUnits(Util.USUnits, "ft^2/ft^2");
        String[] rockFragmentsChoices = {"Override Rock Fragments", "Use Rock Fragments from Soils Database"};
        double[] rockFragmentsValues = {0, -1};
        String[] rockFragmentsDisplay = {null, "FROM SOIL DB"};
        rockFragmentsField.intilize(rockFragmentsChoices, rockFragmentsValues, rockFragmentsDisplay, 0);
        rockFragmentsField.setPreferredSize(new java.awt.Dimension(100, 20));

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, this, org.jdesktop.beansbinding.ELProperty.create("${rockFragments}"), rockFragmentsField, org.jdesktop.beansbinding.BeanProperty.create("value"));
        bindingGroup.addBinding(binding);

        rockFragmentsField.setInputVerifier(new PercentageInputVerifier());

        modeField.setModel(new javax.swing.DefaultComboBoxModel<String>(new String[] { "NRCS", "Cycle", "Dates" }));
        modeField.setPreferredSize(new java.awt.Dimension(54, 20));
        modeField.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                modeFieldItemStateChanged(evt);
            }
        });

        soilRockFragmentsValue.setEditable(false);
        soilRockFragmentsValue.setDisabledTextColor(java.awt.SystemColor.textText);
        soilRockFragmentsValue.setFormat("#0.00##");
        soilRockFragmentsValue.setFormatEdit("#0.000#");
        soilRockFragmentsValue.setPreferredSize(new java.awt.Dimension(100, 20));

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ, c_soilRockFragmentsValue, org.jdesktop.beansbinding.ELProperty.create("${displayValue}"), soilRockFragmentsValue, org.jdesktop.beansbinding.BeanProperty.create("value"));
        bindingGroup.addBinding(binding);

        soilSlopeValue.setEditable(false);
        soilSlopeValue.setDisabledTextColor(java.awt.SystemColor.textText);
        soilSlopeValue.setFormat("#0.00##");
        soilSlopeValue.setFormatEdit("#0.000#");
        soilSlopeValue.setPreferredSize(new java.awt.Dimension(100, 20));

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ, c_soilSlopeValue, org.jdesktop.beansbinding.ELProperty.create("${displayValue}"), soilSlopeValue, org.jdesktop.beansbinding.BeanProperty.create("value"));
        bindingGroup.addBinding(binding);

        soilSlopeLabel1.setFont(soilSlopeLabel1.getFont().deriveFont(soilSlopeLabel1.getFont().getStyle() & ~java.awt.Font.BOLD));
        soilSlopeLabel1.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        soilSlopeLabel1.setText("Soil DB Value");

        soilSlopeLabel2.setFont(soilSlopeLabel2.getFont().deriveFont(soilSlopeLabel2.getFont().getStyle() & ~java.awt.Font.BOLD));
        soilSlopeLabel2.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        soilSlopeLabel2.setText("Soil DB Value");

        rockFragmentsUnits1.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, rockFragmentsField, org.jdesktop.beansbinding.ELProperty.create("${convertedValue.displayUnits.abbreviation}"), rockFragmentsUnits1, org.jdesktop.beansbinding.BeanProperty.create("text"));
        binding.setSourceUnreadableValue("units");
        bindingGroup.addBinding(binding);

        regionSlopeUnits1.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, soilSlopeField, org.jdesktop.beansbinding.ELProperty.create("${convertedValue.displayUnits.abbreviation}"), regionSlopeUnits1, org.jdesktop.beansbinding.BeanProperty.create("text"));
        binding.setSourceUnreadableValue("units");
        bindingGroup.addBinding(binding);

        startDateText.setText("Jan 1, 0001");
        startDateText.setPreferredSize(new java.awt.Dimension(59, 21));
        startDateText.setRequestFocusEnabled(false);

        endDateText.setText("Dec 31, 0001");
        endDateText.setPreferredSize(new java.awt.Dimension(59, 21));
        endDateText.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                endDateTextActionPerformed(evt);
            }
        });

        startDateField.setIcon(new javax.swing.ImageIcon(getClass().getResource("/usda/weru/resources/calpng2.png"))); // NOI18N
        startDateField.setPreferredSize(new java.awt.Dimension(27, 20));

        endDateField.setIcon(new javax.swing.ImageIcon(getClass().getResource("/usda/weru/resources/calpng2.png"))); // NOI18N
        endDateField.setPreferredSize(new java.awt.Dimension(27, 20));

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(soilSlopeLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, 79, Short.MAX_VALUE)
                    .addComponent(cycleCountLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 79, Short.MAX_VALUE)
                    .addComponent(startDateLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 79, Short.MAX_VALUE)
                    .addComponent(endDateLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 79, Short.MAX_VALUE)
                    .addComponent(waterLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 79, Short.MAX_VALUE)
                    .addComponent(soilSlopeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 79, Short.MAX_VALUE)
                    .addComponent(soilSlopeLabel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 79, Short.MAX_VALUE)
                    .addComponent(rockFragmentsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 79, Short.MAX_VALUE)
                    .addComponent(modeLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 79, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(cycleCountField)
                    .addComponent(modeField, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                            .addComponent(waterField, javax.swing.GroupLayout.DEFAULT_SIZE, 98, Short.MAX_VALUE)
                            .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                                    .addComponent(soilSlopeValue, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 1, Short.MAX_VALUE)
                                    .addComponent(soilSlopeField, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                                .addGap(1, 1, 1)))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                            .addComponent(regionSlopeUnits1, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(waterUnitLabel, javax.swing.GroupLayout.Alignment.TRAILING)
                            .addComponent(soilSlopeUnitLabel, javax.swing.GroupLayout.Alignment.TRAILING)))
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(soilRockFragmentsValue, javax.swing.GroupLayout.DEFAULT_SIZE, 98, Short.MAX_VALUE)
                            .addComponent(rockFragmentsField, javax.swing.GroupLayout.DEFAULT_SIZE, 98, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                            .addComponent(rockFragmentsUnits1, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(rockFragmentsUnitLabel)))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(startDateText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(endDateText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(startDateField, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(endDateField, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE))))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(modeLabel)
                    .addComponent(modeField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(cycleCountLabel)
                    .addComponent(cycleCountField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(1, 1, 1)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(startDateLabel)
                    .addComponent(startDateText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(startDateField, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                        .addComponent(endDateText, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addComponent(endDateLabel))
                    .addComponent(endDateField, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(waterUnitLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(waterLabel)
                    .addComponent(waterField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(regionSlopeUnits1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(soilSlopeLabel)
                    .addComponent(soilSlopeField, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addGap(0, 0, 0)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(soilSlopeValue, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(soilSlopeLabel1)
                    .addComponent(soilSlopeUnitLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(rockFragmentsUnits1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(rockFragmentsLabel)
                    .addComponent(rockFragmentsField, javax.swing.GroupLayout.DEFAULT_SIZE, 26, Short.MAX_VALUE))
                .addGap(0, 0, 0)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(soilRockFragmentsValue, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(soilSlopeLabel2)
                    .addComponent(rockFragmentsUnitLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(19, Short.MAX_VALUE))
        );

        bindingGroup.bind();
    }// </editor-fold>//GEN-END:initComponents

private void modeFieldItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_modeFieldItemStateChanged
    if (!holdFire && evt.getStateChange() == ItemEvent.SELECTED) {
        switch (modeField.getSelectedIndex()) {
            case 0:
                firePropertyChange(RunFileData.RunTypeDisp, null, ConfigData.NRCS);
                break;
            case 1:
                firePropertyChange(RunFileData.RunTypeDisp, null, ConfigData.Cycle);
                break;
            case 2:
                firePropertyChange(RunFileData.RunTypeDisp, null, ConfigData.Dates);
                break;
            default:
                return;
        }
    }
}//GEN-LAST:event_modeFieldItemStateChanged

    private void endDateTextActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_endDateTextActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_endDateTextActionPerformed


    // Variables declaration - do not modify//GEN-BEGIN:variables
    protected usda.weru.util.ConvertedValue c_soilRockFragmentsValue;
    protected usda.weru.util.ConvertedValue c_soilSlopeValue;
    protected usda.weru.util.ConvertedValue c_water;
    protected javax.swing.JSpinner cycleCountField;
    protected javax.swing.JLabel cycleCountLabel;
    protected javax.swing.JButton endDateField;
    protected javax.swing.JLabel endDateLabel;
    protected javax.swing.JTextField endDateText;
    protected javax.swing.JLayeredPane jLayeredPane1;
    protected javax.swing.JComboBox<String> modeField;
    protected javax.swing.JLabel modeLabel;
    protected javax.swing.JLabel regionSlopeUnits1;
    protected usda.weru.weps.gui.ComboEditorField rockFragmentsField;
    protected javax.swing.JLabel rockFragmentsLabel;
    protected javax.swing.JLabel rockFragmentsUnitLabel;
    protected javax.swing.JLabel rockFragmentsUnits1;
    protected usda.weru.util.WepsTextField soilRockFragmentsValue;
    protected usda.weru.weps.gui.ComboEditorField soilSlopeField;
    protected javax.swing.JLabel soilSlopeLabel;
    protected javax.swing.JLabel soilSlopeLabel1;
    protected javax.swing.JLabel soilSlopeLabel2;
    protected javax.swing.JLabel soilSlopeUnitLabel;
    protected usda.weru.util.WepsTextField soilSlopeValue;
    protected javax.swing.JButton startDateField;
    protected javax.swing.JLabel startDateLabel;
    protected javax.swing.JTextField startDateText;
    //
    protected usda.weru.util.WepsTextField waterField;
    protected javax.swing.JLabel waterLabel;
    protected javax.swing.JLabel waterUnitLabel;
    private org.jdesktop.beansbinding.BindingGroup bindingGroup;
    // End of variables declaration//GEN-END:variables

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        String property = evt.getPropertyName();
        String value = evt.getNewValue() != null ? evt.getNewValue().toString() : null;
        switch (property) {
            case RunFileData.RunTypeDisp:
                updateMode(value);
                break;
            case ConfigData.Units:
                c_water.setDisplaySystem(value);
                c_soilSlopeValue.setDisplaySystem(value);
                c_soilRockFragmentsValue.setDisplaySystem(value);
                soilSlopeField.getConvertedValue().setDisplaySystem(value);
                rockFragmentsField.getConvertedValue().setDisplaySystem(value);
                break;
            case RunFileData.WaterErosionLoss:
                double d = Double.parseDouble(value);
                if (d < 0.0) {
                    LOGGER.warn("Invalid water erosion value: " + d);
                    d = 0.0;
                    //    waterField.setInputVerifier(new DoubleInputVerifier());
                }
                c_water.setValue(d);
                break;
            case RunFileData.CycleCount:
                setCycleCount(Integer.valueOf(value), false);
                break;
            case RunFileData.StartDate:
                setStartDate(parseDate(value), false);
                break;
            case RunFileData.EndDate:
                setEndDate(parseDate(value), false);
                break;
            case ConfigData.ReadonlySlope:
                if ("1".equals(value)) {
                    soilSlopeField.setReadonly(true);
                } else {
                    soilSlopeField.setReadonly(false);
                }
                break;
            case ConfigData.ReadonlyRockFragments:
                if ("1".equals(value)) {
                    rockFragmentsField.setReadonly(true);
                } else {
                    rockFragmentsField.setReadonly(false);
                }
                break;
            case RunFileData.AverageSlope:
                setSoilSlope(Double.valueOf(value), false);
                break;
            case RunFileData.SoilRockFragments:
                setRockFragments(Double.valueOf(value), false);
                break;
            case ConfigData.CompatibilityNRCS:
                if ("1".equals(value)) {
                    updateCompatibility(true);
                } else {
                    updateCompatibility(false);
                }
                break;
            case RunFileData.SoilFile:
                updateSoilValues(value);
                break;
        }
    }

    private String c_lastSoilPath;

    //TODO: move into properly threaded gui/data contexts
    private void updateSoilValues(String path) {
        if (path != null) {
            if (!path.equals(c_lastSoilPath)) {
                try {
                    IFC ifc = new IFC();
                    ifc.readIfc(path);
                    c_soilSlopeValue.setValue(ifc.surfaceSlope);
                    if (ifc.nsl > 0) {
                        c_soilRockFragmentsValue.setValue(ifc.fractionRock[0]);
                    } else {
                        //no layers
                        c_soilRockFragmentsValue.setValue(Double.NaN);
                    }

                } catch (FileNotFoundException ex) {
                    LOGGER.warn("Error reading soil file: " + path);
                    c_soilRockFragmentsValue.setValue(Double.NaN);
                    c_soilSlopeValue.setValue(Double.NaN);
                }
            }
            //else nothing changed
        } else {
            c_soilRockFragmentsValue.setValue(Double.NaN);
            c_soilSlopeValue.setValue(Double.NaN);
        }
    }

    private void updateCompatibility(boolean c) {
        if (c == c_nrcsInstall) {
            //no change
            return;
        }
        c_nrcsInstall = c;
        modeField.setEnabled(!c);
    }

    //methods for beans binding
    private int c_cycleCount;

    public int getCycleCount() {
        return c_cycleCount;
    }

    public void setCycleCount(int count) {
        setCycleCount(count, true);
    }

    public void setCycleCount(int count, boolean fireRFD) {
        int old = c_cycleCount;
        c_cycleCount = count;

        firePropertyChange("cycleCount", old, c_cycleCount);

        if (fireRFD) {
            firePropertyChange(RunFileData.CycleCount, Integer.toString(old), Integer.toString(c_cycleCount));
        }
    }

    private DateFormat dateFormat() {
        return new SimpleDateFormat("dd MM yyyy");
    }

    private Date parseDate(String value) {
        try {
            return dateFormat().parse(value);
        } catch (ParseException pe) {
            LOGGER.warn("Error parsing date: " + value);
            return null;
        }
    }

    private Date c_startDate;

    public Date getStartDate() {
        return c_startDate;
    }

    public void setStartDate(Date date, boolean pcflag) {
        setStartDate(date, pcflag, false);
    }

    public void setStartDate(Date date, boolean fireRFD, boolean check_message) {
        //System.out.println("[setStartDate] " + date);
        Date old = c_startDate;
        c_startDate = date;
        startDateText.setText(df.format(c_startDate));

        if (c_startDate != null && c_endDate != null) {
            checkStartDate(check_message);
        }

        firePropertyChange("startDate", old, c_startDate);

        if (fireRFD) {
            DateFormat format = dateFormat();
            firePropertyChange(RunFileData.StartDate, old != null ? format.format(old)
                    : null, c_startDate != null ? format.format(c_startDate) : null);
        }
    }

    /*
    *this method checks if the start date appears after end date
    *check_message is only true if the user selected the dates to be processed
    *the static functions accessing and setting datesUnordered is used 
        in setting a new run. if the condition is set a new run can not be 
        performed. 
     */
    public void checkStartDate(boolean check_message) {
        if (c_startDate.compareTo(c_endDate) == 1) {
            if (check_message) {
                //System.out.println("startDate appears after endDate");
                JOptionPane.showMessageDialog(null, "Start Date set past End Date."
                        + "\nPlease Adjust so Start Date is set before End Date.", "Start Date Entry Warning", JOptionPane.WARNING_MESSAGE);
                setDatesUnordered(true);
                //System.out.println(getDatesUnordered());
            }
        } else {
            setDatesUnordered(false);
            //System.out.println(getDatesUnordered());
        }
    }

    private Date c_endDate;

    public Date getEndDate() {
        return c_endDate;
    }

    public void setEndDate(Date date, boolean pcflag) {
        setEndDate(date, pcflag, false);
    }

    public void setEndDate(Date date, boolean fireRFD, boolean check_message) {
        //System.out.println("[setEndDate] " + date);
        Date old = c_endDate;
        c_endDate = date;
        endDateText.setText(df.format(c_endDate));

        if (c_endDate != null && c_startDate != null) {
            checkEndDate(check_message);
        }

        firePropertyChange("endDate", old, c_endDate);

        if (fireRFD) {
            DateFormat format = dateFormat();
            firePropertyChange(RunFileData.EndDate, old != null ? format.format(old)
                    : null, c_endDate != null ? format.format(c_endDate) : null);
        }
    }

    /*
    *this method checks if the end date appears before start date
    *check_message is only true if the user selected the dates to be processed
    *the static functions accessing and setting datesUnordered is used 
        in setting a new run. if the condition is set a new run can not be 
        performed. 
     */
    public void checkEndDate(boolean check_message) {
        if (c_endDate.compareTo(c_startDate) == -1) {
            //dates disjoint
            //set disjoint field 
            if (check_message) {
                //System.out.println("endDate appears before startDate");
                JOptionPane.showMessageDialog(null, "End Date set before Start Date."
                        + "\nPlease Adjust so End Date is set after Start Date.", "End Date Entry Warning", JOptionPane.WARNING_MESSAGE);
                setDatesUnordered(true);
                //System.out.println(getDatesUnordered());
            }
        } else {
            setDatesUnordered(false);
            //System.out.println(getDatesUnordered());
        }
    }

    private double c_soilSlope;

    public double getSoilSlope() {
        return c_soilSlope;
    }

    public void setSoilSlope(double slope) {
        setSoilSlope(slope, true);
    }

    public void setSoilSlope(double slope, boolean fireRFD) {
        double old = c_soilSlope;
        c_soilSlope = slope;

        regionSlopeUnits1.setVisible(c_soilSlope >= 0);
        firePropertyChange("soilSlope", old, c_soilSlope);
        if (fireRFD) {
            firePropertyChange(RunFileData.AverageSlope, Double.toString(old), Double.toString(c_soilSlope));
        }
    }

    private double c_rockFragments2;

    public double getRockFragments() {
        return c_rockFragments2;
    }

    public void setRockFragments(double slope) {
        setRockFragments(slope, true);
    }

    public void setRockFragments(double slope, boolean fireRFD) {
        double old = c_rockFragments2;
        c_rockFragments2 = slope;

        rockFragmentsUnits1.setVisible(c_rockFragments2 >= 0);

        firePropertyChange("rockFragments", old, c_rockFragments2);
        if (fireRFD) {
            String oldString = Double.toString(old).trim().startsWith("-1") ? "-1" : Double.toString(old);
            String newString = Double.toString(c_rockFragments2).trim().startsWith("-1") ? "-1" : Double.toString(c_rockFragments2);
            firePropertyChange(RunFileData.SoilRockFragments, oldString, newString);
        }
    }
    private boolean holdFire = false;

    private void updateMode(String type) {
        //holdFire = true;
        type = type != null ? type.trim().toLowerCase() : null;

        if (ConfigData.NRCS.toLowerCase().equals(type)) {
            this.setNRCS();
        } else if (ConfigData.Cycle.toLowerCase().equals(type)) {
            if (c_nrcsInstall) {
                rejectMode();
                return;
            }
            this.setCYCLE();
        } else if (ConfigData.Dates.toLowerCase().equals(type)) {
            if (c_nrcsInstall) {
                rejectMode();
                return;
            }
            this.setDATES();
        } else {
            LOGGER.warn("Unknown run mode: " + type);
        }
        holdFire = false;
    }

    //set fields visible when nrcs option is selected
    private void setNRCS() {
        modeField.setSelectedItem("NRCS");
        startDateField.setVisible(false);
        startDateLabel.setVisible(false);
        startDateText.setVisible(false);

        endDateField.setVisible(false);
        endDateLabel.setVisible(false);
        endDateText.setVisible(false);

        cycleCountField.setVisible(false);
        cycleCountLabel.setVisible(false);

        /*rockFragmentField.setVisible(true);
        rockFragmentsLabel.setVisible(true);
        rockFragmentsUnitLabel.setVisible(true);*/
        soilSlopeField.setVisible(true);
        soilSlopeLabel.setVisible(true);
        soilSlopeUnitLabel.setVisible(true);

        waterField.setVisible(true);
        waterLabel.setVisible(true);
        waterUnitLabel.setVisible(true);
    }

    //set fields visible when cycle is selected
    private void setCYCLE() {
        modeField.setSelectedItem("Cycle");
        startDateField.setVisible(false);
        startDateLabel.setVisible(false);
        startDateText.setVisible(false);

        endDateField.setVisible(false);
        endDateLabel.setVisible(false);
        endDateText.setVisible(false);

        cycleCountField.setVisible(true);
        cycleCountLabel.setVisible(true);

        /*rockFragmentField.setVisible(true);
        rockFragmentsLabel.setVisible(true);
        rockFragmentsUnitLabel.setVisible(true);*/
        soilSlopeField.setVisible(true);
        soilSlopeLabel.setVisible(true);
        soilSlopeUnitLabel.setVisible(true);

        waterField.setVisible(true);
        waterLabel.setVisible(true);
        waterUnitLabel.setVisible(true);
    }

    //set fields visible when date option is selected
    private void setDATES() {
        modeField.setSelectedItem("Dates");
        startDateField.setVisible(true);
        startDateLabel.setVisible(true);
        startDateText.setVisible(true);

        endDateField.setVisible(true);
        endDateLabel.setVisible(true);
        endDateText.setVisible(true);

        cycleCountField.setVisible(false);
        cycleCountLabel.setVisible(false);

        /*rockFragmentField.setVisible(true);
        rockFragmentsLabel.setVisible(true);
        rockFragmentsUnitLabel.setVisible(true);*/
        soilSlopeField.setVisible(true);
        soilSlopeLabel.setVisible(true);
        soilSlopeUnitLabel.setVisible(true);

        waterField.setVisible(true);
        waterLabel.setVisible(true);
        waterUnitLabel.setVisible(true);
    }

    private void rejectMode() {
        firePropertyChange(RunFileData.RunTypeDisp, null, ConfigData.NRCS);
        JOptionPane.showMessageDialog(this, "This run was configured with an alternative run mode unavailable "
                + "with an NRCS install.\nThe mode was changed to NRCS.", "Compatibility", JOptionPane.INFORMATION_MESSAGE);
    }

    private void addHelp() {
        CSH.setHelpIDString(this, "simrunPanel_html");
        CSH.setHelpIDString(startDateLabel, "simrunDates_html");
        CSH.setHelpIDString(startDateField, "simrunDates_html");
        CSH.setHelpIDString(endDateLabel, "simrunDates_html");
        CSH.setHelpIDString(endDateField, "simrunDates_html");
        CSH.setHelpIDString(cycleCountLabel, "simrunRotCyc_html");
        CSH.setHelpIDString(cycleCountField, "simrunRotCyc_html");
        CSH.setHelpIDString(modeLabel, "simrunModes_html");
        CSH.setHelpIDString(modeField, "simrunModes_html");
        CSH.setHelpIDString(waterLabel, "waterErosion_html");
        CSH.setHelpIDString(waterField, "waterErosion_html");
        CSH.setHelpIDString(soilSlopeLabel, "regionSlope_html");
        CSH.setHelpIDString(soilSlopeField, "regionSlope_html");
        CSH.setHelpIDString(soilSlopeLabel1, "regionSlope_html");
        CSH.setHelpIDString(soilSlopeValue, "regionSlope_html");
        CSH.setHelpIDString(rockFragmentsLabel, "rockFragments_html");
        CSH.setHelpIDString(rockFragmentsField, "rockFragments_html");
        CSH.setHelpIDString(soilSlopeLabel2, "rockFragments_html");
        CSH.setHelpIDString(soilRockFragmentsValue, "rockFragments_html");
    }

    private class simCalendarSelector {

        //date value associated with calendar
        Date dateSelected;
        //option for chaning start/end
        boolean selected;

        public Date getDate() {
            return dateSelected;
        }

        public void setDate(Date dObj) {
            dateSelected = dObj;
        }

        //option determine where start date or end date will be 
        //will be set by call to setnewcalendardate
        public simCalendarSelector(boolean option) {
            selected = option;
        }

        //display calander to allow user to select a date and
        //reset start/end date field
        public void calanderPopOut() {
            // Create a new calendar panel.
            JulianCalendar jd = null;
            Calendar calendar = Calendar.getInstance();
            if (selected) {
                calendar.setTime(c_endDate);
            } else {
                calendar.setTime(c_startDate);
            }
            int year = calendar.get(Calendar.YEAR);
            int month = calendar.get(Calendar.MONTH);
            int day = calendar.get(Calendar.DAY_OF_MONTH);
            jd = new JulianCalendar(year, month, day);
            //jd = new JulianCalendar();
            DisplayCalendar dc = new DisplayCalendar(Util.getParentJFrame(SimulationPanel.this), jd, "sim");
            dc.setVisible(true);

            if (dc.getResult() == DisplayCalendar.OK_OPTION && dc.curDate != null) {
                dateSelected = dc.curDate.getTime();
                if (selected) {
                    setEndDate(dateSelected, true, true);
                } else {
                    setStartDate(dateSelected, true, true);
                }
            }
        }
    }
}
