package usda.weru.erosion;

import java.awt.event.ItemEvent;
import java.awt.event.KeyEvent;
import java.beans.*;
import java.util.*;
import usda.weru.util.*;
import java.text.NumberFormat;

import com.klg.jclass.table.beans.*;
import com.klg.jclass.table.*;
import com.klg.jclass.table.data.JCEditableVectorDataSource;

class Weather extends usda.weru.erosion.gui.Weather_n implements PropertyChangeListener,
        com.klg.jclass.table.JCEditCellListener {
    private static final long serialVersionUID = 1L;

    private FormValidator fv = null;

    public void setFormValidator(FormValidator fv) {
        this.fv = fv;
    }
    private final String measurementUnits = Util.SIUnits;
//    private int curSubr = 0;
    public static void main(String[] args) {

        // test weibull

        double[] rtnArr = calcWeibullSpeeds(10.0, 3.0, 0.20, 96);
        for (int idx = 0; idx < rtnArr.length; idx++) {
            System.out.printf("%2d  %5.2f\n", idx + 1, rtnArr[idx]);
        }

//        Weather wea = new Weather();
//		wea.ds = new DataStore();
//		wea.addPropertyChangeListener(wea.ds);
//		wea.ds.addPropertyChangeListener(wea);
//        wea.setSize(640,480);
//		wea.setTitle("Daily Wind Erosion Model - Weather Test");
//        wea.setVisible(true);
//		wea.ds.readTextFile(new File("c:/weps.wrk/test/barrier_test.in"));
    }
    Hashtable<String,Object> HT_displayFields = new Hashtable<>();
    StringBuffer SB_calmFraction = new StringBuffer();
    StringBuffer SB_weibullC = new StringBuffer();
    StringBuffer SB_weibullK = new StringBuffer();

    Weather() {
        super();

        HT_displayFields.put(DataStore.WeaAirDen, JTF_airDensity);
        HT_displayFields.put(DataStore.WeaWindDir, JTF_windDirection);
        HT_displayFields.put(DataStore.WeaDailySteps, JCB_intervals);
        HT_displayFields.put(DataStore.WeaAnemHgt, JTF_anemometerHeight);
        HT_displayFields.put(DataStore.WeaAeroRough, JTF_aeroRoughness);

//        HT_displayFields.put(DataStore.WeaCalmWind, JTF_calmFraction);
//        HT_displayFields.put(DataStore.WeaWeibullC, JTF_weibullC);
//        HT_displayFields.put(DataStore.WeaWeibullK, JTF_weibullK);

        HT_displayFields.put(DataStore.WeaCalmWind, SB_calmFraction);
        HT_displayFields.put(DataStore.WeaWeibullC, SB_weibullC);
        HT_displayFields.put(DataStore.WeaWeibullK, SB_weibullK);

        makeWindJCTable();
        addJCTableListeners();
    }
    double dummyDouble;

    @Override
    protected void JRB_zoFieldItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_JRB_zoFieldItemStateChanged
        //changes.firePropertyChange(DataStore.PlotLAI, null, (evt.getStateChange() == evt.SELECTED) ? "1" : "0");
        changes.firePropertyChange(DataStore.WeaZoLocFlg, null, (evt.getStateChange() == ItemEvent.SELECTED) ? "1" : "0");
    }//GEN-LAST:event_JRB_zoFieldItemStateChanged

    @Override
    protected void JRB_zoStationItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_JRB_zoStationItemStateChanged
        changes.firePropertyChange(DataStore.WeaZoLocFlg, null, (evt.getStateChange() == ItemEvent.SELECTED) ? "0" : "1");
    }//GEN-LAST:event_JRB_zoStationItemStateChanged

    @Override
    protected void JTF_aeroRoughnessFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_JTF_aeroRoughnessFocusLost
//		if (evt.isTemporary()) return;
        String valStr = HT_prop.get(evt.getSource());
        try {
            dummyDouble = Double.parseDouble(valStr);
        } catch (NumberFormatException k) {
        }
        Util.checkNumericJTF(JP_weather, JTF_aeroRoughness, dummyDouble,
                DataStore.WeaAeroRough,
                changes, measurementUnits,4);
    }//GEN-LAST:event_JTF_aeroRoughnessFocusLost

    @Override
    protected void JTF_aeroRoughnessActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_JTF_aeroRoughnessActionPerformed
        String valStr = HT_prop.get(evt.getSource());
        try {
            dummyDouble = Double.parseDouble(valStr);
        } catch (NumberFormatException k) {
        }
        Util.checkNumericJTF(JP_weather, JTF_aeroRoughness, dummyDouble,
                DataStore.WeaAeroRough,
                changes, measurementUnits,4);
    }//GEN-LAST:event_JTF_aeroRoughnessActionPerformed

    @Override
    protected void JTF_anemometerHeightFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_JTF_anemometerHeightFocusLost
//		if (evt.isTemporary()) return;
        String valStr = HT_prop.get(evt.getSource());
        try {
            dummyDouble = Double.parseDouble(valStr);
        } catch (NumberFormatException k) {
        }
        Util.checkNumericJTF(JP_weather, JTF_anemometerHeight, dummyDouble,
                DataStore.WeaAnemHgt,
                changes, measurementUnits,4);
    }//GEN-LAST:event_JTF_anemometerHeightFocusLost

    @Override
    protected void JTF_anemometerHeightActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_JTF_anemometerHeightActionPerformed
        String valStr = HT_prop.get(evt.getSource());
        try {
            dummyDouble = Double.parseDouble(valStr);
        } catch (NumberFormatException k) {
        }
        Util.checkNumericJTF(JP_weather, JTF_anemometerHeight, dummyDouble,
                DataStore.WeaAnemHgt,
                changes, measurementUnits,4);
    }//GEN-LAST:event_JTF_anemometerHeightActionPerformed

    @Override
    protected void JTF_windDirectionFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_JTF_windDirectionFocusLost
//		if (evt.isTemporary()) return;
        String valStr = HT_prop.get(evt.getSource());
        try {
            dummyDouble = Double.parseDouble(valStr);
        } catch (NumberFormatException k) {
        }
        Util.checkNumericJTF(JP_weather, JTF_windDirection, dummyDouble,
                DataStore.WeaWindDir,
                changes, measurementUnits);
    }//GEN-LAST:event_JTF_windDirectionFocusLost

    @Override
    protected void JTF_windDirectionActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_JTF_windDirectionActionPerformed
        String valStr = HT_prop.get(evt.getSource());
        try {
            dummyDouble = Double.parseDouble(valStr);
        } catch (NumberFormatException k) {
        }
        Util.checkNumericJTF(JP_weather, JTF_windDirection, dummyDouble,
                DataStore.WeaWindDir,
                changes, measurementUnits);
    }//GEN-LAST:event_JTF_windDirectionActionPerformed

    @Override
    protected void JTF_airDensityFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_JTF_airDensityFocusLost
//		if (evt.isTemporary()) return;
        String valStr = HT_prop.get(evt.getSource());
        try {
            dummyDouble = Double.parseDouble(valStr);
        } catch (NumberFormatException k) {
        }
        Util.checkNumericJTF(JP_weather, JTF_airDensity, dummyDouble,
                DataStore.WeaAirDen,
                changes, measurementUnits,4);
    }//GEN-LAST:event_JTF_airDensityFocusLost

    @Override
    protected void JTF_airDensityActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_JTF_airDensityActionPerformed
        String valStr = HT_prop.get(evt.getSource());
        try {
            dummyDouble = Double.parseDouble(valStr);
        } catch (NumberFormatException k) {
        }
        Util.checkNumericJTF(JP_weather, JTF_airDensity, dummyDouble,
                DataStore.WeaAirDen,
                changes, measurementUnits,4);
    }//GEN-LAST:event_JTF_airDensityActionPerformed

    @Override
    protected void JB_estimateActionPerformed(java.awt.event.ActionEvent evt) {
        AirDensityEstimateDialog add = new AirDensityEstimateDialog(this, true);
        int result = add.showDialog();
        double temp = Double.parseDouble(JTF_airDensity.getText());
        if (result == AirDensityEstimateDialog.APPROVE_OPTION) {
            System.out.println("Result:"+add.calculateAverageAirDensity());
            JTF_airDensity.setText(Double.toString(add.calculateAverageAirDensity()));
            Util.checkNumericJTF(JP_weather, JTF_airDensity,temp, DataStore.WeaAirDen, changes, measurementUnits,4);
        }
        //use temp to replace add.calculateAverageAirDensity() by JG
        add.dispose();
    }

    @Override
    protected void JCB_intervalsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_JCB_intervalsActionPerformed
        windSpeeds = getWindSpeeds();
        makeWindJCTable();
        String numStepsStr = "" + stepArr[JCB_intervals.getSelectedIndex()];
        changes.firePropertyChange(DataStore.WeaDailySteps, null, numStepsStr);
    }//GEN-LAST:event_JCB_intervalsActionPerformed

    private final int[] stepArr = {24, 48, 72, 96, 144, 288};

    @Override
    protected void JB_calcWeibullWindSpeedsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_JB_calcWeibullWindSpeedsActionPerformed
        Weibull wdlg = new Weibull(this, SB_weibullC,
                SB_weibullK, SB_calmFraction, JCB_intervals.getSelectedIndex());
        wdlg.setFormValidator(fv);
        wdlg.setVisible(true);
        if (!wdlg.rtnFlg) {
            return;
        }
        windSpeeds = wdlg.windSpeeds;
//        System.out.println("wS: " + windSpeeds);
        makeWindJCTable();
        changes.firePropertyChange(DataStore.WeaCalmWind, null, SB_calmFraction.toString());
        changes.firePropertyChange(DataStore.WeaWeibullC, null, SB_weibullC.toString());
        changes.firePropertyChange(DataStore.WeaWeibullK, null, SB_weibullK.toString());
        changes.firePropertyChange(DataStore.WeaWindSpeeds, null, windSpeeds);
//        wdlg.dispose();

    }//GEN-LAST:event_JB_calcWeibullWindSpeedsActionPerformed
    private final String[][] columnLabels = {
        {"0-59\nminutes"},
        {"0-29", "30-59"},
        {"0-19", "20-39", "40-59"},
        {"0-14", "15-29", "30-44", "45-59"},
        {"0-9", "10-19", "20-29", "30-39", "40-49", "50-59"},
        {"0-4", "5-9", "10-14", "15-19", "20-24", "25-29", "30-34", "35-39",
            "40-44", "45-49", "50-54", "55-59"
        }
    };
    private final String[] rowLabels = {
        "0000-0100", "0100-0200", "0200-0300", "0300-0400", "0400-0500", "0500-0600",
        "0600-0700", "0700-0800", "0800-0900", "0900-1000", "1000-1100", "1100-1200",
        "1200-1300", "1300-1400", "1400-1500", "1500-1600", "1600-1700", "1700-1800",
        "1800-1900", "1900-2000", "2000-2100", "2100-2200", "2200-2300", "2300-0000"
    };
    String windSpeeds = "";

    private void makeWindJCTable() {

        int selIdx = this.JCB_intervals.getSelectedIndex();

        int cols = columnLabels[selIdx].length;
        int rows = rowLabels.length;

        String[][] cellArry = new String[rows][cols];

        String[] cellElms = windSpeeds.trim().split("\\s+");

        int numCells = cellElms.length;
        int sdx = 0;
        for (; sdx < stepArr.length; sdx++) {
            if (stepArr[sdx] == numCells) break;
        }
        
        if (sdx < stepArr.length) {
        int clx = 0;
            for (int rdx = 0; rdx < rows; rdx++) {
                for (int cdx = 0; cdx < cols; cdx++) {
                    clx = rdx * (sdx+1) + cdx;
                    cellArry[rdx][cdx] = (cdx <= sdx) ? cellElms[clx] : cellArry[rdx][cdx-1];
                }
            }
        } else {
            for (int rdx = 0; rdx < rows; rdx++) {
                for (int cdx = 0; cdx < cols; cdx++) {
                    cellArry[rdx][cdx] = "0.0";
                }
            }
        }

        DataWrapper dw =
                new com.klg.jclass.table.beans.DataWrapper(rows, cols, rowLabels,
                columnLabels[selIdx], cellArry);
        this.jcTable.setMaxWidth(JCTableEnum.ALLCELLS, 70);
        this.jcTable.setData(dw);
        this.jcTable.setSelectionPolicy(JCTableEnum.SELECT_RANGE);

        JCCellStyle cs = new JCCellStyle();
        cs.setHorizontalAlignment(JCTableEnum.RIGHT);
        cs.setEditable(true);
        java.awt.Color col = new java.awt.Color(1.0f, 1.0f, 1.0f);
        cs.setBackground(col);
        JCCellRange cr = new JCCellRange(0, 0, rows - 1, cols - 1);
        this.jcTable.setCellStyle(cr, cs);

        JCCellStyle csc = new JCCellStyle();
        csc.setHorizontalAlignment(JCTableEnum.RIGHT);
        csc.setEditable(false);
        java.awt.Color colc = new java.awt.Color(0.0f, 1.0f, 1.0f);
        csc.setBackground(colc);
        JCCellRange crc = new JCCellRange(JCTableEnum.LABEL, 0, JCTableEnum.LABEL, cols - 1);
        this.jcTable.setCellStyle(crc, csc);
        this.jcTable.removeEditCellListener(this);
        this.jcTable.addEditCellListener(this);
//         // set up listener for data changes
//        JCEditableVectorDataSource edvds =
//                (JCEditableVectorDataSource) jcTable.getDataSource();
//        edvds.addTableDataListener(new JCTableDataListener() {
//
//            public void dataChanged(JCTableDataEvent evt) {
//                System.out.println("W: table data changed xxxx " + evt.getSource());
////                changes.firePropertyChange(DataStore.WeaWindSpeeds, null, getWindSpeeds());
////                oldWindSpeeds = getWindSpeeds();
//            }
//        });
    //        jcTable.setAutoEdit(true);

    }

    private int isCopyOrPaste() {
        StackTraceElement[] stea = Thread.currentThread().getStackTrace();
        for (int idx = 1; idx < 10; idx++) {
            if (stea[idx].getMethodName().endsWith("isCopyAction")) {
                return JCTableEnum.COPY_ACTION;
            }
            if (stea[idx].getMethodName().endsWith("isPasteAction")) {
                return JCTableEnum.PASTE_ACTION;
//            System.out.println("method dump " + stea[idx].getMethodName());
            }
        }
        return 0;
    }

    private void addJCTableListeners() {
        // set up copy to another program
        this.jcTable.addAction(new KeyActionInitiator(KeyEvent.VK_C, java.awt.event.InputEvent.CTRL_DOWN_MASK) {
            private static final long serialVersionUID = 1L;

            @Override
            public boolean isMatch(java.awt.AWTEvent evt) {
                try {
                    if (isCopyOrPaste() != com.klg.jclass.table.JCTableEnum.COPY_ACTION) {
                        return false;
                    }
                    java.awt.event.KeyEvent kevt = (java.awt.event.KeyEvent) evt;
                    if ((kevt.getKeyCode() == KeyEvent.VK_C) &&
                            ((kevt.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) > 0)) {
                        kevt.consume();
                        return true;
                    } else {
                        return false;
                    }
                } catch (java.lang.ClassCastException cce) {
                    return false;
                }
            }
        },
                JCTableEnum.COPY_ACTION);


        // set up paste from another program
        this.jcTable.addAction(new KeyActionInitiator(KeyEvent.VK_V, java.awt.event.InputEvent.CTRL_DOWN_MASK) {
            private static final long serialVersionUID = 1L;

            @Override
            public boolean isMatch(java.awt.AWTEvent evt) {
                try {
                    if (isCopyOrPaste() != com.klg.jclass.table.JCTableEnum.PASTE_ACTION) {
                        return false;
                    }
                    java.awt.event.KeyEvent kevt = (java.awt.event.KeyEvent) evt;
//                    System.out.println("class " + evt.getClass() + " " + kevt.getKeyCode() + " " + kevt.getModifiers());
                    if ((kevt.getKeyCode() == KeyEvent.VK_V) &&
                            ((kevt.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) > 0)) {
                        clearCellsBeforePaste();
                        javax.swing.SwingUtilities.invokeLater(new FixCellArry(jcTable));
                        return true;
                    } else {
                        return false;
                    }
                } catch (java.lang.ClassCastException cce) {
                    return false;
                }
            }
        },
                JCTableEnum.PASTE_ACTION);

//        // set up listener for data changes
//        JCEditableVectorDataSource edvds =
//                (JCEditableVectorDataSource) jcTable.getDataSource();
//        edvds.addTableDataListener(new JCTableDataListener() {
//
//            public void dataChanged(JCTableDataEvent evt) {
//                System.out.println("W: table data changed " + evt);
////                changes.firePropertyChange(DataStore.WeaWindSpeeds, null, getWindSpeeds());
//            }
//        });
//
    }

    private void clearCellsBeforePaste() {
        JCEditableVectorDataSource edvds = (JCEditableVectorDataSource) jcTable.getDataSource();
        // getSelectedCells will always return a Collection of JCCellRanges,
        // even if the method signature won't admit it
        Collection<com.klg.jclass.table.JCCellRange> jcclc =
                Caster.<Collection<com.klg.jclass.table.JCCellRange>>cast(jcTable.getSelectedCells());

        if (jcclc.size() != 1) {
            System.out.println("return -- no range selected");
            return;
        }
        com.klg.jclass.table.JCCellRange jccl = jcclc.iterator().next();

//        System.out.println("W_cCBP: clear " + jccl.start_column + " " + jccl.end_column + " " +
//                jccl.start_row + " " + jccl.end_row);

        int numSelRows = Math.abs(jccl.start_row - jccl.end_row) + 1;
        int numSelCols = Math.abs(jccl.start_column - jccl.end_column) + 1;

        int begRow = (jccl.start_row < jccl.end_row) ? jccl.start_row : jccl.end_row;
        int begCol = (jccl.start_column < jccl.end_column) ? jccl.start_column : jccl.end_column;

        for (int rdx = begRow; rdx < begRow + numSelRows; rdx++) {
            for (int cdx = begCol; cdx < begCol + numSelCols; cdx++) {
                edvds.setTableDataItem("", rdx, cdx);
            }
        }
    }

    private String getWindSpeeds() {

        JCEditableVectorDataSource edvds = (JCEditableVectorDataSource) jcTable.getDataSource();

        StringBuffer sb = new StringBuffer("");

        for (int rdx = 0; rdx < edvds.getNumRows(); rdx++) {
            for (int cdx = 0; cdx < edvds.getNumColumns(); cdx++) {
                String cell = edvds.getTableDataItem(rdx, cdx).toString().trim();
                if (cell.length() == 0) {
                    cell = "0.0";
                }
                sb.append(cell + " ");
            }
        }

        return sb.toString();
    }
//    private String oldWindSpeeds = null;
    public void commitEdits() {
        windSpeeds = getWindSpeeds();
        changes.firePropertyChange(DataStore.WeaWindSpeeds, null, windSpeeds);
    }

    private void setWindSpeeds(String selStr) {

        String[] inpElms = selStr.split("\\s+");

        int numIntv = inpElms.length;       // calc type of intervals (hour, 30 min, etc.)
        int selIdx = 0;
        for (selIdx = 0; selIdx < stepArr.length; selIdx++) {
            if (numIntv == stepArr[selIdx]) {
                break;
            }
        }
        if (selIdx == stepArr.length) {     // not standard number of intervals
            JCB_intervals.setSelectedIndex(0);
            inpElms = new String[24];
            for (int idx = 0; idx < inpElms.length; idx++) {
                inpElms[idx] = "0.0";
            }
//            return;
        } else {
            JCB_intervals.setSelectedIndex(selIdx);
        }

        // load windspeeds into table
        JCEditableVectorDataSource edvds = (JCEditableVectorDataSource) jcTable.getDataSource();

        int idx = 0;
        for (int rdx = 0; rdx < edvds.getNumRows(); rdx++) {
            for (int cdx = 0; cdx < edvds.getNumColumns(); cdx++) {
                edvds.setTableDataItem(inpElms[idx++], rdx, cdx);
            }
        }

    }

    class FixCellArry implements Runnable {

        LiveTable jcTable;

        FixCellArry(LiveTable jcTable) {
            this.jcTable = jcTable;
        }

        @Override
        public void run() {
//            System.out.println("invoked later");
            fixCellArry();
        }

        /*
         * After a paste, there may be multiple tokens in a cell;
         */
        private void fixCellArry() {

//            System.out.println("fixCellArry:");

            JCEditableVectorDataSource edvds =
                    (com.klg.jclass.table.data.JCEditableVectorDataSource) jcTable.getDataSource();

            jcTable.cancelEdit(true);
            // getSelectedCells will always return a Collection of JCCellRanges,
            // even if the method signature won't admit it
            Collection<com.klg.jclass.table.JCCellRange> jcclc =
                    Caster.<Collection<com.klg.jclass.table.JCCellRange>>cast(jcTable.getSelectedCells());

            if (jcclc.size() != 1) {
                System.out.println("W_fCA: return -- no range selected");
                return;
            }
            com.klg.jclass.table.JCCellRange jccl = jcclc.iterator().next();

//            System.out.println("W_fCA: range " + jccl.start_column + " " + jccl.end_column + " " +
//                    jccl.start_row + " " + jccl.end_row);
//
            int numSelRows = Math.abs(jccl.start_row - jccl.end_row) + 1;
            int numSelCols = Math.abs(jccl.start_column - jccl.end_column) + 1;

            int begRow = (jccl.start_row < jccl.end_row) ? jccl.start_row : jccl.end_row;
            int begCol = (jccl.start_column < jccl.end_column) ? jccl.start_column : jccl.end_column;

            boolean rtnFlg = true;
            for (int rdx = begRow; rdx < begRow + numSelRows; rdx++) {
                for (int cdx = begCol; cdx < begCol + numSelCols; cdx++) {
                    if (((String) edvds.getTableDataItem(rdx, cdx)).trim().contains(" ")) {
                        rtnFlg = false;
                        break;
                    }
                }
            }
            if (rtnFlg) {
                return;      // no cell contains two+ tokens
            }
            StringBuffer sb = new StringBuffer("");

            for (int rdx = begRow; rdx < begRow + numSelRows; rdx++) {
                for (int cdx = begCol; cdx < begCol + numSelCols; cdx++) {
                    sb.append(edvds.getTableDataItem(rdx, cdx) + " ");
                }
            }

//            System.out.println("sb " + sb.toString());

//            String[] inpElms = sb.toString().split("\\s+");

            String[] inpElms = getWindSpeeds().split("\\s+");


            if (inpElms.length == 8) {           // 8 elms in (0,0) may be 3 hour data
                int res = javax.swing.JOptionPane.showConfirmDialog(null,
                        "Is this 3 hour interval data?",
                        "Select an option",
                        javax.swing.JOptionPane.YES_NO_OPTION);
                if (res == javax.swing.JOptionPane.YES_OPTION) {
                    int rdx = 0;
                    for (int idx = 0; idx < 8; idx++) {
                        for (int jdx = 0; jdx < 3; jdx++, rdx++) {
                            edvds.setCell(rdx, 0, inpElms[idx]);
//                            System.out.println("W_fCA: " + rdx + " " + inpElms[idx]);
                        }
                    }
                    return;
                }
            }

            int idx = 0;

            if (inpElms.length != numSelRows * numSelCols) {
                javax.swing.JOptionPane.showMessageDialog(null,
                        "Number of tokens copied does not equal size of selection.\n(Some data may be missing)",
                        "Warning",
                        javax.swing.JOptionPane.WARNING_MESSAGE);
            }
            for (int rdx = begRow; rdx < begRow + numSelRows; rdx++) {
                for (int cdx = begCol; cdx < begCol + numSelCols; cdx++) {
                    edvds.setTableDataItem(inpElms[idx++], rdx, cdx);
//                   System.out.println("W_fCA: " + rdx + " " + cdx + " " + inpElms[idx-1]);
                    if (idx > inpElms.length) {
                        edvds.setTableDataItem("0.0", rdx, cdx);
                    }
                }
            }

        }
    }
    /****** Property change support methods *****/
    /**
     * RunFileData throws a property change each time setData is called.
     * Wrapper classes listen to determine if the the event is relevant to
     * them.
     */
    private final PropertyChangeSupport changes = new PropertyChangeSupport(this);

    /**
     * Allows the container to add or register some other components to recognize the changes that occur
     * on this component.
     * @param l The listener that listens and reacts towards the the changes to be reflected.
     */
    @Override
    public void addPropertyChangeListener(PropertyChangeListener l) {
        changes.addPropertyChangeListener(l);
    }

    /**
     * Allows the container to remove or de-register some other components and stop recognizing the
     * changes that occur on this component.
     * @param l The listener that does not listen and react towards the the changes to be reflected.
     */
    @Override
    public void removePropertyChangeListener(PropertyChangeListener l) {
        changes.removePropertyChangeListener(l);
    }
    /**
     * Recognizes and takes appropriate actions on registered properties from different
     * screens to update and synchronize data and GUI screens as needed.
     * @param e The event itself that is responsible for triggering the change required for registered
     * properties/components.
     */
    Hashtable<javax.swing.JTextField,String> HT_prop = new Hashtable<>();

    @Override
    public void propertyChange(PropertyChangeEvent e) {

        String property = e.getPropertyName();
        if (property.equals(DataStore.WeaZoLocFlg)) {
            setZoLocFlg((String) e.getNewValue());
        } else if (property.equals(DataStore.WeaWindSpeeds)) {
            setWindSpeeds((String) e.getNewValue());
        } else if (property.equals(DataStore.Commit)) {
            commitEdits();
        } else {
            if (property.indexOf("+") > 0) {
                property = property.substring(0, property.indexOf("+"));
            }
            String value = "";
            try {
                value = (String) e.getNewValue();
            } catch (ClassCastException cce) {
                // not our kind of thing
                return;
            }
            Object obj = HT_displayFields.get(property);
            if (obj != null) {
                if (obj instanceof javax.swing.JTextField) {
                    javax.swing.JTextField jtf = (javax.swing.JTextField) obj;
                    double val = 0.0;
                    HT_prop.put(jtf, value);
                    try {
                        val = Double.parseDouble(value);
                        NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
                        nf.setMaximumFractionDigits(5);
                        nf.setMinimumFractionDigits(0);
                        nf.setGroupingUsed(false);
                        value = nf.format(val);
                    } catch (NumberFormatException f) {
                    }
                    jtf.setText(value.trim());
                } else if (obj instanceof javax.swing.JCheckBox) {
                    javax.swing.JCheckBox jcb = (javax.swing.JCheckBox) obj;
                    jcb.setSelected(value.trim().equals("1"));
                } else if (obj instanceof StringBuffer) {
                    StringBuffer sb = (StringBuffer) obj;
                    sb.setLength(0);
                    sb.append(value);
                }
            }
        }
    }

    /***** specific property change handles ********/
    private void setZoLocFlg(String selStr) {
        selStr = selStr.trim();
        if (selStr.equals("1")) {
            JRB_zoField.setSelected(true);
            JRB_zoStation.setSelected(false);
        } else {
            JRB_zoField.setSelected(false);
            JRB_zoStation.setSelected(true);
        }
    }

    /**
     * calculate wind speed distribution given Weibull parameters
     */
    private static double[] calcWeibullSpeeds(double weiC, double weiK, double weiCalm, int nSteps) {

        double step = nSteps;

        double[] f = new double[nSteps];
        double[] tmpArr = new double[nSteps];
        for (int idx = 0; idx < nSteps; idx++) {
            f[idx] = (1.0 / (2.0 * step)) + idx / step + 0.3 / (step * weiK);
            if (f[idx] < weiCalm) {
                f[idx] = weiCalm;
            }
            tmpArr[idx] = (-Math.log((1.0 - f[idx]) / (1.0 - weiCalm)));
            tmpArr[idx] = weiC * Math.pow(tmpArr[idx], 1.0 / weiK);
        }

        double[] rtnArr = new double[nSteps];

        int jdx = 0;
        for (int idx = 0; idx < nSteps / 2; idx++, jdx += 2) {
            rtnArr[idx] = tmpArr[jdx];
        }
        jdx = nSteps - 1;
        for (int idx = nSteps / 2; idx < nSteps; idx++, jdx -= 2) {
            rtnArr[idx] = tmpArr[jdx];
        }
        return rtnArr;
    }

    @Override
    public void beforeEditCell(JCEditCellEvent arg0) {
//          throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void editCell(JCEditCellEvent arg0) {
        com.klg.jclass.cell.editors.BaseCellEditor bce = 
                (com.klg.jclass.cell.editors.BaseCellEditor) arg0.getEditingComponent();
        bce.setSelectionStart(0);
        bce.setSelectionEnd(100);   // abitrarily big number; selectAllText doesn't work
//        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void afterEditCell(JCEditCellEvent arg0) {
        commitEdits();
        changes.firePropertyChange(DataStore.DataChanged, "", "0");
//        throw new UnsupportedOperationException("Not supported yet.");
    }
}
	
	