/*
 * WindGenStationDisplay.java
 *
 * Created on July 25, 2006, 11:52 AM
 */
package usda.weru.util;

import com.klg.jclass.table.TableDataModel;
import com.klg.jclass.table.data.AbstractDataSource;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import de.schlichtherle.truezip.file.TFile;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.nio.channels.FileChannel;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.StringTokenizer;
import systems.uom.common.USCustomary;
import javax.swing.JOptionPane;
import javax.swing.ProgressMonitor;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; 
import org.openide.util.Exceptions;
import usda.weru.util.gui.WindGenStationDisplay_n;
import usda.weru.util.table.WepsTableMeta;
import usda.weru.weps.location.InterpolatedStation;
import usda.weru.weps.location.Station;
import usda.weru.weps.location.WindgenStation;
import usda.weru.weps.wepsRunControl.WrcBackgroundIf;
import usda.weru.weps.wepsRunControl.WrcException;
import usda.weru.weps.wepsRunControl.WrcRunModelWindInterpolate;
import usda.weru.weps.wepsRunControl.WrcRunModelWindInterpolateGetStations.latlonFlag;

/**
 *
 * @author lrdinuki
 */
public final class WindGenStationDisplay extends WindGenStationDisplay_n implements PropertyChangeListener, WrcBackgroundIf {

    private static final long serialVersionUID = 1L;

    private static final Logger logger = LogManager.getLogger(WindGenStationDisplay.class);

    private static final int WIND_SPEED = 0;
    private static final int WIND_ENERGY = 1;
    private static final int WIND_FRACT = 2;
    private static final int WIND_PREPOND = 3;
    private static final int WIND_DIRECTION = 4;
    private WindGenData dataSource;
    private double[][][] cumProb = null;
    private double[][][] intvProb = null;
    private double[][] windTimes = null;

    protected String[][] cellData = new String[5][12];
    double elevationValue = 1000.0; // default elevation in meters
    double temperature = 20.0; // default temperature Celsius
    double stepSize = 0.1; // width of integrating box
    private double threshold = 8.0;
    private static final int numMonths = 12;
    private static final int numDirections = 16;
    private final double[] boundaries = {1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5,
        9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5,
        18.5, 19.5, 20.5, 25.5, 30.5, 35.5, 40.5, 45.5};
    private final String[] dirNames = {"N-0", "NNE-22", "NE-45", "ENE-67", "E-90", "ESE-112", "SE-135", "SSE-157",
        "S-180", "SSW-202", "SW-225", "WSW-247", "W-270", "WNW-292", "NW-315", "NNW-337"};

    private ProgressMonitor progress;
    public final String progressSetProgressProperty = "WindGenStationDisplaySetProgress";
    public final String progressInitProperty = "WindGenStationDisplayInitProgress";
    public final String progressCloseProperty = "WindGenStationDisplayCloseProgress";
    public final String setEnableProperty = "WindGenStationDisplayEnable";
    
    private ArrayList<String> intpData = null;

    public WindGenStationDisplay(final String filename, final Station station) {
        setTitle("Wind Station Data");
        JCB_station.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                String s = (String) JCB_station.getSelectedItem();
                if (s.equals(dataSource.currentStation)) {
                    return;
                }
                getStationData(s);
            }
        });

        JTF_threshold.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                String valStr = JTF_threshold.getText();
                double thres = Double.parseDouble(valStr);
                if (thres < 2 || thres > boundaries[boundaries.length - 1]) {
                    javax.swing.JOptionPane.showMessageDialog(null,
                            "Number specified is out of range\n"
                            + "must be between 2 & " + boundaries[boundaries.length - 1],
                            "Number out of range",
                            javax.swing.JOptionPane.ERROR_MESSAGE);
                    NumberFormat cf = NumberFormat.getNumberInstance(Locale.US);
                    cf.setMaximumFractionDigits(0);
                    cf.setMinimumFractionDigits(0);
                    JTF_threshold.setText(cf.format(threshold));
                    return;
                }
                threshold = thres;
                getStationData((String) JCB_station.getSelectedItem());
            }
        });
        
        WindGenStationDisplay wgsd = this;
        
        setEnabled(false);
        setVisible(true);
        
        SwingWorker<Object, Integer> workTask = new SwingWorker<Object, Integer> () {
            @Override
            public Object doInBackground () {
                
                addPropertyChangeListener(wgsd);
                
                loadMeta();
                loadData(filename);
                // enable for the current selection to let the new data just loaded
                // be popultaed in the WindGenStationDisplay.
                SwingWorker:
                firePropertyChange(setEnableProperty, null, JCB_station.getSelectedItem());
                
                if (station instanceof WindgenStation) {
                    WindgenStation windgenStation = (WindgenStation) station;
                    getStationData(String.valueOf(windgenStation.getWBan()));
                } else if (station instanceof InterpolatedStation) {
                    makeInterpolatedStation((InterpolatedStation) station, this.getPropertyChangeSupport());
                    addStation(station.getDisplayName());
                    dataSource.currentStation = null;
                }
                
                // now enable again with the specified station.
                SwingWorker:
                firePropertyChange(setEnableProperty, null, station.getDisplayName());
                return null;
            }
            @Override
            public void done () {
            }
        };
        workTask.execute();
    }

    
//    private void makeInterpolatedStationOriginal(InterpolatedStation station) {
//        ProgressMonitor progress = new ProgressMonitor(this, "Interpolating", "Please wait...", 0, 10);
//        progress.setMillisToDecideToPopup(100);
//        progress.setMillisToPopup(200);
//
//        BufferedReader br = null;
//        try {
//            ConfigData cd = ConfigData.getDefault();
//            MakeInterpolatedStation mis = new MakeInterpolatedStation(null);
//            mis.setParameter(MakeInterpolatedStation.INTERPOLATE1_EXE, cd.getDataParsed(ConfigData.WindInterp1EXE));
//            mis.setParameter(MakeInterpolatedStation.INTERPOLATE2_EXE, cd.getDataParsed(ConfigData.WindInterp2EXE));
//            mis.setParameter(MakeInterpolatedStation.WINDGEN_EXE, null);
//
//            mis.setParameter(MakeInterpolatedStation.LAT, String.valueOf(station.getLatLong().latitudeValue(USCustomary.DEGREE_ANGLE)));
//            mis.setParameter(MakeInterpolatedStation.LON, String.valueOf(station.getLatLong().longitudeValue(USCustomary.DEGREE_ANGLE)));
//            mis.setParameter(MakeInterpolatedStation.IDX_FILE, cd.getDataParsed(ConfigData.WinIndex));
//            mis.setParameter(MakeInterpolatedStation.SIM_START, "0");
//            mis.setParameter(MakeInterpolatedStation.SIM_LENGTH, "0");
//
//            String polFile = ConfigData.getDefault().getDataParsed(ConfigData.WindgenInterpolationBoundaryFile);
//            TFile pol = polFile != null && !polFile.isEmpty() ? new TFile(polFile) : null;
//            if (pol == null || !pol.exists()) {
//                logger.error("Unable to find windgen projection file.");
//                return;
//            }
//            polFile = pol.getAbsolutePath();
//
//            mis.setParameter(MakeInterpolatedStation.POL_FILE, polFile);
//            mis.setParameter(MakeInterpolatedStation.WDB, cd.getDataParsed(ConfigData.WinData));
//
//            //don't want mis to automagically cleanup
//            mis.setCleanUp(false);
//            progress.setProgress(2);
//            mis.run();
//
//            if (mis.getOutputFile() != null) {
//                //queue it up to be deleted when weps closes
//                mis.getOutputFile().getParentFile().deleteOnExit();
//            }
//            intpData = new Vector<String>();
//            br = new BufferedReader(new TFileReader(mis.getOutputFile()));
//            br.readLine();
//            while (true) {
//                String inpLin = br.readLine();
//                if (inpLin == null) {
//                    break;
//                }
//                intpData.add(inpLin);
//            }
//        } catch (IOException ex) {
//            java.util.logging.LogManager.getLogger(WindGenStationDisplay.class.getName()).log(Level.SEVERE, null, ex);
//        } finally {
//            if (br != null) {
//                try {
//                    br.close();
//                } catch (Exception ex) {
//                    java.util.logging.LogManager.getLogger(WindGenStationDisplay.class.getName()).log(Level.SEVERE, null, ex);
//                }
//            }
//            progress.close();
//
//        }
//    }

    private void makeInterpolatedStation(InterpolatedStation station, PropertyChangeSupport pcs) {
        Logger LOGGER = LogManager.getLogger(this.getClass());

        BufferedReader br = null;

        pcs.firePropertyChange(progressInitProperty, null, true);
        pcs.firePropertyChange(progressSetProgressProperty, null, 10);
        
        try {
            ConfigData cd = ConfigData.getDefault();

            WrcRunModelWindInterpolate interpModel = new WrcRunModelWindInterpolate (
                    About.getWepsHome().getAbsolutePath() + TFile.separator + "tmp",
                    LOGGER,
                    this
            );

            interpModel.addCmds_latlon(String.valueOf(station.getLatLong().latitudeValue(USCustomary.DEGREE_ANGLE)),latlonFlag.lat);
            interpModel.addCmds_latlon(String.valueOf(station.getLatLong().longitudeValue(USCustomary.DEGREE_ANGLE)),latlonFlag.lon);
            interpModel.addCmds_idxFile(cd.getDataParsed(ConfigData.WinIndex));

            String polFile = ConfigData.getDefault().getDataParsed(ConfigData.WindgenInterpolationBoundaryFile);
            TFile pol = polFile != null && !polFile.isEmpty() ? new TFile(polFile) : null;
            if (pol == null || !pol.exists()) {
                logger.error("Unable to find windgen projection file.");
                return;
            }
            polFile = pol.getAbsolutePath();
            interpModel.addCmds_polFile(polFile);

            pcs.firePropertyChange(progressSetProgressProperty, null, 20);

            interpModel.setLocalOutputWriters();
            interpModel.execModel();
            pcs.firePropertyChange(progressSetProgressProperty, null, 30);
            pcs.firePropertyChange(progressSetProgressProperty, null, 70);

            if (interpModel.getInterpDirName() != null) {
                //queue it up to be deleted when weps closes
                new File(interpModel.getInterpDirName()).deleteOnExit();
            }
            intpData = new ArrayList<String>();
            br = new BufferedReader(new FileReader(new File(interpModel.getInterpDirName(),interpModel.getWdbFileName())));
            br.readLine();
            boolean rdFlag = true;
            while (rdFlag) {
                String inpLin = br.readLine();
                if (inpLin == null) {
                    rdFlag = false;
                }
                intpData.add(inpLin);
            }
            pcs.firePropertyChange(progressSetProgressProperty, null, 80);
        } catch (IOException ex) {
            //java.util.logging.LogManager.getLogger(WindGenStationDisplay.class.getName()).log(Level.SEVERE, null, ex);
            logger.error(ex);
        } catch (WrcException ex) {
            Exceptions.printStackTrace(ex);
        } catch (Exception ex) {
            Exceptions.printStackTrace(ex);
        }
        
        if (br != null) {
            try {
                br.close();
            } catch (Exception ex) {
            }
        }
        pcs.firePropertyChange(progressCloseProperty, null, true);
    }
    

    private void loadData(String filename) {
        dataSource = new WindGenData(this);
        if (dataSource.load(this, new TFile(filename))) {
            WT_windGenTable.setDataSource(dataSource);
        }

    }

    public WindGenStationDisplay(String filename) {
        this(filename, null);
    }

    private void loadMeta() {
        TFile file = new TFile("tables/windgendisp.xml");
        WepsTableMeta meta = new WepsTableMeta();
        meta.fromFile(file);
        WT_windGenTable.setMeta(meta);
    }

    private void parseElevation(ArrayList<String> selVec) {
        String inpLin = selVec.get(0); //elevation in first line
        StringTokenizer st = new StringTokenizer(inpLin);
        for (int edx = 0; st.hasMoreTokens() && edx < 6; edx++) {
            st.nextToken();
        }
        String elevStr = st.nextToken();
        JL_elevation.setText(elevStr);
        elevationValue = Double.parseDouble(elevStr);
    }

    private void parseWindTimes(ArrayList<String> selVec) {
        windTimes = new double[numDirections][];
        for (int ddx = 0; ddx < numDirections; ddx++) {
            String[] inpArr = new String[numMonths];
            windTimes[ddx] = new double[numMonths];
            String inpLin = selVec.get(ddx + 1); //skip the first line, use next 16
            StringTokenizer st = new StringTokenizer(inpLin);
            for (int mdx = 0; st.hasMoreTokens(); mdx++) {
                inpArr[mdx] = st.nextToken();
                if (ddx == 0) {
                    cellData[ddx][mdx] = inpArr[mdx];
                }
                windTimes[ddx][mdx] = Double.parseDouble(inpArr[mdx]);
            }
        }
    }

    public static String parseWinCmd(String inpStr) {
        StringTokenizer st = new StringTokenizer(inpStr);
        String fileToken = null;
        while (st.hasMoreTokens()) {
            fileToken = st.nextToken();
            if (fileToken.startsWith("-f") || fileToken.startsWith("-F")) {
                break;
            }
            fileToken = "";
        }
        if (fileToken.length() == 0) {
            return "./db/wind_gen/wind_test.wdb";
        }
//		if (fileToken.length() == 0) return "C:/weps/weps1.install/db/wind_gen/wind_gen_his.wdb";

        if (fileToken.length() > 2) {
            return fileToken.substring(2);
        }

        if (st.hasMoreTokens()) {
            return st.nextToken();
        }

        return "./db/wind_gen/wind_gen_his.wdb";

    }

    private void parseWindSpeeds(ArrayList<String> selVec) {
        cumProb = new double[numMonths][][];
        intvProb = new double[numMonths][][];
        for (int mdx = 0; mdx < numMonths; mdx++) {
            cumProb[mdx] = new double[numDirections][];
            intvProb[mdx] = new double[numDirections][];
            for (int ddx = 0; ddx < numDirections; ddx++) {

                // load cumulative probability curve for each direction
                String inpLin = selVec.get(mdx * numDirections + ddx + 18); //skip the direction data, use next 16*12
                StringTokenizer st = new StringTokenizer(inpLin);
                int numTok = st.countTokens();
                String[] inpArr = new String[numTok];
                cumProb[mdx][ddx] = new double[numTok + 2];
                intvProb[mdx][ddx] = new double[numTok + 2];
                for (int pdx = 0; st.hasMoreTokens(); pdx++) {
                    inpArr[pdx] = st.nextToken();
                    if (mdx == 0 && ddx == 0 && pdx < cellData[1].length) {
                        cellData[1][pdx] = inpArr[pdx];
                    }
                    cumProb[mdx][ddx][pdx] = Double.parseDouble(inpArr[pdx]);
                }
                cumProb[mdx][ddx][numTok] = 1.0; // put 1 in last 2 positions
                cumProb[mdx][ddx][numTok + 1] = 1.0;

                // convert cumulative curve to interval values
                intvProb[mdx][ddx] = new double[numTok + 2];
                for (int pdx = 1; pdx < cumProb[mdx][ddx].length; pdx++) {
                    try {
                        double deltaY = cumProb[mdx][ddx][pdx] - cumProb[mdx][ddx][pdx - 1];
                        double deltaX = boundaries[pdx] - boundaries[pdx - 1];
                        intvProb[mdx][ddx][pdx] = deltaY / deltaX;
                    } catch (ArrayIndexOutOfBoundsException f) {
                        // wind prob array > # of boundaries -- skip it
                        //System.err.println("WGD_pWD: " + f);
                    }
                }
            }
        }
    }

    private void getStationData(String station) {
        ArrayList<String> v = (station != null && station.toLowerCase().startsWith("interpolated"))
                ? intpData : dataSource.parseFile(station);
        parseElevation(v);
        parseWindTimes(v);
        parseWindSpeeds(v);
        calcThreshold();
        calcEWP();
        calcPrevailingWind();
        dataSource.fireDataReset();
        WT_windGenTable.repaint();
    }

    private void calcThreshold() {
        int tdx = 0;

        while (boundaries[tdx] < threshold && tdx < boundaries.length) {
            tdx++;
        }

        for (int mdx = 0; mdx < numMonths; mdx++) {
            double overThreshold = 0.0;
            for (int ddx = 0; ddx < numDirections; ddx++) {
                try {
                    // find interpolation fraction between two boundary
                    // points
                    double interp = (threshold - boundaries[tdx - 1])
                            / (boundaries[tdx] - boundaries[tdx - 1]);
                    // calculate the interpolated value for winds over
                    // theshold and multiply by the fraction of time
                    // the wind is coming from that direction and
                    // normalize by dividing by number of wind
                    // directions (16);
                    double windSpeedProb = 1 - (cumProb[mdx][ddx][tdx - 1]
                            + interp * (cumProb[mdx][ddx][tdx] - cumProb[mdx][ddx][tdx - 1]));
                    double addOn = windSpeedProb * windTimes[ddx][mdx] / 100;
                    overThreshold += addOn;

                } catch (ArrayIndexOutOfBoundsException e) {
                    // if array doesn't have any winds over threshold,
                    // just skip that direction
                }
            }

            NumberFormat cf = NumberFormat.getNumberInstance(Locale.US);
            cf.setMaximumFractionDigits(1);
            cf.setMinimumFractionDigits(1);

            cellData[WIND_SPEED][mdx] = cf.format(overThreshold * 100);
        }
    }

    private void calcEWP() {
        int tdx = 0;
        // magic formula for air density based upon elev and temp
        double airDensity = 348.56 * ((1.013 - 0.1183 * (elevationValue / 1000)
                + 0.0048 * (elevationValue / 1000) * (elevationValue / 1000))
                / (temperature + 273.1));
        double weFactor = 3.6 * 24 * 0.5;
        NumberFormat cf = NumberFormat.getNumberInstance(Locale.US);
        cf.setMaximumFractionDigits(0);
        cf.setMinimumFractionDigits(0);

        while (boundaries[tdx] < threshold && tdx < boundaries.length) {
            tdx++;
        }

        double[] monWindEnrgArr = new double[numMonths];
        double totalWindEnrg = 0;

        // calc total & monthly energies by month
        for (int mdx = 0; mdx < numMonths; mdx++) {
            double monWindEnrg = 0.0;
            // calc wind enrg by direction
            for (int ddx = 0; ddx < numDirections; ddx++) {

// calculate wind enrg from short first interval
                double dirWindEnrg = 0.0;
                int ntdx = tdx;
                if (ntdx >= intvProb[mdx][ddx].length) {
                    continue;
                }

                double curPos = threshold;

                if ((threshold % stepSize) > 0.000000001) {
                    double currentStepSize = stepSize - (threshold % stepSize);
                    curPos += currentStepSize / 2;
                    double stepValue = intvProb[mdx][ddx][ntdx] * (curPos - threshold) * curPos * curPos * currentStepSize;
                    dirWindEnrg += stepValue;
                    curPos += currentStepSize / 2;
                }

                curPos += stepSize / 2;

                try {

                    int stpIdx = 0;
                    while (ntdx < intvProb[mdx][ddx].length) {
                        while (curPos <= boundaries[ntdx]) {
                            double stepValue = intvProb[mdx][ddx][ntdx] * (curPos - threshold) * curPos * curPos * stepSize;
                            dirWindEnrg += stepValue;
                            curPos += stepSize;
                            stpIdx++;
                        }
                        ntdx++;
                    }
                } catch (ArrayIndexOutOfBoundsException e) {
                    //System.err.println("WGD_cWEP: AIOOBE");
                }
                monWindEnrg += weFactor * airDensity * dirWindEnrg * windTimes[ddx][mdx] / 100;
            }
            cellData[WIND_ENERGY][mdx] = cf.format(monWindEnrg);
            monWindEnrgArr[mdx] = monWindEnrg;
            totalWindEnrg += monWindEnrg;
        }

        cf.setMaximumFractionDigits(1);
        cf.setMinimumFractionDigits(1);
        for (int mdx = 0; mdx < numMonths; mdx++) {
            cellData[WIND_FRACT][mdx] = cf.format(monWindEnrgArr[mdx] * 100 / totalWindEnrg);
        }
        cf.setMaximumFractionDigits(0);
        cf.setMinimumFractionDigits(0);
        JL_avgEnergy.setText(cf.format(totalWindEnrg / 12));
    }

    private void calcPrevailingWind() {
        int tdx = 0;

        NumberFormat cf = NumberFormat.getNumberInstance(Locale.US);
        cf.setMaximumFractionDigits(1);
        cf.setMinimumFractionDigits(1);

        // find threshold boundary
        while (boundaries[tdx] < threshold && tdx < boundaries.length) {
            tdx++;
        }

        double[][] windErosionForces = new double[numMonths][numDirections];
        double[][] paraForces = new double[numMonths][numDirections];
        double[][] perpForces = new double[numMonths][numDirections];
        double[][] posvForces = new double[numMonths][numDirections];
        double[][] ratioForces = new double[numMonths][numDirections];

        for (int mdx = 0; mdx < numMonths; mdx++) {

            // calc wind forces by month and direction
            for (int ddx = 0; ddx < numDirections; ddx++) {
                try {
                    double firstFrac = (boundaries[tdx] - threshold) / (boundaries[tdx] - boundaries[tdx - 1]);
                    windErosionForces[mdx][ddx] = firstFrac * Math.pow(((boundaries[tdx] + threshold) / 2), 3) * intvProb[mdx][ddx][tdx] * windTimes[ddx][mdx];
                    for (int pdx = tdx + 1; pdx < intvProb[mdx][ddx].length; pdx++) {
                        windErosionForces[mdx][ddx] += Math.pow(((boundaries[pdx] + boundaries[pdx - 1]) / 2), 3) * intvProb[mdx][ddx][pdx] * windTimes[ddx][mdx];
                    }
                } catch (ArrayIndexOutOfBoundsException e) {
                }

            }

            for (int ddx = 0; ddx < numDirections; ddx++) {
                for (int adx = 0; adx < numDirections; adx++) {
                    double cos = Math.cos((adx - ddx) * 22.5 * Math.PI / 180);
                    double sin = Math.sin((adx - ddx) * 22.5 * Math.PI / 180);
                    paraForces[mdx][ddx] += windErosionForces[mdx][adx] * Math.abs(cos);
                    perpForces[mdx][ddx] += windErosionForces[mdx][adx] * Math.abs(sin);
                    if (cos > 0) {
                        posvForces[mdx][ddx] += windErosionForces[mdx][adx] * cos;
                    }
                }
                try {
                    ratioForces[mdx][ddx] = paraForces[mdx][ddx] / perpForces[mdx][ddx];
                } catch (Exception f) {
                    ratioForces[mdx][ddx] = Double.NaN;
                }
            }

            double maxRatio = 0.0;
            int maxDirection = 0;
            for (int ddx = 0; ddx < numDirections; ddx++) {
                if (maxRatio < ratioForces[mdx][ddx]) {
                    maxRatio = ratioForces[mdx][ddx];
                    maxDirection = ddx;
                }
            }
            if (posvForces[mdx][maxDirection] * 2 < paraForces[mdx][maxDirection]) {
                maxDirection = (maxDirection + numDirections / 2) % numDirections;
            }

            cellData[WIND_PREPOND][mdx] = cf.format(maxRatio);
            cellData[WIND_DIRECTION][mdx] = dirNames[maxDirection];
        }
    }

    public void addStation(String s) {
        JCB_station.addItem(s);
    }

    @Override
    public void bkgndDlgWriteWindMsg(String msg) {
    }

    @Override
    public void bkgndDlgWriteCliMsg(String msg) {
    }

    @Override
    public void bkgndDlgWriteWepsMsg(String msg) {
    }

    @Override
    public void bkgndDlgWriteMsg(int idx, String msg) {
    }

    @Override
    public void bkgndDlgWriteStatus(String status) {
    }

    @Override
    public void bkgndDlgSetPbarTotal(int totalYears) {
    }

    @Override
    public void bkgndDlgSetPbarCurrent(int currentYear) {
    }

    @Override
    public void bkgndDlgSetCancelEnabled(boolean enabled) {
    }

    @Override
    public void bkgndShowWepsMessageList(Component parent, String title, String text, String defaultFilePath, int optionType, ArrayList<WepsMessage> messages) {
    }

    @Override
    public void bkgndShowWepsMessageList(Component parent, String title, String defaultFilePath, ArrayList<WepsMessage> messages) {
    }

    @Override
    public void bkgndShowWepsMessage(Component parent, String title, String message, String defaultFilePath, int messageType, int optionType) {
    }

    @Override
    public boolean bkgndGetStopFlag() {
        return false;
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        switch (evt.getPropertyName()) {
            case progressSetProgressProperty:
                progress.setProgress(((Integer)evt.getNewValue()));
//                System.err.println("progress progress");
                break;
            case progressInitProperty:
                progress = new ProgressMonitor(this, "Interpolating", "Please wait...", 0, 100);
                progress.setMillisToDecideToPopup(300);
                progress.setMillisToPopup(500);
//                System.err.println("progress intitialized");
                
                progress.setProgress(1);
                // The ProgressMonitor self determines if it needs to display.
                // Give a pause here, to let ProgressMonitor think this is taking some time.
                // Then, it will display.
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException ex) {
                }
                progress.setProgress(2);
                
                break;
            case progressCloseProperty:
                progress.close();
//               System.err.println("progress close");
                break;
            case setEnableProperty:
                JCB_station.setSelectedItem(((String)evt.getNewValue()));
                toFront();
                setEnabled(true);
//                System.err.println("enable");
                break;
        }
    }
}

class WindGenData extends AbstractDataSource implements TableDataModel {

    private static final long serialVersionUID = 1L;

    private static final Logger logger = LogManager.getLogger(WindGenData.class);
    private List<String> c_keyMap;
    private List<Object[]> c_data;
    private TFile file;
    private final HashMap<String, Number> map = new HashMap<String, Number>();
    private final HashMap<String, String> idmap = new HashMap<String, String>();
    private final WindGenStationDisplay parent;
    protected String currentStation;
    String[][] cellData = new String[5][12];
    private final String[] monthNames = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

    public WindGenData(WindGenStationDisplay parent) {
        this.parent = parent;
        fireDataReset();
    }

    @Override
    public int getNumColumns() {
        return 12;
    }

    @Override
    public int getNumRows() {
        return 5;
    }

    @Override
    public Object getTableColumnLabel(int columnIndex) {
        return monthNames[columnIndex];
    }

    @Override
    public Object getTableDataItem(int rowIndex, int columnIndex) {
        try {
            String s = parent.cellData[rowIndex][columnIndex];
            return s;
        } catch (Exception e) {
            return "ERR";
        }
    }

    @Override
    public Object getTableRowLabel(int rowIndex) {
        int a = 21349;
        switch (rowIndex) {
            case 0:
                return "Winds > Threshold";
            case 1:
                return "Energy kJ/m^2/day";
            case 2:
                return "Monthly Percent";
            case 3:
                return "Preponderance";
            case 4:
                return "PWED";
            default:
                return "x";
        }
    }

    public ArrayList<String> parseFile(String station) {
        long index = 0;
        String tmp = station;
        if (map.get(tmp) == null) {
            tmp = idmap.get(station);
        }

        Number number = map.get(tmp);

        if (number != null) {
            index = number.longValue();
        } else {
            logger.warn("Unable to find index for " + (station != null ? station : "[NULL Station]"));
        }
        ArrayList<String> data = new ArrayList<>();
        String inLine;
        BufferedReader in = null;
        try {
            java.io.FileInputStream fin = new java.io.FileInputStream(file);
//            fin.getChannel().position(index);
            in = new BufferedReader(new InputStreamReader(fin));
            inLine = in.readLine();

            for (int i = 0; i < index; i++) {
                in.readLine();
            }

            while ((inLine = in.readLine()) != null) {
                if (inLine.startsWith("#")) {
                    break;
                } else {
                    data.add(inLine);
                }
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            try {
                in.close();
            } catch (Exception e) {
                logger.error("Error closing file stream.", e);
            }

        }
        currentStation = tmp;
        if (parent.JCB_station.getSelectedItem().equals(currentStation) == false) {
            final String tmp2 = tmp;

            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    parent.JCB_station.setSelectedItem(tmp2);
                }
            });
        }

        return data;
    }

    public boolean load(Component parent, TFile file) {
        this.file = file;
        String inLine;
        long position = 0;
        boolean success = true;
        String station;
        //read the file one line at a time into a vector for processing
        ProgressMonitor progress = null;
        try {
            java.io.FileInputStream fileStream = new java.io.FileInputStream(file);
            FileChannel channel = fileStream.getChannel();
            progress = new ProgressMonitor(parent, "Loading Table Data...", file.getName(), 0, (int) channel.size());
            progress.setMillisToDecideToPopup(300);
            progress.setMillisToPopup(500);
            InputStreamReader streamReader = new InputStreamReader(fileStream);
            LineNumberReader in = new LineNumberReader(streamReader);
            StringTokenizer s;
            //add parsing here...
            while ((inLine = in.readLine()) != null) {
                progress.setProgress((int) channel.position());
                if (inLine.startsWith("#")) {
                    s = new StringTokenizer(inLine, " ");
                    s.nextToken();
                    String stationID = s.nextToken();
                    StringBuilder sb = new StringBuilder();
                    while (s.hasMoreTokens()) {
                        sb.append(" " + s.nextToken());
                    }
                    station = sb.toString().trim();
                    idmap.put(stationID, station);
                    map.put(station, position);
                }
                position = in.getLineNumber();
//                position += inLine.length() + 1;
            }
            in.close();
            streamReader.close();
            fileStream.close();

            Set<String> keyset = map.keySet();
            ArrayList<String> l = new ArrayList<>();
            l.addAll(keyset);
            Collections.sort(l);
            for (String str : l) {
                this.parent.addStation(str);
            }

        } catch (OutOfMemoryError oome) {
            progress.close();
            JOptionPane.showMessageDialog(parent, "The data file is too large.", "Out of Memory", JOptionPane.ERROR_MESSAGE);
            success = false;
        } catch (Exception e) {
            e.printStackTrace();
            success = false;
        }
        fireDataReset();
        return success;

    }
}
