<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">package usda.weru.weps;

import com.vividsolutions.jts.geom.Coordinate;

import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.TFileInputStream;
import de.schlichtherle.truezip.file.TFileReader;

import java.awt.geom.Point2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import javax.measure.unit.NonSI;

import javax.swing.JOptionPane;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.log4j.Logger;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;
import org.jscience.geography.coordinates.LatLong;
import org.opengis.referencing.operation.MathTransform;
import org.openide.util.Exceptions;
import org.w3c.dom.Document;
import org.w3c.dom.DOMException;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;
import org.w3c.dom.traversal.DocumentTraversal;
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.traversal.TreeWalker;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

import usda.weru.gis.GISData;
import usda.weru.gis.GISLookup;
import usda.weru.mcrew.XMLConstants;
import usda.weru.mcrew.XMLDoc;
import usda.weru.util.About;
import usda.weru.util.Caster;
import usda.weru.util.ConfigData;
import usda.weru.util.FireAllContext;
import usda.weru.util.PropertyStackContext;
import usda.weru.util.Util;
import static usda.weru.weps.BarrierData.BARRIER;
import usda.weru.util.Pair;
import usda.weru.weps.archive.SubmodelOutput;
import usda.weru.weps.archive.RunFileData;
import usda.weru.weps.location.Site;
import usda.weru.weps.location.Station;
import usda.weru.weps.location.StationMode;
import usda.weru.weps.location.StationUtil;
import usda.weru.weps.location.mode.SimpleStationHelper;

/**
 * The "Run file Data" class/object manages, accesses, returns and updates data
 * for the WEPS application GUI where data modifications need to be propagated
 * to different screens that have registered their components to be recognized
 * for any property changes that happen.
 *
 */
public class RunFileDataXML implements PropertyChangeListener
{

    private static final Logger LOGGER = Logger.getLogger(RunFileDataXML.class);
    
    private RunXMLParser xmlParser;
    
    private StationMode cligenStationModeValue;
    private StationMode windgenStationModeValue;
    private Station cligenStationValue;
    private Station windgenStationValue;
    private Site&lt;?&gt; siteValue;
    
    private SimpleStationHelper statFinder = new SimpleStationHelper();

    /**
     *
     */
    protected boolean c_displayMessages = true;
    
    /**
     * The head and tail of the weps.run.xml.
     */
    private static final String RFDRoot = "runFileData";
    
    /**
     * Key used to identify parameters that have no bearing on reading or writing from
     * the interface, and do not affect the src.
     */
    public static final String INT = "internal";
    /**
     *  The key used to identify that a parameter is necessary for the weps executable.
     */
    public static final String SRC = "SCI_";
    /**
     * The key used to identify that a parameter is used for the weps interface.
     */
    public static final String GUI = "GUI_";
    /**
     * The username to be used in the application
     */
    public static final String UserName = GUI + "UserName";
    /**
     * The farm identification number. Often an individual operator will have
     * more than one farm and therefore more than one farm number. It is saved
     * as part of the WEPS Run and appears on the summary and other output
     * reports. This information is not required for a simulation run but may be
     * useful in identifying specific WEPS Runs and output
     */
    public static final String FarmId = GUI + "FarmId";
    /**
     * Often used by FSA and NRCS to identify a field. It is a unit of
     * contiguous land that has both of the following: (1) under one ownership,
     * and (2) operated as a farm or a part of a farm. It is saved as part of a
     * WEPS Run and appears on the summary and other output reports. This
     * information is not required for a simulation run but may be useful in
     * identifying specific WEPS Runs and output.
     */
    public static final String TractId = GUI + "TractId";
    /**
     * The "Field No." is a part of a tract that is separated by permanent
     * boundaries, such as: (1) fences, (2) permanent waterways, (3) woodlands,
     * (4) croplines not subject to change because of farming practices, and (5)
     * other similar features. It is saved as part of the WEPS Run and appears
     * on the summary and other output reports. This information is not required
     * for a simulation run but may be useful in identifying specific WEPS Runs
     * and output
     */
    public static final String FieldId = GUI + "FieldId";
    /**
     * String used to identify the run type to be displayed.
     */
    public static final String RunTypeDisp = GUI + "RunTypeDisp";
    /**
     * The number of years in which the crop cycle needs to be rotated.
     */
    public static final String RotationYears = GUI + "RotationYears";
    /**
     * The current count before the cycle is started over again.
     */
    public static final String CycleCount = SRC + "CycleCount";
    public static final String Site = GUI + "Site";
    public static final String StrLatLong = SRC + "LatLong";
    private static final String Elevation = SRC + "Elevation";
    public static final String ClimateFlag = GUI + "ClimateFlag";
    public static final String CligenStation = GUI + "cligen.station";
    public static final String WindFlag = GUI + "WindFlag";
    public static final String WindgenStation = GUI + "windgen.station";  //handled by the mode
    /**
     * The date from which you want the simulation to begin.
     */
    public static final String StartDate = SRC + "StartDate";
    /**
     * The date on which you want the simulation to end.
     */
    public static final String EndDate = SRC + "EndDate";
    /**
     * The steps in which you can increment the time interval.
     */
    private static final String TimeSteps = SRC + "TimeSteps";
    /**
     * The name of the climate file.
     */
    //@Deprecated
    public static final String ClimateFile = SRC + "climateFile";
    /**
     * The name of the wind file.
     */
    //@Deprecated
    public static final String WindFile = SRC + "windFile";
    /**
     * The name of the sub-daily file.
     */
    private static final String SubDailyFile = SRC + "subDailyFile";
    /** ???? */
    public static final String ErosionSubmodelOutput = SRC + "ErosionSubmodelOutput";
    /**
     * Indicates the simulation region angle assigned.
     */
    public static final String RegionAngle = SRC + "RegionAngle";
    /**
     * Origin Coordinate.  May be useless
     */
    public static final String XOrigin = SRC + "XOrigin";
    public static final String YOrigin = SRC + "YOrigin";
    /**
     * 
     */
    public static final String XGrid = SRC + "XGrid";
    public static final String YGrid = SRC + "YGrid";
    /** ???? */
    public static final String AccNo = SRC + "AccNo";
    /**
     * Keeps track of the number of subregions, so the science code knows how much
     * memory to allocate.
     */
    public static final String SubHead = SRC + "Subregions";
    /**
     * This key is used to identify the start of a subregion block:  It will create
     * a subregion object to accept the Subregion values after seeing this tag, and
     * print this tag before a dump of the subregion object.
     */
    public static final String SubKey = SRC + "Subregion";
    /**
     * Keeps track of the number of barriers, so the science code knows how much
     * memory to allocate.
     */
    public static final String BarHead = SRC + "Barriers";
    /**
     * This key is used to identify the start of a barrier block:  It will create
     * a barrier object to accept the barrier values after seeing this tag and print
     * this tag before a dump of the subregion object.
     */
    public static final String BarKey= SRC + "Barrier";
    /**
     * Area of the simulation region in the units of measure displayed on the
     * screen (acres or hectares) based upon the "X" length and "Y" length
     * values. X-Length happens to be the breadth of the field.
     */
    public static final String XLength = SRC + "XLength";
    /**
     * Area of the simulation region in the units of measure displayed on the
     * screen (acres or hectares) based upon the "X" length and "Y" length
     * values. Y-Length happens to be the length of the field.
     */
    public static final String YLength = SRC + "YLength";
    
    public static final String PASSMINBOX = "RFD.mbb";
    public static final String PASSSELECTION = "RFD.select";
    public static final String PASSAUXINIT = "RFD.auxinit";
    public static final String POSTMANFILE = "RFD.manFileCommit";
    public static final String POSTSOILFILE = "RFD.soilFileCommit";
    public static final String PASSPOINTSINIT = "RFD.initializepolygons";
    public static final String DELETION = "RFD.delete event";
    
    public static final String RunsLocation = "archivedRunLocation";
    /**
     * Tells the user what the last WEPS run was by storing its name.
     */
    public static final String LastRun = "lastrun";
    /**
     * The name used to register notes data changes.
     */
    public static final String NotesText = "Notes.txt conent change";
    /**
     * Default name for the soil file to be used in SOIL UI.
     */
    public static final String DefaultSoilFileName = "none";
    /**
     * Default name for the management file to be used in MCREW.
     */
    public static final String DefaultManageFileName = "none";
    ////////////////////////////////////////////////////////////////////////////
    /*                            BEGIN FILE NAMES                            */
    /**
     * The WEPS data file used to store all the initialization information for
     * the GUI when it's first executed.
     */
    public static final String WepsData = "weps.ini";
    /**
     *
     */
    public static final String WarningsFile = "warnings.txt";
    /**
     * Default name to be assigned to a new project if saved without any name.
     */
    public static final String UntitledProject = "untitled.wpj";
    /**
     * The wind generation file's default name with a ".win" extension for the
     * file to be recognized
     */
    public static final String DefaultWinGenName = "win_gen.win";
    /**
     * The climate generation file's default name with a ".cli" extension for
     * the file to be recognized
     */
    public static final String DefaultCliGenName = "cli_gen.cli";
    /**
     * Data file name for the WEPS GUI related stored data
     */
    public static final String WepsOutput = "gui1_data.out";
    /**
     * The output file for the calibration mode parameter for the harvest file.
     */
    public static final String CalibFileName = "harvest_calib_parm.out";
    /**
     * name of the Notes text file used to save management file level notes or
     * notes from the notes section provided in the WEPS screen.
     */
    public static final String NotesFileName = "notes.txt";
    /**
     * All the "RUN" files have this extension after their file names i:e file
     * extension to be used.
     */
    public static final String RunSuffix = ".wjr";
    /**
     * All the project files have this extension after the file names i:e file
     * extension to be used.
     */
    public static final String ProjectSuffix = ".wpj";
    /**
     * Error file name to be used for re-directing the erros codes or messages
     * if any generated.
     */
    public static final String StdErr = "stderr.txt";
    /**
     * The text messages from the standard output such as screns dialogs which
     * need to be saved are directed to this file.
     */
    public static final String StdOut = "stdout.txt";
    
    public static final String INDEX = SRC + "index";
    public static final String NUMBER = SRC + "number";
    public static final String XCOORD = SRC + "x";
    public static final String YCOORD = SRC + "y";
    public static final String LATITUDE = GUI + "lat";
    public static final String LONGITUDE = GUI + "lon";
    public static final String COORD = SRC + "coord";
    public static final String COORDINATEHEAD = SRC + "coords";
    /*                            END FILE NAMES                              */
    ////////////////////////////////////////////////////////////////////////////
    private boolean wasCircle = false;

    /**
     * Hashtable used to store weps.run file data internally
     */
    protected Hashtable&lt;String, String&gt; data = new Hashtable&lt;&gt;(200);
    protected List&lt;BarrierData&gt; barriers = null;
    protected List&lt;SubregionData&gt; subregions = null;
    public TFile fileObject;
    
    Hashtable&lt;String, String&gt; archive = new Hashtable&lt;&gt;(50);
    
    private static final String[] printOrder = { UserName, FarmId, TractId, FieldId, 
        RunTypeDisp, RotationYears, CycleCount, Site, StrLatLong, Elevation, ClimateFlag,
        CligenStation, WindFlag, WindgenStation, StartDate, EndDate, TimeSteps, ClimateFile, 
        WindFile, SubDailyFile, ErosionSubmodelOutput, RegionAngle, XOrigin, YOrigin, 
        XLength, YLength, XGrid, YGrid };
    
    private static final String[] archiveKeys = { LastRun };
    

    /**
     * This methods reads the data from the WEPS.ini file and shows it. Errors
     * will be shown in a WepsMessageDialog
     *
     * @param pathName The path where this file resides on the system.
     */
    public RunFileDataXML(String pathName) {
        this(pathName, true);
    }

    /**
     * This method reads the data from the WEPS.ini file and shows it.
     *
     * @param pathName The path where this file resides on the system.
     * @param displayMessages If true, errors and warnings will be displayed in
     * a WepsMessageDialog.
     */
    public RunFileDataXML(String pathName, boolean displayMessages) {
        c_displayMessages = displayMessages;
        readWepsRunXML(pathName);
    }

    /**
     * Initializes the WEPS RUN data.
     */
    public RunFileDataXML() {
        this(false);
    }

    /**
     *
     * @param initialize
     */
    public RunFileDataXML(boolean initialize) {
        subregions = new ArrayList&lt;SubregionData&gt;();
        barriers = new ArrayList&lt;BarrierData&gt;();
        if (initialize) {
            initialize();
        }
    }

    /**
     * This is the method where all the WEPS main GUI initialization takes place
     * with the default dataset used for initial display.
     */
    public void initialize() {
        setData(UserName, "");
        setData(FarmId, "");
        setData(TractId, "");
        setData(FieldId, "");
        setData(RunTypeDisp, "cycle");
        setData(RotationYears, "1");
        setData(CycleCount, "50");
        setData(Site, "fips:US00-KS-055");
        setData(StrLatLong, "+37.73835;-100.43785");
        setData(Elevation, "801.0");
        setData(ClimateFlag, "choice");
        setData(CligenStation, "cligen|+46.75;-118.617|45|3546|HATTON 10 E|417.0");
	setData(WindFlag, "choice");
	setData(WindgenStation, "windgen|+46.267;-119.117|727845|US|WA|PASCO/TRI-CITIES");
	setData(StartDate, "01 01 0001");
	setData(EndDate, "31 12 0840");
	setData(TimeSteps, "24");
	setData(ClimateFile, "cligen.cli");
	setData(WindFile, "win_gen.win");
	setData(ErosionSubmodelOutput, "0");
	setData(RegionAngle, "0.0");
	setData(XOrigin, "0.0");
	setData(YOrigin, "0.0");
	setData(XLength, "365.76");
	setData(YLength, "365.76");
        
        subregions.add(new SubregionData(subregions.size()));

    }

    /**
     *
     * @param idxstr
     * @return
     */
    public String getData(String idxstr) 
    {
        String val = data.get(idxstr);
        if(val != null) return val;
        val = archive.get(idxstr);
        if(val != null) return val;
        return "";
    }

    public boolean wasCircle() { return wasCircle; }
    
    /**
     *
     * @param idxstr
     * @param newData
     * @param trimNewData
     */
    public void setData(final String idxstr, String newData, boolean trimNewData) {

        PropertyStackContext.enter(this, idxstr);
        try {
            String oldData;
            if(idxstr.equals(ErosionSubmodelOutput))
            {
                try 
                { 
                    int tocheck = Integer.parseInt(newData); 
                    if((tocheck &lt; 0) || (tocheck &gt; 15)) 
                    {
                        LOGGER.error("Trying to set erosion output at invalid value");
                        return;
                    }
                }
                catch(NumberFormatException nfe) {}
            }

            if (newData == null) {
                oldData = data.get(idxstr);
                data.remove(idxstr);
            } else {
                if (trimNewData) {
                    newData = newData.trim();      //1148, only trim when told to.
                }
                oldData = data.get(idxstr);
                if (newData.equals(oldData)) {
                    return;
                }
                data.put(idxstr, newData);
            }

        } finally {
            PropertyStackContext.exit(this, idxstr);
        }

    }

    //1148, overiding method to pass a default true for trimNewData
    /**
     *
     * @param idxstr
     * @param newData
     */
    public void setData(String idxstr, String newData) {
        setData(idxstr, newData, true);
    }

    /**
     * Sets data to be used in restoring from a .ini file.
     * @param idxstr
     * @param newData 
     */
    public void setArchiveData(final String idxstr, String newData) 
    {

        PropertyStackContext.enter(this, idxstr);
        try {
            String oldData;
            if (newData == null) {
                oldData = archive.get(idxstr);
                archive.remove(idxstr);
            } else {
                oldData = archive.get(idxstr);
                if (newData.equals(oldData)) {
                    return;
                }
                archive.put(idxstr, newData);
            }
            changes.firePropertyChange(idxstr, oldData, newData);
        } finally {
            PropertyStackContext.exit(this, idxstr);
        }

    }
    
    public StationMode getCligenStationMode() { return cligenStationModeValue; }
    public Station getCligenStation() { return cligenStationValue; }
    public StationMode getWindgenStationMode() { return windgenStationModeValue; }
    public Station getWindgenStation() { return windgenStationValue; }
    
    /**
     * Sets the integer value to the rotation year's attribute from the
     * management file provided as an argument path where it exists on the
     * system.
     *
     * @param manageFile The management file that stores this integer value that
     * is used for setting.
     */
    // throws a warning when we manually close 'in'.
    @SuppressWarnings("try")
    public void setRotationYears(String manageFile) {
        //We need to have a file to work with.
        if (manageFile == null || manageFile.equals("none") || manageFile.length() == 0) {
            return;
        }

        try (BufferedReader in = new BufferedReader(new TFileReader(
                new TFile(manageFile)))) {
            String temp;
            while ((temp = in.readLine()) != null) {
                if (temp.startsWith("*START")) {
                    StringTokenizer st = new StringTokenizer(temp);
                    st.nextToken();
                    String rotationYears = st.nextToken().trim();
                    in.close();
                    setData(RunFileDataXML.RotationYears, rotationYears);
                    return;
                }
            }


        } catch (IOException e) { }
    }
    
    public void setLatLonPoints(List&lt;List&lt;Coordinate&gt;&gt; latLon, List&lt;List&lt;Point2D.Double&gt;&gt; xy)
    {
        if(latLon.size() != xy.size()) throw new RuntimeException("Coordinate Lists not of the same size.");
        for(int index = 0; index &lt; latLon.size(); index ++)
        {
            if(latLon.get(index).size() != xy.get(index).size()) throw new RuntimeException("Coordinate Lists not of the same size.");
            subregions.get(index).setCoordinate(latLon.get(index), xy.get(index));
        }
    }

    /**
     * This method reads the data in the RUN file meant for the GUI
     * initialization from the existing set of values and makes it visible on
     * the respective components of the interface.
     *
     * @param runFilePathName The system path to the RUN file from where this
     * data is retrieved.
     */
    static boolean lockMessage = true;

    void setLockMessage(boolean bool) {
        lockMessage = bool;
    }

    boolean getLockMessage() {
        return lockMessage;
    }
    
    public static RunFileDataXML convertOldWepsRun(RunFileData other, boolean ini)
    {
        RunFileDataXML xml = new RunFileDataXML();
        xml.convertOldWepsRunInPlace(other, ini);
        return xml;
    }
    
    public void convertOldWepsRunInPlace(RunFileData other, boolean ini)
    {
        //&lt;editor-fold defaultstate="collapsed" desc="Initial Block Conversion"&gt;
        {
            setData(UserName, other.getData(RunFileData.UserName));
            setData(FarmId, other.getData(RunFileData.FarmId));
            setData(TractId, other.getData(RunFileData.TractId));
            setData(FieldId, other.getData(RunFileData.FieldId));
            setData(RunTypeDisp, other.getData(RunFileData.RunTypeDisp));
            setData(RotationYears, other.getData(RunFileData.RotationYears));
            setData(CycleCount, other.getData(RunFileData.CycleCount));
            setData(Site, other.getData(RunFileData.Site));
            {
                String temp = other.getData(RunFileData.StrLatLong);
                temp = temp.replace(';', ' ');
                setData(StrLatLong, temp);
            }
            setData(Elevation, other.getData(RunFileData.Elevation));
            setData(ClimateFlag, other.getData(RunFileData.CligenModeText));
            {
                String cligenMode = other.getData(RunFileData.CligenModeText);
                cligenStationModeValue = StationMode.parse(cligenMode);
                String cligenStation = other.getData(RunFileData.CligenStationText);
                cligenStationValue = StationUtil.deserializeStation(cligenStation);
                setData(CligenStation, cligenStation);
            }
            setData(WindFlag, other.getData(RunFileData.WindgenModeText));
            setData(WindgenStation, other.getData(RunFileData.WindgenStationText));
            setData(StartDate, other.getData(RunFileData.StartDate));
            setData(EndDate, other.getData(RunFileData.EndDate));
            setData(TimeSteps, other.getData(RunFileData.TimeSteps));
            setData(ClimateFile, other.getData(RunFileData.ClimateFile));
            setData(WindFile, other.getData(RunFileData.WindFile));
            setData(SubDailyFile, other.getData(RunFileData.SubDailyFile));
            {
                setData(ErosionSubmodelOutput, other.so.getSubmodelOutput(SubmodelOutput.submodel.Erosion));
            }
            setData(RegionAngle, other.getData(RunFileData.RegionAngle));
            setData(XOrigin, "0.0");
            setData(YOrigin, "0.0");
            setData(XLength, other.getData(RunFileData.XLength));
            setData(YLength, other.getData(RunFileData.YLength));
            setData(XGrid, "0");
            setData(YGrid, "0");
        }
        
        //&lt;/editor-fold&gt;
        if(other.getData(RunFileData.Shape).toLowerCase().contains("circle"))
        {
            JOptionPane.showMessageDialog(null, "The original weps.run file used"
                    + " a circular field.\nTo keep the field consistant, the new"
                    + " file will use the representative rectangle generated previously.\n"
                    + "To make a circular field, you must manually draw it.", 
                    "Circular Field", JOptionPane.WARNING_MESSAGE);
            wasCircle = true;
        }
        double angle = Double.parseDouble(other.getData(RunFileData.RegionAngle));
        //&lt;editor-fold defaultstate="collapsed" desc="Subregion Conversion"&gt;
        {
            subregions = new ArrayList&lt;SubregionData&gt;(1);
            SubregionData sub = new SubregionData(subregions.size());
            sub.dataChange(SubregionData.SUBMODELMASK + SubregionData.HYDROOUTPUT, Integer.parseInt(other.so.getSubmodelOutput(SubmodelOutput.submodel.Hydrology)), 0);
            sub.dataChange(SubregionData.SUBMODELMASK + SubregionData.SOILOUTPUT, Integer.parseInt(other.so.getSubmodelOutput(SubmodelOutput.submodel.Soil)), 0);
            sub.dataChange(SubregionData.SUBMODELMASK + SubregionData.MANOUTPUT, Integer.parseInt(other.so.getSubmodelOutput(SubmodelOutput.submodel.Management)), 0);
            sub.dataChange(SubregionData.SUBMODELMASK + SubregionData.CROPOUTPUT, Integer.parseInt(other.so.getSubmodelOutput(SubmodelOutput.submodel.Crop)), 0);
            sub.dataChange(SubregionData.SUBMODELMASK + SubregionData.DECOMPOUTPUT, Integer.parseInt(other.so.getSubmodelOutput(SubmodelOutput.submodel.Decomposition)), 0);
            for(String out : SubregionData.outputOrder)
            {
                sub.dataChange(SubregionData.DEBUGMASK + out, 0, 0);
            }
            sub.dataChange(SubregionData.AVSLOPE, Double.parseDouble(other.getData(RunFileData.AverageSlope)), 0);
            sub.dataChange(SubregionData.ROCKFRAG, Double.parseDouble(other.getData(RunFileData.SoilRockFragments)), 0);
            sub.dataChange(SubregionData.SOILFILE, other.getData(RunFileData.SoilFile), 0);
            sub.dataChange(SubregionData.MANFILE, other.getData(RunFileData.ManageFile), 0);
            sub.dataChange(SubregionData.WATERLOSS, Double.parseDouble(other.getData(RunFileData.WaterErosionLoss)), 0);
            double xlen = Double.parseDouble(getData(XLength));
            double ylen = Double.parseDouble(getData(YLength));
            List&lt;Pair&lt;Double, Double&gt;&gt; coordinates = new ArrayList&lt;Pair&lt;Double, Double&gt;&gt;();
            List&lt;Coordinate&gt; latLongs = new ArrayList&lt;Coordinate&gt;();
            Pair&lt;Double, Double&gt; point = new Pair&lt;Double, Double&gt;();
            point.left = 0.0;
            point.right = 0.0;
            coordinates.add(point);
            latLongs.add(backConvert(point.left, point.right, angle, other.getData(RunFileData.StrLatLong)));
            point = new Pair&lt;Double, Double&gt;();
            point.left = xlen;
            point.right = 0.0;
            coordinates.add(point);
            latLongs.add(backConvert(point.left, point.right, angle, other.getData(RunFileData.StrLatLong)));
            point = new Pair&lt;Double, Double&gt;();
            point.left = xlen;
            point.right = ylen;
            coordinates.add(point);
            latLongs.add(backConvert(point.left, point.right, angle, other.getData(RunFileData.StrLatLong)));
            point = new Pair&lt;Double, Double&gt;();
            point.left = 0.0;
            point.right = ylen;
            coordinates.add(point);
            latLongs.add(backConvert(point.left, point.right, angle, other.getData(RunFileData.StrLatLong)));
            sub.setCoordinate(latLongs, coordinates, true);
            subregions.add(sub);
        }
        //&lt;/editor-fold&gt;
        //&lt;editor-fold defaultstate="collapsed" desc="Barrier Conversion"&gt;
        {
            barriers = new ArrayList&lt;BarrierData&gt;();
            double xlen = Double.parseDouble(getData(XLength));
            double ylen = Double.parseDouble(getData(YLength));
            Barrier old;
            if(!other.getData(RunFileData.BarrierN).toLowerCase().startsWith("none"))
            {
                old = new Barrier(other.getData(RunFileData.BarrierN));
                BarrierData north = new BarrierData(1, 2, barriers.size());
                north.dataChange(0, 0, BarrierData.COORDTRANSWIDTH, old.wid);
                north.dataChange(0, 1, BarrierData.COORDTRANSWIDTH, old.wid);
                north.dataChange(0, 0, BarrierData.COORDTRANSHEIGHT, old.hgt);
                north.dataChange(0, 1, BarrierData.COORDTRANSHEIGHT, old.hgt);
                north.dataChange(0, 0, BarrierData.COORDTRANSPOROSITY, old.por);
                north.dataChange(0, 1, BarrierData.COORDTRANSPOROSITY, old.por);
                north.dataChange(0, 0, XCOORD, xlen);
                north.dataChange(0, 0, YCOORD, ylen);
                north.dataChange(1, 0, XCOORD, 0.0);
                north.dataChange(1, 0, YCOORD, ylen);
                Coordinate singleLL = backConvert(xlen, ylen, angle, other.getData(RunFileData.StrLatLong));
                north.dataChange(0, 0, LATITUDE + LONGITUDE, singleLL);
                singleLL = backConvert(0.0, ylen, angle, other.getData(RunFileData.StrLatLong));
                north.dataChange(1, 0, LATITUDE + LONGITUDE, singleLL);
                north.dataChange(0, 0, BarrierData.FLAG, BarrierData.SwitchingMech.POINTS.id);
                north.dataChange(0, 0, BarrierData.TRANSITIONTIMEMARK, 1);
                north.dataChange(0, 0, BarrierData.TRANSITIONTIMEDESC, old.name);
                barriers.add(north);
            }
            if(!other.getData(RunFileData.BarrierE).toLowerCase().startsWith("none"))
            {
                old = new Barrier(other.getData(RunFileData.BarrierE));
                BarrierData east = new BarrierData(1, 2, barriers.size());
                east.dataChange(0, 0, BarrierData.COORDTRANSWIDTH, old.wid);
                east.dataChange(0, 1, BarrierData.COORDTRANSWIDTH, old.wid);
                east.dataChange(0, 0, BarrierData.COORDTRANSHEIGHT, old.hgt);
                east.dataChange(0, 1, BarrierData.COORDTRANSHEIGHT, old.hgt);
                east.dataChange(0, 0, BarrierData.COORDTRANSPOROSITY, old.por);
                east.dataChange(0, 1, BarrierData.COORDTRANSPOROSITY, old.por);
                east.dataChange(0, 0, XCOORD, xlen);
                east.dataChange(0, 0, YCOORD, 0.0);
                east.dataChange(1, 0, XCOORD, xlen);
                east.dataChange(1, 0, YCOORD, ylen);
                Coordinate singleLL = backConvert(xlen, 0.0, angle, other.getData(RunFileData.StrLatLong));
                east.dataChange(0, 0, LATITUDE + LONGITUDE, singleLL);
                singleLL = backConvert(xlen, ylen, angle, other.getData(RunFileData.StrLatLong));
                east.dataChange(1, 0, LATITUDE + LONGITUDE, singleLL);
                east.dataChange(0, 0, BarrierData.FLAG, BarrierData.SwitchingMech.POINTS.id);
                east.dataChange(0, 0, BarrierData.TRANSITIONTIMEMARK, 1);
                east.dataChange(0, 0, BarrierData.TRANSITIONTIMEDESC, old.name);
                barriers.add(east);
            }
            if(!other.getData(RunFileData.BarrierS).toLowerCase().startsWith("none"))
            {
                old = new Barrier(other.getData(RunFileData.BarrierS));
                BarrierData south = new BarrierData(1, 2, barriers.size());
                south.dataChange(0, 0, BarrierData.COORDTRANSWIDTH, old.wid);
                south.dataChange(0, 1, BarrierData.COORDTRANSWIDTH, old.wid);
                south.dataChange(0, 0, BarrierData.COORDTRANSHEIGHT, old.hgt);
                south.dataChange(0, 1, BarrierData.COORDTRANSHEIGHT, old.hgt);
                south.dataChange(0, 0, BarrierData.COORDTRANSPOROSITY, old.por);
                south.dataChange(0, 1, BarrierData.COORDTRANSPOROSITY, old.por);
                south.dataChange(0, 0, XCOORD, 0.0);
                south.dataChange(0, 0, YCOORD, 0.0);
                south.dataChange(1, 0, XCOORD, xlen);
                south.dataChange(1, 0, YCOORD, 0.0);
                Coordinate singleLL = backConvert(0.0, 0.0, angle, other.getData(RunFileData.StrLatLong));
                south.dataChange(0, 0, LATITUDE + LONGITUDE, singleLL);
                singleLL = backConvert(xlen, 0.0, angle, other.getData(RunFileData.StrLatLong));
                south.dataChange(1, 0, LATITUDE + LONGITUDE, singleLL);
                south.dataChange(0, 0, BarrierData.FLAG, BarrierData.SwitchingMech.POINTS.id);
                south.dataChange(0, 0, BarrierData.TRANSITIONTIMEMARK, 1);
                south.dataChange(0, 0, BarrierData.TRANSITIONTIMEDESC, old.name);
                barriers.add(south);
            }
            if(!other.getData(RunFileData.BarrierW).toLowerCase().startsWith("none"))
            {
                old = new Barrier(other.getData(RunFileData.BarrierW));
                BarrierData west = new BarrierData(1, 2, barriers.size());
                west.dataChange(0, 0, BarrierData.COORDTRANSWIDTH, old.wid);
                west.dataChange(0, 1, BarrierData.COORDTRANSWIDTH, old.wid);
                west.dataChange(0, 0, BarrierData.COORDTRANSHEIGHT, old.hgt);
                west.dataChange(0, 1, BarrierData.COORDTRANSHEIGHT, old.hgt);
                west.dataChange(0, 0, BarrierData.COORDTRANSPOROSITY, old.por);
                west.dataChange(0, 1, BarrierData.COORDTRANSPOROSITY, old.por);
                west.dataChange(0, 0, XCOORD, 0.0);
                west.dataChange(0, 0, YCOORD, ylen);
                west.dataChange(1, 0, XCOORD, 0.0);
                west.dataChange(1, 0, YCOORD, 0.0);
                Coordinate singleLL = backConvert(0.0, ylen, angle, other.getData(RunFileData.StrLatLong));
                west.dataChange(0, 0, LATITUDE + LONGITUDE, singleLL);
                singleLL = backConvert(0.0, 0.0, angle, other.getData(RunFileData.StrLatLong));
                west.dataChange(1, 0, LATITUDE + LONGITUDE, singleLL);
                west.dataChange(0, 0, BarrierData.FLAG, BarrierData.SwitchingMech.POINTS.id);
                west.dataChange(0, 0, BarrierData.TRANSITIONTIMEMARK, 1);
                west.dataChange(0, 0, BarrierData.TRANSITIONTIMEDESC, old.name);
                barriers.add(west);
            }
        }
        
        //&lt;/editor-fold&gt;
        if(ini) archive.put(LastRun, other.getData(RunFileData.LastRun));
        else archive.put(LastRun, other.fileObject.getParentFile().getName());
    }
    
    public void readWepsRunXML(String pFileName)
    {
        try
        {
            if(pFileName.endsWith(RunFileDataXML.ProjectSuffix))
            {
                readIni(pFileName);
                return;
            }
            fileObject = new TFile(pFileName);
            if(pFileName.endsWith(RunFileDataXML.RunSuffix))
            {
                if(!fileObject.exists()) fileObject.mkdir();
                pFileName += TFile.separator + "weps.run.xml";
                fileObject = new TFile(pFileName);
                if(!fileObject.exists())
                {
                    pFileName = pFileName.substring(0, pFileName.length() - 4);
                    fileObject = new TFile(pFileName);
                    if(!fileObject.exists()) throw new UnsupportedOperationException("Unsupported RunFile format.");
                    else
                    {
                        RunFileData archive = new RunFileData();
                        archive.readRunData(pFileName);
                        convertOldWepsRunInPlace(archive, false);
                        return;
                    }
                }
            }
            if(xmlParser == null)
            {
                xmlParser = new RunXMLParser();
            }
            xmlParser.readWepsRunXML(pFileName);
        }
        finally
        {
            //I think it's important to commit Aux first.
            commitAux();
            passInitialPoints();
        }
    }

    public void writeWepsRunXML(String pFileName)
    {
        if(pFileName.endsWith(RunFileDataXML.ProjectSuffix))
        {
            writeIni(pFileName);
            return;
        }
        if(pFileName.endsWith(RunFileDataXML.RunSuffix))
        {
            TFile rundir = new TFile(pFileName);
            if(!rundir.exists()) rundir.mkdir();
            pFileName += TFile.separator + "weps.run.xml";
        }
        if(xmlParser == null)
        {
            xmlParser = new RunXMLParser();
        }
        xmlParser.writeWepsRunXML(pFileName);
    }
    public void writeIni(String projectDirectory)
    {
        if(xmlParser == null)
        {
            xmlParser = new RunXMLParser();
        }
        xmlParser.writeIni(projectDirectory);
    }
    
    public void readIni(String projectDirectory)
    {
        if(xmlParser == null)
        {
            xmlParser = new RunXMLParser();
        }
        xmlParser.readIni(projectDirectory);
    }
    
    /**
     * Removes the files/directories that contain the RUN data.
     *
     * @param dir The directory that contains the RUN data that will be removed.
     * @return True if the directory is deleted else false.
     */
    public boolean removeRunData(TFile dir) { return Util.deleteAll(dir); }
    
    private void fillNode(Node top, Document doc)
    {
        for(String name : printOrder)
        {
            if(data.get(name) == null) continue;
            Node workNode;
            workNode = doc.createElement(name);
            XMLDoc.setTextData(workNode, data.get(name), doc);
            top.appendChild(workNode);
        }
        //Add Accounting Regions
        Node workNode = doc.createElement(SubHead);
        if(subregions != null)
        {
            ((Element) workNode).setAttribute(NUMBER, Integer.toString(subregions.size()));
            for(SubregionData sub : subregions) 
            {
                Node top2 = doc.createElement(SubKey);
                sub.fillNode(top2, doc);
                workNode.appendChild(top2);
            }
        }
        else ((Element) workNode).setAttribute(NUMBER, Integer.toString(0)); 
        top.appendChild(workNode);
        workNode = doc.createElement(BarHead);
        if(barriers != null)
        {
            ((Element) workNode).setAttribute(NUMBER, Integer.toString(barriers.size()));
            for(BarrierData bar : barriers) 
            {
                Node top2 = doc.createElement(BARRIER);
                bar.fillNode(top2, doc);
                workNode.appendChild(top2);
            }
        }
        else ((Element) workNode).setAttribute(NUMBER, Integer.toString(0));
        top.appendChild(workNode);
    }
    
    private Coordinate backConvert(double x, double y, double angle, String originLL)
    {
        String[] xy = originLL.split(";");
        Coordinate coord = new Coordinate(Double.parseDouble(xy[1]), Double.parseDouble(xy[0]));
        double origx = 0;
        double origy = 0;
        try
        {
            MathTransform transform = CRS.findMathTransform(CRS.decode("EPSG:4326"), CRS.decode("EPSG:3857"), false);
            JTS.transform(coord, coord, transform);
            origx = coord.x;
            origy = coord.y;
        }
        catch(Exception e){}
        double xPrime = (x) * Math.cos(angle) - (y) * Math.sin(angle);
        double yPrime = (y) * Math.cos(angle) + (x) * Math.sin(angle);
        xPrime += origx;
        yPrime += origy;
        coord.x = xPrime;
        coord.y = yPrime;
        try
        {
            MathTransform transform = CRS.findMathTransform(CRS.decode("EPSG:3857"), CRS.decode("EPSG:4326"), false);
            JTS.transform(coord, coord, transform);
        }
        catch(Exception e){}
        return coord;
    }
    
    /**
     * This method updates to the newly inserted date values in the dates column
     * of the interface.
     */
    public String updateDates() {
        String runType = getData(RunTypeDisp);
        if (runType.equals(ConfigData.Dates)) {
            String sD = getData(StartDate);
            // //System.out.println("RFD_uD: START DATE is :" + sD);  // TESTING
            String eD = getData(EndDate);
            // //System.out.println("RFD_uD: END DATE is :" + eD);  // TESTING
            StringTokenizer st = new StringTokenizer(sD);
            st.nextToken();
            st.nextToken();
            sD = st.nextToken();
            //System.out.println("RFD_uD: START DATE after TOKEN is :" + sD); // TESTING
            st = new StringTokenizer(eD);
            st.nextToken();
            st.nextToken();
            eD = st.nextToken();
            //System.out.println("RFD_uD: END DATE after TOKEN is :" + eD); // TESTING
            String totYrs = "" + ((Integer.parseInt(eD) - Integer.parseInt(sD)) + 1);
            //System.out.println("RFD_uD: Total Years are :" + totYrs); // TESTING
            return totYrs;
        } else {
            if (runType.equals(ConfigData.NRCS)) {
                setData(CycleCount, ConfigData.getDefault().getData(ConfigData.NRCSRunLen));
            }
            setData(StartDate, "01 01 01");
            String numYrs = getData(RotationYears);
            String numCyl = getData(CycleCount);
            int nY = Integer.parseInt(numYrs);
            int nC = Integer.parseInt(numCyl);
            setData(EndDate, "31 12 " + (nY * nC));
            String totYrs = "" + (nY * nC);
            return totYrs;
        }

    }

    @Override
    public void propertyChange(PropertyChangeEvent pce) 
    {
        switch(pce.getPropertyName())
        {
            case PASSSELECTION:
                System.out.println("Selection/addition");
                if(pce.getNewValue() instanceof Integer)
                {
                    int index = (Integer) pce.getNewValue();
                    if(index &gt; subregions.size()) LOGGER.error("Given out of bounds index to add/edit a subregion.");
                    if(index == subregions.size()) 
                    {
                        subregions.add(new SubregionData(subregions.size()));
                    }
                }
                else LOGGER.error("Given non list for Lat/Lon Values in subregions");
                break;
            case PASSMINBOX:
                if(pce.getNewValue() instanceof MinimumBoxData)
                {
                    MinimumBoxData minBox = (MinimumBoxData) pce.getNewValue();
                    if((minBox.getAllOriginalLatLonPolygonPts().size() != subregions.size())
                            || minBox.getTranslatedRotatedPolygonPtSet().size() != subregions.size())
                    {
                        LOGGER.error("Incorrect Number of points.");
                        return;
                    }
                    for(int index = 0; index &lt; subregions.size(); index ++)
                    {
                        subregions.get(index).setCoordinate(minBox.getAllOriginalLatLonPolygonPts().get(index), 
                                minBox.getTranslatedRotatedPolygonPtSet().get(index));
                    }
                    {
                        double lat = minBox.getBoundingBoxCentriod().latitude.degrees;
                        double lon = minBox.getBoundingBoxCentriod().longitude.degrees;
                        setData(StrLatLong, (lat &gt; 0 ? "+" : "") + lat + " " + (lon &gt; 0 ? "+" : "") + lon);
                        LatLong latlong = LatLong.valueOf(lat, lon, NonSI.DEGREE_ANGLE);
                        GISLookup&lt;Site&lt;?&gt;&gt; lookup = GISData.getInstance().&lt;Site&lt;?&gt;&gt;
                                getLookup(Caster.&lt;Class&lt;Site&lt;?&gt;&gt;&gt;cast(Site.class));
                        List&lt;Site&lt;?&gt;&gt; results = lookup.lookup(latlong);
                        if (results.size() &gt; 0) 
                        {
                            Comparator&lt;Site&lt;?&gt;&gt; c = new Site.LevelComparator();
                            Collections.sort(results, c);
                            siteValue = results.get(results.size() - 1);
                            String FIPS = siteValue.getFIPSCode();
                            setData(Site, FIPS);
                        } 
                    }
                    setData(Elevation, Double.toString(minBox.getBoundingBoxCentriod().elevation));
                    setData(RegionAngle, Double.toString(minBox.getAngle()));
                    setData(XLength, Double.toString(minBox.getxOrig()));
                    setData(YLength, Double.toString(minBox.getyOrig()));
                }
                break;
            case SubregionData.SOILFILE:
                if(pce.getOldValue() instanceof Integer)
                {
                    if(pce.getNewValue() instanceof String)
                    {
                        int index = (Integer) pce.getOldValue();
                        if(index &gt;= subregions.size()) 
                        {
                            LOGGER.error("Given out of bounds index to add/edit a subregion.");
                            break;
                        }
                        String soilFileName = (String) pce.getNewValue();
                        subregions.get(index).dataChange(SubregionData.SOILFILE, soilFileName, index);
                    }
                    else LOGGER.error("Given non String for soil File.");
                }
                else LOGGER.error("Given non Integer for soil File index.");
                break;
            case SubregionData.MANFILE:
                if(pce.getOldValue() instanceof Integer)
                {
                    if(pce.getNewValue() instanceof String)
                    {
                        int index = (Integer) pce.getOldValue();
                        if(index &gt;= subregions.size()) 
                        {
                            LOGGER.error("Given out of bounds index to add/edit a subregion.");
                            break;
                        }
                        String manFileName = (String) pce.getNewValue();
                        subregions.get(index).dataChange(SubregionData.MANFILE, manFileName, index);
                    }
                    else LOGGER.error("Given non String for soil File.");
                }
                else LOGGER.error("Given non Integer for soil File index.");
                break;
            case SubregionData.ROCKFRAG:
                if(pce.getOldValue() instanceof Integer)
                {
                    if(pce.getNewValue() instanceof Double)
                    {
                        int index = (Integer) pce.getOldValue();
                        if(index &gt;= subregions.size()) 
                        {
                            LOGGER.error("Given out of bounds index to add/edit a subregion.");
                            break;
                        }
                        Double rfVal = (Double) pce.getNewValue();
                        subregions.get(index).dataChange(SubregionData.ROCKFRAG, rfVal, index);
                    }
                    else LOGGER.error("Given non String for soil File.");
                }
                else LOGGER.error("Given non Integer for subregionIndex.");
                break;
            case SubregionData.AVSLOPE:
                if(pce.getOldValue() instanceof Integer)
                {
                    if(pce.getNewValue() instanceof Double)
                    {
                        int index = (Integer) pce.getOldValue();
                        if(index &gt;= subregions.size()) 
                        {
                            LOGGER.error("Given out of bounds index to add/edit a subregion.");
                            break;
                        }
                        Double avSlVal = (Double) pce.getNewValue();
                        subregions.get(index).dataChange(SubregionData.AVSLOPE, avSlVal, index);
                    }
                    else LOGGER.error("Given non Double for average slope.");
                }
                else LOGGER.error("Given non Integer for subregion index.");
                break;
            case SubregionData.WATERLOSS:
                if(pce.getOldValue() instanceof Integer)
                {
                    if(pce.getNewValue() instanceof Double)
                    {
                        int index = (Integer) pce.getOldValue();
                        if(index &gt;= subregions.size()) 
                        {
                            LOGGER.error("Given out of bounds index to edit a subregion.");
                            break;
                        }
                        Double watLossVal = (Double) pce.getNewValue();
                        subregions.get(index).dataChange(SubregionData.WATERLOSS, watLossVal, index);
                    }
                    else LOGGER.error("Given non Double for Water Loss.");
                }
                else LOGGER.error("Given non Integer for subregionIndex.");
                break;
            case LastRun:
                if(pce.getNewValue() instanceof String) archive.put(LastRun, (String) pce.getNewValue());
                else LOGGER.error("Given non String for last run.");
                break;
            case DELETION:
                System.out.println("Deletion");
                if(pce.getNewValue() instanceof Integer) subregions.remove((int) pce.getNewValue());
                else LOGGER.error("Given non int to delete.");
                break;
            default:
                LOGGER.error("Fallthrough of property change listener.  Missed RFD tag:  " + pce.getPropertyName());
        }
    }

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

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

    /**
     *
     * @param propertyName
     * @param l
     */
    public void addPropertyChangeListener(String propertyName, PropertyChangeListener l) { changes.addPropertyChangeListener(propertyName, l); }

    /**
     * Allows the container to remove or de-register some other components and
     * stop recognizing the changes that occur on this component.
     *
     * @param l The listener that does not listen and react towards the the
     * changes to be reflected.
     */
    public void removePropertyChangeListener(PropertyChangeListener l) { changes.removePropertyChangeListener(l); }

    /**
     *
     * @param propertyName
     * @param l
     */
    public void removePropertyChangeListener(String propertyName, 
            PropertyChangeListener l) { changes.removePropertyChangeListener(propertyName, l); }
    
    /**
     *
     */
    public void fireAll() {
        FireAllContext.enter();
        try {
            Enumeration&lt;String&gt; e = data.keys();
            while (e.hasMoreElements()) {
                String key = e.nextElement();
                String value = data.get(key);
                changes.firePropertyChange(key, null, value);
            }
            e = archive.keys();
            while (e.hasMoreElements()) {
                String key = e.nextElement();
                String value = archive.get(key);
                changes.firePropertyChange(key, null, value);
            }
        } finally {
            FireAllContext.exit();
        }

    }

    /**
     *
     * @param listeners
     */
    public void fireAll(PropertyChangeListener... listeners) {
        FireAllContext.enter();
        try {
            Enumeration&lt;String&gt; e = data.keys();
            while (e.hasMoreElements()) {
                String key = e.nextElement();
                String value = data.get(key);
                PropertyChangeEvent event = new PropertyChangeEvent(this, key, null, value);
                for (PropertyChangeListener listener : listeners) {
                    listener.propertyChange(event);
                }
            }

            e = archive.keys();
            while (e.hasMoreElements()) {
                String key = e.nextElement();
                String value = archive.get(key);
                PropertyChangeEvent event = new PropertyChangeEvent(this, key, null, value);
                for (PropertyChangeListener listener : listeners) {
                    listener.propertyChange(event);
                }
            }
        } finally {
            FireAllContext.exit();
        }
    }
    
    public void passInitialPoints()
    {
        List&lt;List&lt;Coordinate&gt;&gt; latLonPolyPoints = new ArrayList&lt;List&lt;Coordinate&gt;&gt;();
        for(SubregionData dat : subregions)
        {
           latLonPolyPoints.add(dat.latLon);
        }
        changes.firePropertyChange(PASSPOINTSINIT, null, latLonPolyPoints);
    }
    
    public void setOutput(String type, int index, int newVal)
    {
        if(type.equals(ErosionSubmodelOutput)) data.put(type, Integer.toString(newVal));
        else subregions.get(index).dataChange(type, newVal, 0);
    }
    
    public String getOutput(String type, int index)
    {
        if(type.equals(ErosionSubmodelOutput)) return data.get(type);
        else return subregions.get(index).getOutputValue(type);
    }
    
    public static List&lt;String&gt; getDataKeySet() { return Arrays.asList(printOrder); }
    public static List&lt;String&gt; getArchiveKeySet() { return  Arrays.asList(archiveKeys); }
    
    public List&lt;SubregionData&gt; getSubregions() { return subregions; }
    public List&lt;BarrierData&gt; getBarriers() { return barriers; }
    
    public Site&lt;?&gt; getSite() { return siteValue; }
    public void setSite(Site&lt;?&gt; input) { siteValue = input; }
    
    public LatLong getLatLong()
    {
        String[] latlon = getData(StrLatLong).split(" +");
        return LatLong.valueOf(Double.parseDouble(latlon[0]), Double.parseDouble(latlon[1]), NonSI.DEGREE_ANGLE);
    }
    public void setLatLong(LatLong input) { setData(StrLatLong, input.toString()); }
    public void setCligenStationMode(StationMode input) { cligenStationModeValue = input; }
    public void setWindgenStationMode(StationMode input) { windgenStationModeValue = input; }
    public void setCligenStation(Station input) { cligenStationValue = input; }
    public void setWindgenStation(Station input) { windgenStationValue = input; }
    
    public boolean validateManagements()
    {
        for(SubregionData data : subregions)
        {
            if(!data.validateMan()) return false;
        }
        return true;
    }

    public boolean validateSoils()
    {
        for(SubregionData data : subregions)
        {
            if(!data.validateSoil()) return false;
        }
        return true;
    }
    
    public void commitAux()
    {
        List&lt;String[]&gt; manSoil = new LinkedList&lt;String[]&gt;();
        for(SubregionData data : subregions) manSoil.add(data.bundleManSoil());
        changes.firePropertyChange(PASSAUXINIT, null, manSoil);
    }
    
    public void forceStations()
    {
        statFinder.setLatLon(getLatLong());
        //For now we force stations to be in NRCS mode.
        cligenStationModeValue = StationMode.NRCS;
        setData(ClimateFlag, "nrcs");
        cligenStationValue = statFinder.findCligenStation();
        setData(CligenStation, StationUtil.serializeStation(cligenStationValue));
        windgenStationModeValue = StationMode.NRCS;
        setData(WindFlag, "nrcs");
        windgenStationValue = statFinder.findWindgenStation();
        setData(WindgenStation, StationUtil.serializeStation(windgenStationValue));
    }
    
    public RunXMLParser getParser() { return xmlParser; }
    
    public class RunXMLParser
    {
        private String tempFileName;
        
        private static final String RUN_ROOT = "runFileData";
        
        private static final String DEFAULT_DTD = "weps.run.dtd";
        
        /**
         * Reads a weps.run.xml file.
         * @param pFileName
         */
        private void readWepsRunXML(String pFileName)
        {
            org.w3c.dom.Document doc;

            doc = getDocument(pFileName);
            if (doc == null) {
                return;
            }

            doc.normalize();
            Node node = doc.getDocumentElement();

            DocumentTraversal traversable;

            if (node.getOwnerDocument() == null) {
                traversable = (DocumentTraversal) node;
            } else {
                traversable = (DocumentTraversal) node.getOwnerDocument();
            }

            TreeWalker walker = traversable.createTreeWalker(node, NodeFilter.SHOW_ALL, null, false);
            String nodeName = node.getNodeName();
            String nodeValue;

            if (nodeName.equals(RFDRoot)) 
            {
                int barNo = -1;
                int subNo = -1;
                Node nodeChild = walker.firstChild();
                Node grandChild;
                while(nodeChild != null)
                {
                    nodeName = nodeChild.getNodeName();
                    if(nodeName.equals(BarHead))
                    {
                        barNo = Integer.parseInt(XMLDoc.getTextData(nodeChild.getAttributes().getNamedItem(NUMBER)));
                        grandChild = nodeChild.getFirstChild();
                        while(grandChild != null)
                        {
                            try 
                            { 
                                if(barriers == null) RunFileDataXML.this.barriers = new ArrayList&lt;BarrierData&gt;();
                                BarrierData barData = new BarrierData(barriers.size());
                                barData.setParser(xmlParser);
                                barData.readFromNode(grandChild); 
                                RunFileDataXML.this.barriers.add(barData);
                            }
                            catch(ParseException pe)
                            {
                                LOGGER.error("Failed to parse barrier section of RFD.  " + pe);
                                JOptionPane.showMessageDialog(null, "Failure to parse "
                                        + "barriers data out of weps.run.xml.\nFile "
                                        + "may be corrupted or of incompatible format."
                                        + "\nSkipping section and continuing with no "
                                        + "barriers.", "Failure to parse Barriers", 
                                        JOptionPane.WARNING_MESSAGE);
                            }
                            grandChild = grandChild.getNextSibling();
                        }
                    }
                    else if(nodeName.equals(SubHead))
                    {
                        subNo = Integer.parseInt(XMLDoc.getTextData(nodeChild.getAttributes().getNamedItem(NUMBER)));
                        grandChild = nodeChild.getFirstChild();
                        while(grandChild != null)
                        {
                            try
                            {
                                SubregionData subDat = new SubregionData(subregions.size());
                                subDat.readFromNode(grandChild);
                                if(RunFileDataXML.this.subregions == null) RunFileDataXML.this.subregions = new ArrayList&lt;SubregionData&gt;();
                                RunFileDataXML.this.subregions.add(subDat);
                            }
                            catch(ParseException pe)
                            {
                                LOGGER.error("Failed to parse subregion section of RFD.  " + pe);
                                JOptionPane.showMessageDialog(null, "Failure to parse "
                                        + "subregion data out of weps.run.xml.\nFile "
                                        + "may be corrupted or of incompatible format."
                                        + "\nSkipping section and continuing with no "
                                        + "subregions.", "Failure to parse Subregions", 
                                        JOptionPane.WARNING_MESSAGE);
                            }
                            grandChild = grandChild.getNextSibling();
                        }
                    }
                    else
                    {
                        nodeValue = XMLDoc.getTextData(nodeChild);
                        RunFileDataXML.this.setData(nodeName, nodeValue);
                    }
                    nodeChild = nodeChild.getNextSibling();
                }
                if(((RunFileDataXML.this.barriers == null) &amp;&amp; barNo != -1) || (barNo != RunFileDataXML.this.barriers.size()))
                {
                    LOGGER.error("BarrierNo does not match number of barriers");
                    JOptionPane.showMessageDialog(null, "Number of barriers inconsitant "
                            + "with BarrierNo field.  Correcting.", "Failure to parse "
                            + "Barriers", JOptionPane.WARNING_MESSAGE);
                }
                if(((RunFileDataXML.this.subregions == null) &amp;&amp; subNo != -1) || (subNo != RunFileDataXML.this.subregions.size()))
                {
                    LOGGER.error("BarrierNo does not match number of barriers");
                    JOptionPane.showMessageDialog(null, "Number of barriers inconsitant "
                            + "with BarrierNo field.  Correcting.", "Failure to parse "
                            + "Barriers", JOptionPane.WARNING_MESSAGE);
                }
            }
            barriers.sort(new BarrierData(-1));
            subregions.sort(new SubregionData(-1));
        }

        private void writeWepsRunXML(String pFileName)
        {
            Node root;
            try {

                /* createDocument function creates a new Document with appropriate Doctype and stylesheet attached */
                Document runDoc = createTarget(RUN_ROOT);
                if (runDoc == null) {
                    LOGGER.error("Failed to create target for weps.run.xml.");
                    return;
                }

                root = runDoc.getDocumentElement();

                RunFileDataXML.this.fillNode(root, runDoc);
                DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
                DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");
                if (impl == null) {
                    System.out.println("No DOMImplementation found !");
                    return;
                }
                LSSerializer serializer = impl.createLSSerializer();
                serializer.getDomConfig().setParameter("format-pretty-print", true);
                LSOutput output = impl.createLSOutput();
                output.setEncoding(XMLConstants.sEncoding);
                output.setCharacterStream(new java.io.FileWriter(pFileName));
                serializer.write(runDoc, output);
            } catch (DOMException e) {
                System.err.println("DomException");
            } catch (java.io.IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | ClassCastException ex) {
                Exceptions.printStackTrace(ex);
            }
        }
        
        private void readIni(String projectDirectory)
        {
            tempFileName = projectDirectory;
            if(!projectDirectory.endsWith("weps.ini")) projectDirectory += "/weps.ini";
            org.w3c.dom.Document doc;

            doc = getDocument(projectDirectory);
            if (doc == null) {
                return;
            }

            doc.normalize();
            Node node = doc.getDocumentElement();

            DocumentTraversal traversable;

            if (node.getOwnerDocument() == null) {
                traversable = (DocumentTraversal) node;
            } else {
                traversable = (DocumentTraversal) node.getOwnerDocument();
            }

            TreeWalker walker = traversable.createTreeWalker(node, NodeFilter.SHOW_ALL, null, false);
            String nodeName = node.getNodeName();
            String nodeValue;

            if (nodeName.equals(RFDRoot)) 
            {
                int barNo = -1;
                int subNo = -1;
                Node nodeChild = walker.firstChild();
                while(nodeChild != null)
                {
                    nodeName = nodeChild.getNodeName();
                    if(nodeName.equals(SubKey))
                    {
                        try
                        {
                            SubregionData subDat = new SubregionData(subregions.size());
                            subDat.readFromNode(nodeChild);
                            if(RunFileDataXML.this.subregions == null) RunFileDataXML.this.subregions = new ArrayList&lt;SubregionData&gt;();
                            RunFileDataXML.this.subregions.add(subDat);
                        }
                        catch(ParseException pe)
                        {
                            LOGGER.error("Failed to parse subregion section of RFD.  " + pe);
                            JOptionPane.showMessageDialog(null, "Failure to parse "
                                    + "subregion data out of weps.run.xml.\nFile "
                                    + "may be corrupted or of incompatible format."
                                    + "\nSkipping section and continuing with no "
                                    + "subregions.", "Failure to parse Subregions", 
                                    JOptionPane.WARNING_MESSAGE);
                        }
                    }
                    else if(nodeName.equals(BarKey))
                    {
                        try 
                        { 
                            if(RunFileDataXML.this.barriers == null) RunFileDataXML.this.barriers = new ArrayList&lt;BarrierData&gt;();
                            BarrierData barData = new BarrierData(barriers.size());
                            barData.setParser(xmlParser);
                            barData.readFromNode(nodeChild); 
                            RunFileDataXML.this.barriers.add(barData);
                        }
                        catch(ParseException pe)
                        {
                            LOGGER.error("Failed to parse barrier section of RFD.  " + pe);
                            JOptionPane.showMessageDialog(null, "Failure to parse "
                                    + "barriers data out of weps.run.xml.\nFile "
                                    + "may be corrupted or of incompatible format."
                                    + "\nSkipping section and continuing with no "
                                    + "barriers.", "Failure to parse Barriers", 
                                    JOptionPane.WARNING_MESSAGE);
                        }
                    }
                    else if(nodeName.equals(BarHead))
                    {
                        barNo = Integer.parseInt(XMLDoc.getTextData(nodeChild.getAttributes().getNamedItem(NUMBER)));
                    }
                    else if(nodeName.equals(SubHead))
                    {
                        subNo = Integer.parseInt(XMLDoc.getTextData(nodeChild.getAttributes().getNamedItem(NUMBER)));
                    }
                    else
                    {
                        nodeValue = XMLDoc.getTextData(nodeChild);
                        RunFileDataXML.this.setData(nodeName, nodeValue);
                    }
                    nodeChild = nodeChild.getNextSibling();
                }
                if(((RunFileDataXML.this.barriers == null) &amp;&amp; barNo != -1) || (barNo != RunFileDataXML.this.barriers.size()))
                {
                    LOGGER.error("BarrierNo does not match number of barriers");
                    JOptionPane.showMessageDialog(null, "Number of barriers inconsitant "
                            + "with BarrierNo field.  Correcting.", "Failure to parse "
                            + "Barriers", JOptionPane.WARNING_MESSAGE);
                }
                if(((RunFileDataXML.this.subregions == null) &amp;&amp; subNo != -1) || (subNo != RunFileDataXML.this.subregions.size()))
                {
                    LOGGER.error("BarrierNo does not match number of barriers");
                    JOptionPane.showMessageDialog(null, "Number of barriers inconsitant "
                            + "with BarrierNo field.  Correcting.", "Failure to parse "
                            + "Barriers", JOptionPane.WARNING_MESSAGE);
                }
            }
        }
        
        private void writeIni(String projectDirectory)
        {
            if(!projectDirectory.endsWith("weps.ini")) projectDirectory += "/weps.ini";
            Node root;
            try {
                /* createDocument function creates a new Document with appropriate Doctype and stylesheet attached */
                Document runDoc = createTarget(RunXMLParser.RUN_ROOT);
                if (runDoc == null) {
                    LOGGER.error("Failed to create target for weps.run.xml.");
                    return;
                }

                root = runDoc.getDocumentElement();

                RunFileDataXML.this.fillNode(root, runDoc);
                Node child;
                for(String key : archiveKeys)
                {
                    child = runDoc.createElement(key);
                    XMLDoc.setTextData(child, RunFileDataXML.this.archive.get(key), runDoc);
                    root.appendChild(child);
                }
                DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
                DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");
                if (impl == null) {
                    System.out.println("No DOMImplementation found !");
                    return;
                }
                LSSerializer serializer = impl.createLSSerializer();
                serializer.getDomConfig().setParameter("format-pretty-print", true);
                LSOutput output = impl.createLSOutput();
                output.setEncoding(XMLConstants.sEncoding);
                output.setCharacterStream(new java.io.FileWriter(projectDirectory));
                serializer.write(runDoc, output);
            } catch (DOMException e) {
                System.err.println("DomException");
            } catch (java.io.IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | ClassCastException ex) {
                Exceptions.printStackTrace(ex);
            }
        }
        
        /**
     * Returns the document type for one of the operation, crop or management files
     */
        private DocumentType getDocType(DOMImplementation domImpl, String root) {
            DocumentType docType = null;
            docType = domImpl.createDocumentType(root, null, DEFAULT_DTD);
            return docType;
        }

        /**
         * Creates an XML document with the required element name and data following the 
         * DTD and XSl guidelines for arranging the data in pre-described manner according 
         * to the standard DOM implementations.
         * @param pDocumentName The name with which the document should be created and saved.
         * @return The newly constructed DOM file
         */
        public Document createTarget(String root) {
            DocumentType docType;
            Document doc = null;
//            ProcessingInstruction styleSheet;

            DocumentBuilder builder = createBuilder();
            if (builder == null) {
                return null;
            }
            DOMImplementation domImpl = builder.getDOMImplementation();
            if (domImpl == null) {
                return null;
            }

            docType = getDocType(domImpl, root);
            if (docType == null) {
                //System.err.println("XMLDoc:createDocument():" + "DocType for " + pDocumentName + " is null");
                return null;
            }
            doc = domImpl.createDocument(null, root, docType);
//            styleSheet = doc.createProcessingInstruction(sStyleSheetTarget, sStyleSheetData
//                    + "\"" + sCropDBXSLfile + "\"");
//            Node root = doc.getDocumentElement();
//            if (styleSheet != null) {
//                doc.insertBefore(styleSheet, root);
//            }

            return doc;
        }

        private DocumentBuilder createBuilder() {
            try {
                DocumentBuilderFactory mFactory = DocumentBuilderFactory.newInstance();
                mFactory.setIgnoringElementContentWhitespace(true); // Ignore whitespace
                mFactory.setIgnoringComments(true); // Ignore comments
                mFactory.setValidating(true);
                mFactory.setNamespaceAware(true);

                DocumentBuilder mParser = mFactory.newDocumentBuilder();
                mParser.setErrorHandler(new RunXMLHandler(this));
                mParser.setEntityResolver(new RunEntityResolver());

                return mParser;
            } catch (ParserConfigurationException e) {
                LOGGER.error("Unable to create XML DocumentBuilder", e);
                return null;
            }
        }

        /**
         * Returns a newly constructed document object
         * @param pFilename Name to be used in creating/constructing a new DOM file.
         * @return The newly constructed DOM file
         */
        public org.w3c.dom.Document getDocument(String pFilename) {

            try {

                DocumentBuilder builder = createBuilder();

                if (builder != null) {
                    TFile file = null;

                    if ((new TFile(pFilename)).isAbsolute()) {
                        file = new TFile(pFilename);
                    } else {
                        file = new TFile(".", pFilename);
                    }

                    TFileInputStream is = new TFileInputStream(file);

                    org.w3c.dom.Document doc = builder.parse(is);

                    return doc;
                } else {
                }
            } catch (SAXException | IOException | IllegalArgumentException e) {
                LOGGER.error("Error reading file \"" + pFilename + "\"", e);
            }
            return null;
        }

        private class RunXMLHandler extends DefaultHandler
        {
            public RunXMLHandler(RunXMLParser parent) {
                super();
            }

            @Override
            public void fatalError(SAXParseException exc) {
                System.out.println("McrewXMLHandler:fatalError() ");

            }

            @Override
            public void error(SAXParseException exc)
            {
                try
                {
                    RunFileData archive = new RunFileData();
                    archive.readRunData(tempFileName);
                    RunFileDataXML.this.convertOldWepsRunInPlace(archive, 
                            tempFileName.endsWith("ini") || tempFileName.endsWith(".wpj"));
                }
                catch(Exception e)
                {
                    LOGGER.error("Trying to read older weps.run format failed.  Original error:\n");
                    LOGGER.error(exc);
                }
            }

            @Override
            public void warning(SAXParseException exc)
            {
                System.out.println("McrewXMLHandler:warning() ");
            }
        }

        private class RunEntityResolver implements EntityResolver
        {

            @Override
            public InputSource resolveEntity(String privateId, String systemId) throws SAXException, IOException {
                if (systemId == null) {
                    //System.err.println("McrewEntityResolver:resolveEntiity() " + "SystemId is null!!");	
                    return null;
                }

                String configDirPath = System.getProperty("user.dir") + TFile.separator + "run_cfg";

                TFile file = new TFile(systemId);
                String resolveFileName = file.getName();

                TFile file2 = new TFile(configDirPath, resolveFileName);
                if (file2.exists()) {
                    try {
                        return new InputSource(new java.io.FileInputStream(file2));
                    } catch (FileNotFoundException ex) {
                        //I've already checked for this.
                    }
                }

                return null;
            }

        }
    }
    public static void main(String[] args)
    {
        if(args.length &gt; 0)
        {
            String mainConfig = "./cfg/weps.cfg";
            String origin = "";
            String destination = "";
            for(int index = 0; index &lt; args.length; index ++)
            {
                if(args[index].equals("-rfd")) origin = args[++index];
                if(args[index].equals("-dst")) destination = args[++index];
                if(args[index].equals("-cfg")) mainConfig = args[++index];
            }
            if(origin.equals("") || destination.equals("")) return;
            TFile mainConfigFile = new TFile(mainConfig).getCanOrAbsFile();
            String userConfig = About.getUserWeps().getAbsolutePath() + "/" + mainConfigFile.getName();
            ConfigData.getDefault().load(mainConfigFile, new TFile(userConfig).getCanOrAbsFile());
            RunFileData rfdo = new RunFileData();
            rfdo.readRunFile(origin);
            RunFileDataXML rfdx = RunFileDataXML.convertOldWepsRun(rfdo, 
                    origin.endsWith("ini") || origin.endsWith(".wpj"));
            rfdx.writeWepsRunXML(destination);
        }
        else
        {
            RunFileDataXML rfdx = new RunFileDataXML();
            rfdx.readWepsRunXML("./run7.xml");
            rfdx.writeWepsRunXML("./run11.xml");
        }
    }
    
    /**
     *
     */
    public static enum StationType {

        /**
         *
         */
        Cligen("Cligen"),
        /**
         *
         */
        Windgen("Windgen");

        private final String c_displayName;

        private StationType(String displayName) {
            c_displayName = displayName;
        }

        /**
         *
         * @return
         */
        public String getDisplayName() {
            return c_displayName;
        }

    }
}
</pre></body></html>