package usda.weru.weps.wepsRunControl;

import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.TFileReader;
import de.schlichtherle.truezip.file.TFileWriter;
import java.awt.Component;
import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.concurrent.ExecutionException;
import systems.uom.common.USCustomary;
import javax.swing.JOptionPane;
import static javax.swing.JOptionPane.ERROR_MESSAGE;
import javax.swing.SwingWorker;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; 
import org.openide.util.Exceptions;
import usda.weru.mcrew.ManageData;
import usda.weru.nrmv.ConvertAllToNrmv;
import usda.weru.util.About;
import usda.weru.util.ConfigData;
import usda.weru.util.Mantis;
import usda.weru.util.Util;
import usda.weru.util.WepsMessage;
import usda.weru.util.WepsMessage.MessageSeverity;
import usda.weru.util.WepsMessageDialog;
import static usda.weru.util.WepsMessageDialog.CANCEL_OPTION;
import static usda.weru.util.WepsMessageDialog.OK_OPTION;
import usda.weru.util.WepsMessageLog;
import usda.weru.weps.CalFactorDialog;
import usda.weru.weps.RunFileData;
import usda.weru.weps.RunNameChooser;
import usda.weru.weps.ScriptWriter;
import usda.weru.weps.Weps;
import usda.weru.weps.location.CligenStation;
import usda.weru.weps.location.FileStation;
import usda.weru.weps.location.InterpolatedStation;
import usda.weru.weps.location.Station;
import usda.weru.weps.location.StationMode;
import usda.weru.weps.location.WindgenStation;
import usda.weru.weps.reports.Locks;
import usda.weru.weps.reports.ReportManager;
import static usda.weru.weps.wepsRunControl.WrcException.wrcExceptionType.stationNotFound;

/**
 *
 * @author mhaas
 */
public class WrcSimulationControl extends SwingWorker<Integer, Integer> implements WrcBackgroundIf, PropertyChangeListener {

    protected String CurrentProj = "";
    protected String lastSuccessfulRun = "";
    protected String ManageFile = "";
    protected String SoilFile = "";
    protected String WinGen = "";
    protected String CliGen = "";
    protected String WinGenNumber = "";
    protected String WinCmd = "";
    protected String TotalYears = "";
    protected String startYear = "";
    protected String CliGenState = "";
    protected String CliGenStation = "";
    protected String CliCmd = "";
    protected String WepsCmd = "";
    protected String calWepsCmd = "";
    protected String WinFlg = "";
    protected String CliFlg = "";
    protected String notesText = "";
    protected String oldNotes = "";

    private final Locks rvLock = new Locks();
    protected final Logger LOGGER = LogManager.getLogger(WrcSimulationControl.class);

    /**
     * holds the command line arguments for three executables 0 windgen.exe 1
     * cligen.exe 2 weps.exe
     */
    protected String[][] commandsArr = new String[3][];
    protected String runDir;
    protected Component parent;
    protected WrcDialog wepsRunDialog;
    protected Thread mainRunThread;
    protected Process exeProcess;
    protected RunFileData runFileData;
    protected ConfigData configData;
    protected String newDir;
    protected boolean stopFlag = false;
    protected boolean calMode;
    //This boolean is used to check if the copying of the files is done properly for the run. - neha
    protected TFile copyResult = null;
    protected String xLength;
    protected String yLength;
    protected boolean noteLock = false;
    protected PropertyChangeSupport changes;
    // Object handle for the calibration factor dialog box for accessing its
    // components within the scope of RUN Program class.
    protected CalFactorDialog calibFactors;
    // The current project name to which this simulation RUN is associated.
    protected String projName = "";

    protected TFile runDirFile;
    protected boolean fileStation = false;

    protected Station windgenStation;

    protected Station cligenStation;

    protected RunNameChooser rnc = null;

    protected int bkgndDlgDefaultIdx = 0;
    protected int errIdx = -1;

    WrcRunModelWindInterpolate windInterpolateModel;
    WrcRunModelWind windModel;
    WrcRunModelClimate climateModel;
    WrcRunModelWeps wepsModel;

    boolean aborted;
//    boolean SkipWindgenExec = false;
//    boolean SkipCligenExec = false;

    //
    // Use this global to get a new WrcSimulationControl
    // It automatically uses a WrcSimulationControlIntegrated
    // if required
    //
    public static WrcSimulationControl getNewWrcSimulationControl(Component parent, RunFileData rfd, ConfigData cd, boolean cm) {
        return ConfigData.isWepsIntegrated() ? 
            new WrcSimulationControlIntegrated(parent, rfd, cd, cm) :
            new WrcSimulationControl(parent, rfd, cd, cm);
    }
    
    //
    // Do not use this directly.
    // See above.
    //
    protected WrcSimulationControl(Component parent, RunFileData rfd, ConfigData cd, boolean cm) {

        runFileData = rfd;
        ManageFile = runFileData.getData(RunFileData.ManageFile);

        configData = cd;
        this.parent = parent;
        calMode = cm;

        if (parent instanceof PropertyChangeListener) {
            addPropertyChangeListener((PropertyChangeListener) parent);
        }

        changes = new PropertyChangeSupport(this);
        changes.addPropertyChangeListener(rfd);

        aborted = false;
    }

    protected void setupData() throws WrcException {

        initArgs();
        initWindgenArgs();
        initCligenArgs();
        setRunInfo();
        setupWindgenExec();
        setupCligenExec();
        setupWepsExec();
        checkCmdsFormat();
        setupSupportFiles();

        if (rnc.getCreateBatch()) {
            createBatchFile();
        } else {
            setupDialog();
        }

        // for changes coming from the Swing background thread interface
        wepsRunDialog.addPropertyChangeListener(this);
        // for user messages back from the dialog
        addPropertyChangeListener(wepsRunDialog);
    }

    protected void initArgs() throws WrcException {

        runFileData.updateDates();

        getRunfileDataParms();
        getConfigDataParms();

        //Make sure that X length and Y length are not zero
        try {
            double test = Double.parseDouble(xLength);
            if (Double.isNaN(test) || Math.abs(test) == 0) {
                throw new NumberFormatException();
            }
        } catch (NumberFormatException nfe) {
            throw new WrcFormatException("field X-Length Error").addDlg(parent, "0.0 is an invalid value for the field X-Length.");
        }

        try {
            double test = Double.parseDouble(yLength);
            if (Double.isNaN(test) || Math.abs(test) == 0) {
                throw new NumberFormatException();
            }
        } catch (NumberFormatException nfe) {
            JOptionPane.showMessageDialog(parent, "0.0 is an invalid value for the field Y-Length.");
            throw new WrcFormatException("field Y-Length").addDlg(parent, "0.0 is an invalid value for the field Y-Length.");
        }

        if (!checkManExists()) {
            throw new WrcFormatException("Management file not selected or found").addDlg(parent, ".  Please select one.");
        }

        if (!checkSoilExists()) {
            throw new WrcFormatException("Soil file not selected or found").addDlg(parent, ".  Please select one.");
        }

        //make sure we don't have an xml file
        if (!checkManFormat()) {
            throw new WrcFormatException("Management file XML format not selected or found").addDlg(parent,
                    ".\nThe selected management file is in an unsupported and "
                    + "experimental XML format.\nReturn to MCREW and save as a *.man format.");
        }

        if (this.calMode && !checkManCalibration()) {
            throw new WrcFormatException("Check callibration failed").addLog(LOGGER, "");
        }

        // check if project exists -- if not, save it -- if unsaved, stop run
        if (CurrentProj.endsWith(RunFileData.UntitledProject)) {
            throw new WrcFormatException("Untitled Project").addDlg(parent, ".  Save project first, then make a run.");
        }

        if (ManageFile.equals(RunFileData.DefaultManageFileName)) {
            throw new WrcFormatException("No management selection").addDlg(parent, ". You must pick a management scenario before making a run.");
        }

        if (SoilFile.equals(RunFileData.DefaultSoilFileName)) {
            throw new WrcFormatException("No soil selection").addDlg(parent, ". You must pick a soil before making a run.");
        }
    }

    protected void getRunfileDataParms() {

        WinGenNumber = runFileData.getData(RunFileData.WinGenStation);
        TotalYears = runFileData.getData(RunFileData.TotalYears);

        String StartDate = runFileData.getData(RunFileData.StartDate);
        
        String[] tmpArr = StartDate.split(" +");
        startYear = tmpArr[2];
        CliGenState = runFileData.getData(RunFileData.CliGenState);

        if (!noteLock) {
            notesText = runFileData.getData(RunFileData.NotesText);
        } else {
            oldNotes = runFileData.getData(RunFileData.NotesText);
        }

        CliGenStation = runFileData.getData(RunFileData.CliGenStation);
        WinFlg = runFileData.getData(RunFileData.WindFlag);
        CliFlg = runFileData.getData(RunFileData.ClimateFlag);
        SoilFile = runFileData.getData(RunFileData.SoilFile);
        WinGen = runFileData.getData(RunFileData.WindFile);
        CliGen = runFileData.getData(RunFileData.ClimateFile);
        lastSuccessfulRun = runFileData.getData(RunFileData.LastRun);
        xLength = runFileData.getData(RunFileData.XLength);
        yLength = runFileData.getData(RunFileData.YLength);
    }

    protected void getConfigDataParms() {
        WinCmd = configData.getDataParsed(ConfigData.WinCmd);
        CliCmd = configData.getDataParsed(ConfigData.CliCmd);
        WepsCmd = configData.getDataParsed(ConfigData.WepsCmd);
        calWepsCmd = configData.getDataParsed(ConfigData.CalWepsCmd);
        CurrentProj = configData.getDataParsed(ConfigData.CurrentProj);
        CurrentProj = configData.getDataParsed(ConfigData.CurrentProj);
    }

    protected void initWindgenInterpolateArgs() throws WrcException {

        //WINDGEN PRECHECK LOGIC
        StationMode windgenMode = runFileData.getBean().getWindgenStationMode();
        windgenStation = runFileData.getBean().getWindgenStation();

        if (windgenMode == null) {
            throw new WrcFormatException("No windgen station selected.").addDlg(parent);
        } else if (windgenStation instanceof WindgenStation) {
            //normal station, we generate a wind file with windgen
            //make sure we have enough data to run
            WindgenStation test = (WindgenStation) windgenStation;
            if (test.getWBan() == 0) {
                throw new WrcFormatException("Incomplete Windgen Record").addDlg(parent,
                        ". The windgen station record is missing the wban parameter.\n"
                        + "Please contact your data provider for updated records.");
            }
        } else if (windgenStation instanceof FileStation) {
            //file station, we use an already generated file.
            FileStation station = (FileStation) windgenStation;
            TFile file = station.getFile();
            if (file == null || !file.exists()) {
                throw new WrcFormatException("Windgen file does not exist").addDlg(parent, "\n" + "File:  " + file.getAbsolutePath());
            }
        } else if (windgenStation instanceof InterpolatedStation) {
            //interpolated station
            //no checks yet.
        } else if (windgenStation == null) {
            //no station selected
            throw new WrcFormatException("No windgen station selected.").addDlg(parent);
        } else {
            //don't know how to handle the windgen station
            throw new WrcFormatException("Unexpected windgen station type").addLog(LOGGER, ": " + windgenStation.toString());
        }
    }

    protected void initWindgenArgs() throws WrcException {

        if (WinGen != null) {
            TFile tmp = new TFile(WinGen);
            if (tmp != null && !tmp.isAbsolute()) {
                tmp = new TFile(CurrentProj + "/" + lastSuccessfulRun + "/" + WinGen);
            }
        }
        //WINDGEN PRECHECK LOGIC
        StationMode windgenMode = runFileData.getBean().getWindgenStationMode();
        windgenStation = runFileData.getBean().getWindgenStation();

        windInterpolateModel = null;

        if (windgenMode == null) {
            throw new WrcFormatException("No windgen station selected.").addDlg(parent);
        } else if (windgenStation instanceof WindgenStation) {
            //normal station, we generate a wind file with windgen
            //make sure we have enough data to run
            WindgenStation test = (WindgenStation) windgenStation;
            if (test.getWBan() == 0) {
                throw new WrcFormatException("Incomplete Windgen Record").addDlg(parent,
                        ". The windgen station record is missing the wban parameter.\n"
                        + "Please contact your data provider for updated records.");
            }
        } else if (windgenStation instanceof FileStation) {
            //file station, we use an already generated file.
            FileStation station = (FileStation) windgenStation;
            TFile file = station.getFile();
            if (file == null || !file.exists()) {
                throw new WrcFormatException("Windgen file does not exist").addDlg(parent, "\n" + "File:  " + file.getAbsolutePath());
            }
        } else if (windgenStation instanceof InterpolatedStation) {
            //interpolated station
            //no checks yet.
        } else if (windgenStation == null) {
            //no station selected
            throw new WrcFormatException("No windgen station selected.").addDlg(parent);
        } else {
            //don't know how to handle the windgen station
            throw new WrcException("Unexpected windgen station type").addLog(LOGGER, ": " + windgenStation.toString());
        }
    }

    protected void initCligenArgs() throws WrcException {
        //CLIGEN PRECHECK LOGIC
        StationMode cligenMode = runFileData.getBean().getCligenStationMode();
        cligenStation = runFileData.getBean().getCligenStation();

        if (cligenMode == null) {
            throw new WrcException("Unexpected cligen station type").addLog(LOGGER, ": " + cligenStation.toString());
        } else if (cligenStation instanceof CligenStation) {
            //normal station, we generate a climate file with cligen
            //make sure we have enough data to run
            CligenStation test = (CligenStation) cligenStation;
            if (test.getState() == 0 || test.getId() == 0) {
                throw new WrcFormatException("Incomplete Cligen Record").addDlg(parent,
                        ". The cligen station record is missing the state id or station id.\n"
                        + "Please contact your data provider for updated records.");
            }
        } else if (cligenStation instanceof FileStation) {
            //file station, we use an already generated file.
            FileStation station = (FileStation) cligenStation;
            TFile file = station.getFile();
            if (file == null || !file.exists()) {
                throw new WrcException("Cligen file does not exist");
            }
        } else if (cligenStation == null) {
            //no station selected
            throw new WrcFormatException("No Cligen station selected.").addDlg(parent);
        } else {
            //don't know how to handle the cligenStation station
            throw new WrcException("Unexpected Cligen station type")
                    .addLog(LOGGER, ":" + cligenStation.toString());
        }
        //END CLIGEN PRECHECK LOGIC

        TFile tmp = new TFile("");
        if (CliGen != null) {
            tmp = new TFile(CliGen);
            if (!tmp.isAbsolute()) {
                tmp = new TFile(CurrentProj + "/" + lastSuccessfulRun + "/" + CliGen);
            }
        }
        if (CliFlg.equals("1") && !(tmp.exists())) {
            throw new WrcFormatException("Climate file does not exist").addDlg(parent,
                    "\nSpecify file or enable climate generation.\n"
                    + "File:  " + new TFile(CliGen).getAbsolutePath());
        }
    }

    /**
     * Is used when a run is made or a new project is created. Creating the
     *  "My WS_WEPS Runs" (now "Runs") file in the project folder.
     *
     * @throws WrcException - if user cancels the operation
     */
    protected void setRunInfo() throws WrcException {
        //Run Name Selector
        rnc = new RunNameChooser(runFileData, calMode);
        rnc.setNewProject(); // So RunNameChooser will use the defaults or create necessary dirs
        runDirFile = rnc.showRunNameChooser(parent);
        if (Files.exists(Paths.get(runDirFile.getAbsolutePath()))) {
            int result = JOptionPane.showConfirmDialog(rnc,
                    "The run location already exists.  Would you like to write over a previous run?\n\n"
                    + runDirFile.getName(), "WEPS Run Name", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
            if (result == JOptionPane.YES_OPTION) {
                try {
                    FileUtils.deleteDirectory(new File(runDirFile.getAbsolutePath()));
                } catch (IOException e) {

                }
            } else {
                setRunInfo();

            }

        }
        if (runDirFile == null) {
            //user cancelled
            throw new WrcFormatException("User cancelled");
        }

        /// using absolute path for now
        //runFileData.setData(RunFileData.LastRunAttempt, rnc.getRunFile().getName());
        runFileData.setData(RunFileData.LastRunAttempt, rnc.getRunFile().getAbsolutePath());

        newDir = runDirFile.getName();
        runDir = runDirFile.getAbsolutePath();

        //make the new run directory, first make sure the space is clear
        try {
            FileUtils.deleteDirectory(new File(runDirFile.getAbsolutePath()));
        } catch (IOException e) {

        }
        if (!runDirFile.mkdir()) {
            throw new WrcFormatException("Cannot create run directory").addDlg(parent,
                    " with name " + newDir);
        }

        try {
            About.getUserConfig().cp(new File(runDir, About.getUserConfig().getName() + ".txt"));
        } catch (IOException ex) {
        }

        // If there occurs a change in the rotation years in Mcrew, then that
        // change should be reflected in the Run Dialog and also in the weps.run file
        //[EndDate in weps.run should change accordingly]
        runFileData.setRotationYears(ManageFile);
        runFileData.updateDates();

    }

    protected void setupDialog() {
        wepsRunDialog = new WrcDialog(parent, newDir);
        //wepsRunDialog.addPropertyChangeListener(this);
        wepsRunDialog.setTotalYears(TotalYears);
        wepsRunDialog.setVisible(true);
    }

    protected void setupWindgenExec() throws WrcException {

        //WINDGEN EXECUTABLE LOGIC
        windModel = new WrcRunModelWind(runDir, LOGGER, this);
        if (startYear.length() > 0) {
            windModel.addCmds_startYear(startYear);
        }
        windModel.addCmds_totalYears(TotalYears);
        if (windgenStation instanceof WindgenStation) {
            WindgenStation station = (WindgenStation) windgenStation;

            windModel.addCmds_station(station.getWBan());
            WinGenNumber = String.valueOf(station.getWBan());
            // output file name, always uses the default name
            //windModel.addCmds_outputFile(new TFile(runDir, RunFileData.DefaultWinGenName).getAbsolutePath());
        } else if (windgenStation instanceof FileStation) {
            fileStation = true;
            FileStation station = (FileStation) windgenStation;
            //file station, we use an already generated file.
            copyResult = copyFileStation(runDir, station);
            if (copyResult == null) {
                throw new WrcException("Error in copying the Wind File.").addLog(LOGGER, "dir:" + runDir + "station:" + station);
            }
            // Add the copied file to the model.
            // Weps gets the file name from the model
            windModel.addCmds_outputFile(copyResult.getAbsolutePath());
            if (wepsRunDialog != null) {
                wepsRunDialog.JTF_win.setText("copied");
            }
            //SkipWindgenExec = true;
            windModel.skipExec = true;

        } else if (windgenStation instanceof InterpolatedStation) {

            windInterpolateModel = new WrcRunModelWindInterpolate(runDir, LOGGER, this);

            String winIdxFile = ConfigData.getDefault().getDataParsed(ConfigData.WinIndex);
            windInterpolateModel.addCmds_idxFile(winIdxFile);

            String polFile = ConfigData.getDefault().getDataParsed(ConfigData.WindgenInterpolationBoundaryFile);
            TFile pol = polFile != null && !polFile.isEmpty() ? new TFile(polFile) : null;
            if (pol == null || !pol.exists()) {
                throw new WrcException("Unable to find windgen projection file.").addLog(LOGGER, ". Filename:" + polFile);
            }
            polFile = pol.getAbsolutePath();
            windInterpolateModel.addCmds_polFile(polFile);
            windInterpolateModel.addCmds_latlon(String.valueOf(windgenStation.getLatLong().latitudeValue(USCustomary.DEGREE_ANGLE)),
                    WrcRunModelWindInterpolateGetStations.latlonFlag.lat);
            windInterpolateModel.addCmds_latlon(String.valueOf(windgenStation.getLatLong().longitudeValue(USCustomary.DEGREE_ANGLE)),
                    WrcRunModelWindInterpolateGetStations.latlonFlag.lon);
            //windInterpolateModel.addCmds_outputFile("weights.txt");
            windModel.addCmds_station(windInterpolateModel.getStationNum());
            windModel.addCmds_outputFile("interpolated.win");
            // wind_gen4.exe is a windows program, use a windows path
            windModel.addCmds_wdbFile("interpolate/" + windInterpolateModel.getWdbFileName());

            // For interpolation mode, windgen uses the legacy output format (used to be run in MIS).
            windModel.setLegacyMimicMIS();
        }
    }

    protected void setupCligenExec() throws WrcException {
        climateModel = new WrcRunModelClimate(runDir, LOGGER, this);

        //CLIGEN EXECUTABLE LOGIC
        if (cligenStation instanceof CligenStation) {
            CligenStation station = (CligenStation) cligenStation;

            // state number
            climateModel.addCmds_stateNum(station.getState());
            // state name
            climateModel.addCmds_stationNum(station.getId());
            // start year
            if (startYear.length() > 0) {
                climateModel.addCmds_startYear(startYear);
            }
            // number of years
            climateModel.addCmds_totalYears(TotalYears);
            // output file name
            climateModel.addCmds_outputFile(new TFile(runDir, RunFileData.DefaultCliGenName).getAbsolutePath());
            // cligen PRISM
            if (climateModel.isServerPrismMode()) {
                // csip Cligen_prism expects latlon, whether it is doing PRISM or not
                climateModel.addCmds_latlon(runFileData.getData(RunFileData.StrLatLong));
            } else if (climateModel.isLocalPrismMode()) {
                // (PRISM data only exists for continental US)
                if (climateModel.isContinentalUS()) {
                    climateModel.addCmds_localPrism(runFileData.getData(RunFileData.StrLatLong));
                } else {
                    LOGGER.info("Cligen local: not continental US, skipping PRISM");
                }
            }

        } else if (cligenStation instanceof FileStation) {
            FileStation station = (FileStation) cligenStation;
            copyResult = copyFileStation(runDir, station);
            if (copyResult == null) {
                throw new WrcException("Error in copying the Climate File.").addLog(LOGGER, "dir:" + runDir + "station:" + station);
            }
            // Add the copied file to the model.
            // Weps gets the file name from the model
            climateModel.addCmds_outputFile(copyResult.getAbsolutePath());
            if (wepsRunDialog != null) {
                wepsRunDialog.JTF_cli.setText("copied");
            }
            //SkipCligenExec = true;
            climateModel.skipExec = true;
        }
    }

    protected void setupWepsExec() throws WrcException {
        wepsModel = new WrcRunModelWeps(runDir, LOGGER, this);

        // misc calib cmds
        if (calMode) {
            wepsModel.addCmds_fromStr(calWepsCmd);
        }
        // output file name
        wepsModel.addCmds_outputPath(runDir);

        wepsModel.setManageFile(ManageFile);
        wepsModel.setSoilFile(SoilFile);
        wepsModel.addCmds_addWindgenInput(new File(windModel.get_outputFile()).getName());
    }

    protected void checkCmdsFormat() throws WrcException {
        //check that none of the commands are too long
        if (Util.isWindows()) {
            for (String[] cmd : commandsArr) {
                if (cmd == null) {
                    continue;
                }
                for (String arg : cmd) {
                    if (arg.length() > 259) {
                        wepsRunDialog.setVisible(false);
                        throw new WrcException("Command argument too long").addLog(LOGGER, "\n" + cmd[0] + "\n" + arg);
                    }
                }
            }
        }
    }

    protected void setupSupportFiles() throws WrcException {
        if (copyManIFCNotes(runDir) == false) {
            throw new WrcException("Error in copying the Management or Soil Files").addLog(LOGGER, " dir:" + runDir);
        }
//        runFileData.writeRunDataXML(CurrentProj); // should only update last run
        runFileData.writeRunFile(runDir);
        if (calMode) {
            TFile backup = new TFile(runDir, "weps.run");
            TFile orig = Util.incrementFileName(backup, "_ORIG", ".run");
            try {
                backup.mv(orig);
            } catch (IOException e) {
                LOGGER.warn("Failed to backup weps.run file");
            }
            runFileData.writeRunFile(runDir, calMode);
        }
    }

    protected void createBatchFile() throws WrcException {
        if (commandsArr[0] == null) {
            if (fileStation) {
                List<String> windCmd = new ArrayList<String>();
                windCmd.add(wepsModel.getCmd_exe());
                windCmd.add("-s file");	// station number
                this.WinGenNumber = "file";
                //Add the data file from the config
                WinCmd = Util.parse(WinCmd);
                parseCmd(WinCmd, windCmd);          // misc params
                if (startYear.length() > 0) {
                    windCmd.add("-b" + startYear);	// start year
                }
                windCmd.add("-y" + TotalYears);     // number of years
                // output file name, always uses the default name
                windCmd.add("-o" + this.runFileData.getData(RunFileData.WinGenStation));
                String[] winArr = windCmd.toArray(new String[windCmd.size()]);
                commandsArr[0] = winArr;
            } else {
                List<String> windCmd = new ArrayList<String>();
                windCmd.add(wepsModel.getCmd_exe());
                windCmd.add("-s interpolated");	// station number
                this.WinGenNumber = "interpolated";
                //Add the data file from the config
                WinCmd = Util.parse(WinCmd);
                parseCmd(WinCmd, windCmd);          // misc params
                if (startYear.length() > 0) {
                    windCmd.add("-b" + startYear);	// start year
                }
                windCmd.add("-y" + TotalYears);     // number of years
                // output file name, always uses the default name
                windCmd.add("-o" + new TFile(runDir, RunFileData.DefaultWinGenName).getAbsolutePath());
                String[] winArr = windCmd.toArray(new String[windCmd.size()]);
                commandsArr[0] = winArr;
            }
        }
        String lat = String.valueOf(windgenStation.getLatLong().latitudeValue(USCustomary.DEGREE_ANGLE));
        String lon = String.valueOf(windgenStation.getLatLong().longitudeValue(USCustomary.DEGREE_ANGLE));
        //System.out.println(Arrays.toString(commandsArr[1]));
        ScriptWriter.writeBatchScript(runDirFile, configData, wepsModel.getCmd_exe(), WinGenNumber,
                climateModel.getCmd_exe(), CliGenState, CliGenStation, wepsModel.getCmd_exe(), TotalYears, startYear,
                this.runFileData.getData(RunFileData.WindFile),
                this.runFileData.getData(RunFileData.ClimateFile), lat, lon, commandsArr);
        JOptionPane.showMessageDialog(parent, "run.sh created in directory "
                + runDirFile + "\nThis script must be run to produce weps output.",
                "Script Created", JOptionPane.INFORMATION_MESSAGE);
    }

    private boolean checkManFormat() {
        TFile chkFile = new TFile(ManageFile);
        return !chkFile.getName().toLowerCase().endsWith(".xml");
    }

    private boolean checkManExists() {
        TFile chkFile = new TFile(ManageFile);
        return chkFile.exists();
    }

    private boolean checkSoilExists() {
        TFile chkFile = new TFile(SoilFile);
        return chkFile.exists();
    }

    private boolean checkManCalibration() {
        ManageData man = new ManageData();
        man.readDataFile(ManageFile);

        List<String> msgs = new LinkedList<>();
        if (man.checkCalibration(msgs) == ManageData.CHECK_FAILED) {
            WepsMessageLog log = new WepsMessageLog();
            for (String msg : msgs) {
                log.logMessage(WepsMessage.MessageSeverity.ERROR, msg);
            }
            WepsMessageDialog.showMessageList(null, "Management File Errors", "Unable to proceed with calibration run.\n"
                    + "Errors were detected with the management file.", CurrentProj, log.getMessages());
            return false;
        }
        return true;
    }

    private void parseCmd(String cmdLin, List<String> cmdVec) {
        String[] args = cmdLin.split("(^-)|(\\s+-)", -1);
        for (String arg : args) {
            if (arg.trim().length() > 0) {
                cmdVec.add("-" + arg.trim());
            }
        }
    }

    private TFile copyFileStation(String runDir, FileStation station) {
        TFile fromFile = station.getFile();
        TFile toFile = new TFile(runDir, fromFile.getName());

        if (!Util.copyFile(fromFile, toFile)) {
            return null;
        }
        return toFile;
    }

    private boolean copyManIFCNotes(String runDir) {
        String fromFile;
        String toFile;
        String tmp;
        String appendName = "";
        boolean retValue = false;
        
        String mgtExt = ".man"; // Deal with XML mgt file extension later
        String appendCalibTmp = "";
        String appendCalib = "_CALIB"; // String to append to mgt filenames being calibrated - LEW - 3-2-23
        String appendOrig = ".ORIG";
        String mgtStr = "";
        String mgtOrigStr = "";
        String mgtCalibStr = "";
        TFile MgtFile;
        TFile MgtOrigFile;
        TFile MgtCalibFile;

        String mgtStrTmp = "";
        int mgtStrTmpLen;
        String appendNameTmp;
        int calib_idx;
        int number = 0;
        boolean isInteger = true;
        TFile MgtFileTmp;

        // Get name of original mgt file with the Run path
        mgtStr = new TFile(runDir, new TFile(ManageFile).getName()).getAbsolutePath();           
        // Copy over original mgt file
        retValue = Util.copyFile(ManageFile, mgtStr);
        if (!retValue) {
           return retValue;
        }
        MgtFile = new TFile(mgtStr);
        
        if (calMode) {

            // Derive backup filename of original mgt file (appends "appendOrig" to name prior to final mgt extension, which is ".man" for now)
            mgtOrigStr = Util.incrementFileName(MgtFile, appendName, appendOrig, mgtExt).getAbsolutePath();         
            // Copy over original mgt file with "appendOrig" extension
            retValue = Util.copyFile(ManageFile, mgtOrigStr);
            if (!retValue) {
                return retValue;
            }
            MgtOrigFile = new TFile(mgtOrigStr);

            mgtStrTmp = mgtStr.replace(mgtExt,""); //Remove mgtExt string temporarily
            mgtStrTmpLen = mgtStrTmp.length();
                
            // Check to see if original mgt file already has the "appendCalib" extension (ideally it shouldn't)
            if (!mgtStrTmp.contains(appendCalib)) {
                // No appendCalib string, add an appendCalib string to Filename
                mgtCalibStr = Util.incrementFileName(MgtFile, appendName, appendCalib, mgtExt).getAbsolutePath();
            }
            else { // Must already have an appendCalib string
                //Find the last appendCalib string in the Filename
                calib_idx = mgtStrTmp.lastIndexOf(appendCalib) + appendCalib.length();
                if (calib_idx == mgtStrTmpLen) { //Is appendCalib string at end of Filename?
                    //Yes, appendCalib string is at end of Filename
                    appendCalibTmp = "_1"; //Append an underscore and the number one
                    mgtCalibStr = Util.incrementFileName(MgtFile, appendName, appendCalibTmp, mgtExt).getAbsolutePath();
                }
                //Find out what is following the appendCalib string
                else if ((((calib_idx + 1) == mgtStrTmpLen) && (mgtStrTmp.charAt(calib_idx)) == '_')) { //Did someone possibly add only an "_" after the appendCalib string?
                    //appendCalibTmp = appendCalib + "_1"; //Just put a number after the "_" and continue
                    //mgtCalibStr = Util.incrementFileName(MgtFile, appendName, appendCalibTmp, mgtExt).getAbsolutePath();

                    mgtStrTmp = mgtStrTmp.substring(0,calib_idx+1).concat("1"); //Just put a number after the "_" and continue
                    MgtFileTmp = new TFile(mgtStrTmp);
                    mgtCalibStr = Util.incrementFileName(MgtFileTmp, mgtExt).getAbsolutePath();
                }
                else if (mgtStrTmp.charAt(calib_idx) == '_') { //Grab last char and hope it is a number
                    int underscore_idx = mgtStrTmp.lastIndexOf("_");
                    if (underscore_idx != -1) {
                        try {
                            String numberString = mgtStrTmp.substring(underscore_idx + 1);
                            number = Integer.parseInt(numberString);
                        } catch (NumberFormatException e) { //Characters after the underscore are not an integer
                            isInteger = false;
                            MgtFileTmp = new TFile(mgtStrTmp);
                            mgtCalibStr = Util.incrementFileName(MgtFileTmp, appendName, appendCalib, mgtExt).getAbsolutePath();
                        }
                        if (isInteger == true) {
                            number += 1; //Increment the number here
                            mgtStrTmp = mgtStrTmp.substring(0,underscore_idx+1).concat(Integer.toString(number));
                            MgtFileTmp = new TFile(mgtStrTmp);
                            mgtCalibStr = Util.incrementFileName(MgtFileTmp, mgtExt).getAbsolutePath();
                        }
                    }
                }
            }
            retValue = Util.copyFile(ManageFile, mgtCalibStr);
            if (!retValue) {
                return retValue;
            }
            MgtCalibFile = new TFile(mgtCalibStr);
            runFileData.setData(RunFileData.MgtCalibFile,mgtCalibStr); //Pass data to RunFileData to create valid calibration "weps.run" file
            
            // Update model w/ new name
            wepsModel.setManageFile(mgtCalibStr);
        }

        // copy IFC file
        toFile = new TFile(runDir, new TFile(SoilFile).getName()).getAbsolutePath();
        retValue = Util.copyFile(SoilFile, toFile); // copy soil ifc file to "Run" folder
        return retValue;
    }

    /**
     * Deletes wingen and cligen files that are no longer needed after the weps
     * simulation.
     */
    public void purgeRunFiles() {

        if (ConfigData.getDefault().isPurgeFlag()) {
            //We have a filter to work with.

            String dirString = runDir;
            TFile dir = new TFile(dirString);
            String[] list = dir.list();
            if (list == null) {
                return;
            }
            for (String list1 : list) {
                if (isPurgeable(list1)) {
                    TFile file = new TFile(dirString, list1);
                    LOGGER.info("Deleting: " + file.getAbsolutePath());
                    try {
                        file.rm();
                    } catch (IOException e) {
                        LOGGER.warn("Unable to delete file: " + file.getAbsolutePath());
                    }
                }
            }
        }
    }

    private boolean isPurgeable(String name) {
        String[] filters = ConfigData.getDefault().getPurgeFilenames();
        for (String filter : filters) {
            if (filter.equalsIgnoreCase(name)) {
                return true;
            }
        }
        return false;
    }

    private void displayCalibReport(TFile calibParmFile, String myRunDir) {
        calibFactors = new CalFactorDialog(configData, runFileData);
        calibFactors.setLocation(50, 50);
        try {

            String inpLin;
            try (BufferedReader in = new BufferedReader(new TFileReader(calibParmFile))) {
                inpLin = null;
                while (true) {
                    String tmpLin = in.readLine();
                    if (tmpLin == null) {
                        break;
                    }
                    inpLin = tmpLin;
                }
            }
            if (inpLin != null) {
                StringTokenizer st = new StringTokenizer(inpLin, "|");
                StringBuilder sb = new StringBuilder();
                String myNew = "";
                String adjustmentDate = "";
                String adjustmentCrop = "";
                String adjustmentValue = "";

                //System.out.println( " RP_displayCalibReport : Number of Columns: " + numCols );
                while (st.hasMoreTokens()) {
                    st.nextToken();
                    adjustmentDate = st.nextToken();
                    sb.append(" " + adjustmentDate + "\t");
                    st.nextToken();
                    adjustmentCrop = st.nextToken();
                    myNew = adjustmentCrop;

                    sb.append(myNew);
                    adjustmentValue = st.nextToken();
                    sb.append("\t\t" + adjustmentValue + " " + "\n");
                    calibFactors.addCalibrationAdjustment(adjustmentDate, adjustmentCrop, adjustmentValue);
                }
                notesText = sb.toString() + "\n" + notesText;

                String myCurrProjName = new TFile(myRunDir).getParentFile().getAbsolutePath();
                if (calibFactors == null) {

                    String[] myFiles = new TFile(myRunDir).list();
                    String myManageFile = "";
                    for (String myFile : myFiles) {
                        if (calMode) {
//                            if (myFile.endsWith("._calib.man")) {
                            if (myFile.endsWith("_CALIB.man")) {
                                myManageFile = myFile;
                            }
                            //I added this to ensure it set "myManageFile" in calibration mode, may need to modify later - LEW
                            else if (myFile.contains("_CALIB")) {
				myManageFile = myFile;
			    }
                            
//                        } else if (myFile.endsWith(".man")) {
                        } else if (myFile.endsWith(".man")) {
                            myManageFile = myFile;
                        }
                    }
                    if (myManageFile.lastIndexOf('.') > 0) {
                        myManageFile = myManageFile.substring(0, myManageFile.lastIndexOf('.'));
                    }

                    calibFactors.JTF_projName.setText(myCurrProjName);
                    calibFactors.JTF_runName.setText(newDir);
                    calibFactors.JTF_manFile.setText(myManageFile);
                    calibFactors.JTA_cropAttributes.setText(sb.toString());
                    calibFactors.toFront();
                    calibFactors.setVisible(true);
                } else {

                    java.io.File[] myFiles = new TFile(myRunDir).listFiles();

                    String myManageFile1 = "";
                    for (java.io.File myFile : myFiles) {
                        if (calMode) {
//      //                      if (myFile.getName().endsWith("._calib.man")
   //   //                      if (myFile.getName().endsWith("_CALIB.man")
   //   //                              && myFile.getName().endsWith("man")  // Hmm, needs modified for XML man files here - LEW 12/15/22
   //                                 //&& !myFile.getName().contains("._orig")
   //                         ) {
//                              // if (myFile.getName() == myCalibStr.getName()) {
//                              if (myFile == runFileData.getData(RunFileData.MgtCalibFile)) {
//                                calibFactors.setManagementFile(new TFile(myFile));
//                                myManageFile1 = myFile.getName();
//                              }
   //   //                      }
//
                            String mgtTmp = runFileData.getData(RunFileData.MgtCalibFile);
                            calibFactors.setManagementFile(new TFile(runFileData.getData(RunFileData.MgtCalibFile)));
                            myManageFile1 = new TFile (mgtTmp).getName();

                        } else if (myFile.getName().endsWith(".man")) { //Probably not a good way to do this if more than one mgt file exists - LEW
                            calibFactors.setManagementFile(new TFile(myFile));
                            myManageFile1 = myFile.getName();
                        }
                    }
                    if (myManageFile1.lastIndexOf('.') > 0) {
                        myManageFile1 = myManageFile1.substring(0, myManageFile1.lastIndexOf('.'));
                    }
                    calibFactors.JTF_projName.setText(myCurrProjName);
                    calibFactors.JTF_runName.setText(newDir);
                    calibFactors.JTF_manFile.setText(myManageFile1);
                    calibFactors.JTA_cropAttributes.setText(sb.toString());
                    calibFactors.updateManagementFile();
                    calibFactors.toFront();
                    calibFactors.setVisible(true);
                }
            }
        } catch (IOException e) {
            //System.err.println("RFD_rRF: " + e);
        } catch (java.lang.NullPointerException f) {
            JOptionPane.showMessageDialog(parent,
                    "Error loading calibration run file(s)",
                    "Error (RFD-001)",
                    JOptionPane.ERROR_MESSAGE);
            f.printStackTrace();
        }
    }

    @Override
    protected Integer doInBackground() throws Exception {
        WepsMessageLog localSimLog = new WepsMessageLog();
        int rtnVal = -1;

        PrintWriter writerStdErr = null;
        PrintWriter writerStdOut = null;
        oldNotes = notesText;
        noteLock = true;
        aborted = false;
    
        try {
            setupData();
        } catch (Exception e) {
            WrcException ex=null; 
            if (e instanceof WrcException) {
                ex = (WrcException)e; 
                if (ex.getType() == WrcException.wrcExceptionType.prismDataReadFail) {
                    String msg = "Run failed because the Prism data is not available for the current location.\n"
                            + "This is usually caused by an Internet connection problem.\n"
                            + "Either try the run later with Internet connectivity, or disable the Prism adjustment mode.\n"
                            + "Prism adjust mode option is located in the tools/Edit Configuration menu item,\n"
                            + "Then on the Server tab, Model options sub-tab.\n"
                            + "\n"
                            + "You can also see the locations of all downloaded Prism data.\n"
                            + "Use the 'Select Field Location' button in th eupper right area of the Weps screen\n"
                            + "and then select the 'visible' checkbox of the 'Cached Prism Data' selection on the\n"
                            + "left side of that window and all of the downloaded Prismvlocations will be displayed\n"
                            + "\n"
                            + "If you think this is an error and wish to submit a bug report, please press OK.\n"
                            + "Otherwise, press Cancel and adjust your settings for the next run.";
                    if (WepsMessageDialog.showScrollableMessage(parent, "Run Error", msg, null, JOptionPane.WARNING_MESSAGE, OK_OPTION | CANCEL_OPTION)
                            == OK_OPTION) {
                        ex.setFatal(true);
                    }
                }
            }
            throw (e);
        }

        try {

            writerStdErr = new PrintWriter(new BufferedWriter(new TFileWriter(
                    new TFile(runDir, RunFileData.StdErr)))); // SEP01	RUN08
            writerStdOut = new PrintWriter(new BufferedWriter(new TFileWriter(
                    new TFile(runDir, RunFileData.StdOut))));// SEP01	RUN08
        } catch (FileNotFoundException ex) {
            throw new WrcException("Could not open stdout or stderr in WrcSimulationControl", ex);
        }

        try {
//            if (windInterpolateModel != null) {
            if (windInterpolateModel != null && !windInterpolateModel.skipExec) {
                bkgndDlgWriteWindMsg("interpolating");
                windInterpolateModel.setOutputWriters(writerStdErr, writerStdOut);
                rtnVal = windInterpolateModel.execModel();
                localSimLog.mergeLog(windInterpolateModel.getLocalLog());
                bkgndDlgWriteWindMsg("finished");
            }

            errIdx = 0;
            windModel.setOutputWriters(writerStdErr, writerStdOut);            
//            if (!SkipWindgenExec) {
            if (!windModel.skipExec) {
                rtnVal = windModel.execModel();
            }
            localSimLog.mergeLog(windModel.getLocalLog());

            errIdx = 1;
//            if (!SkipCligenExec) {
            if (!climateModel.skipExec) {
                climateModel.setOutputWriters(writerStdErr, writerStdOut);
                rtnVal = climateModel.execModel();
            }
            localSimLog.mergeLog(climateModel.getLocalLog());

            errIdx = 2;
            wepsModel.setOutputWriters(writerStdErr, writerStdOut);
            rtnVal = wepsModel.execModel();
            localSimLog.mergeLog(wepsModel.getLocalLog());

        } catch (WrcException e) {
            writerStdOut.close();
            writerStdErr.close();

            if (e.getType() == stationNotFound) {
                bkgndShowWepsMessage(parent,
                        "Weps run failed",
                        e.getMessage(),
                        null, ERROR_MESSAGE, CANCEL_OPTION);
            } else {
//                bkgndShowWepsMessage(parent,
//                        "Weps run failed",
//                        "This Weps run failed due to a technical issue.\nPlease send a Weps Error report",
//                        null, ERROR_MESSAGE, CANCEL_OPTION);
            }

            if (wepsRunDialog != null) {
                wepsRunDialog.setVisible(false);
            }

            throw new WrcException("WrcSimulationControl model invocation failed in background, model=" + errIdx, e).
                    addLog(LOGGER, "WrcSimulationControl model invocation failed in background, model=" + errIdx + ": " + e.getMessage()).
                    setType(e.getType()).setFatal(e.getFatal());
        }

        // MEH moved down here
        if (stopFlag) {
            bkgndShowWepsMessage(parent, "Abnormal Termination", "Run canceled by user " + runDir,
                    runDir, JOptionPane.ERROR_MESSAGE, OK_OPTION);
            aborted = true;
        } else if (rtnVal != 0) {
            bkgndShowWepsMessage(parent, "Abnormal Termination", "Error executing " + commandsArr[errIdx][0] + "\n" + "return value:" + rtnVal,
                    commandsArr[errIdx][0], JOptionPane.ERROR_MESSAGE, OK_OPTION);
            Mantis.message("WEPS Error", "Error executing " + commandsArr[errIdx][0], runDir);
            aborted = true;
        }

        writerStdOut.close();
        writerStdErr.close();

        bkgndDlgSetCancelEnabled(true);

        /* weps run completed successfully */
        if (rtnVal == 0 && !aborted) {
            TFile calibParmFile = new TFile(runDir, RunFileData.HarvCalibParmFileName);
            if (calibParmFile.exists() && calibParmFile.length() != 0) {
                displayCalibReport(calibParmFile, runDir);
            }
            //Display Dialog of warnings. and update the notes variable with each warning.
            if (localSimLog.getCount(WepsMessage.MessageSeverity.WARNING) > 0) {

                //runDialog.JTF_status.setText("Warnings...");
                this.bkgndDlgWriteStatus("Warnings...");
                notesText = "This WEPS Run generated one or more Warning messages. "
                        + "For detailed information about these Warnings, see this run's '"
                        + RunFileData.WarningsFile + "' output file.\n\n" + notesText;
                try {
                    try (BufferedWriter out = new BufferedWriter(
                            new TFileWriter(new TFile(runDir, RunFileData.WarningsFile)))) {
                        out.write("Project: " + CurrentProj);
                        out.newLine();
                        out.write("Run: " + runDir);
                        out.newLine();
                        out.write("Timestamp: " + new Date().toString());
                        out.newLine();
                        out.newLine();
                        for (WepsMessage message : localSimLog.getMessages(WepsMessage.MessageSeverity.WARNING)) {
                            out.write(message.toString());
                            out.newLine();
                        }
                    }

                } catch (IOException ioe) {
                    System.err.println("Error writing weps warnings to log file.");
                }
                bkgndShowWepsMessageList(null, "Warning Messages Generated", "", CurrentProj,
                        WepsMessageDialog.OK_OPTION, localSimLog.getMessages(WepsMessage.MessageSeverity.WARNING));
            }

            for (WepsMessage m : localSimLog.getMessages()) {
                if (m.getSeverity() == MessageSeverity.WARNING) {
                    LOGGER.warn(m.getMessage());
                } else {
                    LOGGER.info(m.getMessage());
                }
            }

            noteLock = false;
            runFileData.writeNotesFile(runDir);
            //Delete files we've been told are not needed after a good run.
            purgeRunFiles();
            //display each of the reports selected for immediate viewing
            String reportsToViewString = configData.getData(ConfigData.ReportsView);
            String[] reportsToView = reportsToViewString.split(",", -1);
            for (String reportName : reportsToView) {
                reportName = reportName.trim();
                if (reportName.length() > 0) {
                    //ReportPack pack = ReportManager.getDefault().getReportPack(new TFile(runDir), reportName);
                    //pack.startFill();
                    //ReportManager.getDefault().displayReport(runDir, reportName, Weps.getInstance().getRunFileData());
                    ReportManager.getDefault().displayReport(runDir, reportName);  // <--- this was commented out. not sure why above was used
                    //pack.close();
                    
                }
            }
            //create pdf's for all reports
            Thread task = new Thread("RunProgram pdfs") {
                int state = 0;

                @Override
                public void run() {
                    switch (state) {
                        case 0:
                            state = 1;
                            try {
                                EventQueue.invokeAndWait(this);
                            } catch (InterruptedException | InvocationTargetException ex) {
                            }
                            //This is where all reports are initially created 
                            String reportsToPDFString = configData.getData(ConfigData.ReportsGeneratePDF);
                            String[] reportsToPDF = reportsToPDFString.split(",", -1);
                            for (String reportName : reportsToPDF) {
                                reportName = reportName.trim();
                                //System.out.println("reportName: " + reportName);
                                if (reportName.length() > 0 /*&& reportName.equals("run")*/) {
                                    //System.out.println("running PDF..." +reportName);
                                    try {
                                        //locks used to help manage report generation and 
                                        //issues with executing threads concurrently
                                        rvLock.getrpMutex();
                                        rvLock.getrvMutex();
                                        //    ReportPack pack = ReportManager.getDefault().getReportPack(new TFile(runDir), reportName);
                                        ReportManager.getDefault().generateReportPDF(runDir, reportName, Weps.getInstance().getRunFileData());
                                        //ReportManager.getDefault().generateReportPDF(runDir, reportName);
                                        rvLock.setrpMutex();
                                        rvLock.setrvMutex();
                                    } catch (Throwable t) {
                                        LOGGER.error("Unable to generate \"" + reportName + "\".pdf.", t);
                                        // This JOptionPane call should be OK: this is in a (plain) thread, which ought ot already be on the EDT.
                                        JOptionPane.showMessageDialog(parent, "Unable to generate \"" + reportName
                                                + "\".", "PDF Error", JOptionPane.ERROR_MESSAGE);
                                    }
                                }
                            }
                            state = 2;
                            EventQueue.invokeLater(this);
                            return;

                        case 1:
                            wepsRunDialog.JTA_status.setText("Generating reports...");
                            return;

                        case 2:
                            wepsRunDialog.setVisible(false);
                            wepsRunDialog.dispose();
                            wepsRunDialog = null;
                            break;
                    }
                    ReportManager.getDefault().close();
                }
            };
            task.start();
            try {
                task.join();
            } catch (InterruptedException ex) {
                Exceptions.printStackTrace(ex);
            }
        }

        if ("on".equals(this.configData.getData(ConfigData.NRMVMode))
                || "summaries".equals(this.configData.getData(ConfigData.NRMVMode))) {
            System.out.println("running summaries...");
            ConvertAllToNrmv catn = new ConvertAllToNrmv(newDir, runDir);
            catn.shouldDoAverages("summaries".equals(this.configData.getData(ConfigData.NRMVMode)));
            catn.run();
        }

        return rtnVal;
    }

    @Override
    protected void done() {
        try {
            int rtnVal = get();

            changes.firePropertyChange(RunFileData.NotesText, null, notesText);
            changes.firePropertyChange(RunFileData.NotesText, null, oldNotes);
            changes.firePropertyChange(Weps.WEPS_RUNCREATED, null, runDir);
            changes.firePropertyChange(RunFileData.LastRun, null, new TFile(runDir).getAbsolutePath());

            if (rtnVal != 0) {
                wepsRunDialog.setVisible(false);
                wepsRunDialog.dispose();
                wepsRunDialog = null;
                changes.firePropertyChange(Weps.WEPS_RUNCREATED, null, runDir);
            }

            Weps.getInstance().removePropertyChangeListener(this);
        } catch (Exception ex) {
            Throwable cause = ex.getCause();
            // If format exception, just return to GUI
            if (cause instanceof WrcFormatException || cause instanceof NullPointerException) {
            } else if (ex instanceof WrcException || cause instanceof WrcException) {
                JOptionPane.showMessageDialog(Weps.getInstance(), 
                        "WEPS cloud simulation failed\n"+
                        "due to internet / connectivity issues\n"+
                        "The initial run data remains as it was before the cloud "+
                        "invocation and the run can be re-attempted at anytime", "Model Failure", JOptionPane.WARNING_MESSAGE);
                LOGGER.error("WEPS cloud simulation failed: ",ex);
            } else {
                // otherwise, throw new Runtime so that it will get posted to Mantis
                throw new RuntimeException("WrcSimulationControl failed, unexpected error, model=" + errIdx, ex);
            }
        } finally {
            System.gc();
        }
    }

    // These dlg functions are used by code running on the background threads.
    // Access from background thread to evt in SwingWorker is via firePropertyChange()
    // They are implemented in and received by an instance of WrcDialog.
    @Override
    public void bkgndDlgWriteWindMsg(String msg) {
        SwingWorker:
        firePropertyChange(propChangeCmdDlgBkgndWriteWindMsg, null, msg);
    }

    @Override
    public void bkgndDlgWriteCliMsg(String msg) {
        SwingWorker:
        firePropertyChange(propChangeCmdDlgBkgndWriteCliMsg, null, msg);
    }

    @Override
    public void bkgndDlgWriteWepsMsg(String msg) {
        SwingWorker:
        firePropertyChange(propChangeCmdDlgBkgndWriteWepsMsg, null, msg);
    }

    @Override
    public void bkgndDlgWriteMsg(int idx, String msg) {
        switch (idx) {
            case 0:
                bkgndDlgWriteWindMsg(msg);
                break;
            case 1:
                bkgndDlgWriteCliMsg(msg);
                break;
            case 2:
                bkgndDlgWriteWepsMsg(msg);
                break;
            default:
                bkgndDlgWriteStatus(msg);
        }
    }

    @Override
    public void bkgndDlgWriteStatus(String status) {
        if (status.length()>60) {
        int j=1;
        }
        status = status.substring(0, (status.length()>300)?300:status.length());
        SwingWorker:
        firePropertyChange(propChangeCmdDlgBkgndWriteStatusMsg, null, status);
    }

    @Override
    public void bkgndDlgSetPbarTotal(int totalYears) {
        SwingWorker:
        firePropertyChange(propChangeCmdDlgBkgndWritePbarTotalMsg, null, totalYears);
    }

    @Override
    public void bkgndDlgSetPbarCurrent(int currentYear) {
        SwingWorker:
        firePropertyChange(propChangeCmdDlgBkgndWritePbarCurMsg, null, currentYear);
    }

    @Override
    public void bkgndDlgSetCancelEnabled(boolean enabled) {
        SwingWorker:
        firePropertyChange(propChangeCmdDlgBkgndWriteCancelEnabledMsg, null, enabled);
    }

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

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

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

    @Override
    public void bkgndShowWepsMessage(Component parent, String title, String message, final String defaultFilePath, int messageType, int optionType) {
        WepsMessageDialog.showScrollableMessage(parent, title, message, defaultFilePath, messageType, optionType);
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        Object o;
        if ((o = evt.getNewValue()) != null) {
            switch (evt.getPropertyName()) {
                case WrcDialog.propChangeCmdStrWepsRunDlgClosed:
                    stopFlag = (boolean) o;
                    break;
            }
        }
    }

}