package usda.weru.erosion;

import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.TFileReader;
import de.schlichtherle.truezip.file.TFileWriter;
import java.util.*;
import java.beans.*;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.PrintWriter;
import usda.weru.erosion.barriereditor.BarrierPolygon;
import usda.weru.erosion.barriereditor.FieldPolygon;

/**
 *
 * @author maxerdwien
 */
public class DataStore implements PropertyChangeListener {

	/**
	 *
	 */
	public static final String InputExt = ".in";

	/**
	 *
	 */
	public DataStore() {
		init();
	}
	private int lineNum = 0;
//	private int numSubr = 1;  // needed for future expansion
	// Global

	/**
	 *
	 */
	public static final String SimRegOrgX = "SimRegOrgX";

	/**
	 *
	 */
	public static final String SimRegOrgY = "SimRegOrgY";

	/**
	 *
	 */
	public static final String SimRegLenX = "SimRegLenX";

	/**
	 *
	 */
	public static final String SimRegLenY = "SimRegLenY";

	/**
	 *
	 */
	public static final String SimX1Y1 = "SimX1Y1";

	/**
	 *
	 */
	public static final String SimX2Y2 = "SimX2Y2";
//    public static final String  SimFld          = "SimFld";

	/**
	 *
	 */
	public static final String SimRegAngle = "SimRegAngle";

	/**
	 *
	 */
	public static final String SimField = "SimField";    // Accounting Regions - not currently displayed

	/**
	 *
	 */
	public static final String AccRegNum = "AccRegNum";

	/**
	 *
	 */
	public static final String AccRegOrgX = "AccRegOrgX";

	/**
	 *
	 */
	public static final String AccRegOrgY = "AccRegOrgY";

	/**
	 *
	 */
	public static final String AccRegLenX = "AccRegLenX";

	/**
	 *
	 */
	public static final String AccRegLenY = "AccRegLenY";    // Subregions - not currently displayed

	/**
	 *
	 */
	public static final String SubRegNum = "SubRegNum";

	/**
	 *
	 */
	public static final String SubRegOrgX = "SubRegOrgX";

	/**
	 *
	 */
	public static final String SubRegOrgY = "SubRegOrgY";

	/**
	 *
	 */
	public static final String SubRegLenX = "SubRegLenX";

	/**
	 *
	 */
	public static final String SubRegLenY = "SubRegLenY";    // Barriers

	/**
	 *
	 */
	public static final String BarriersNum = "BarriersNum";

	/**
	 *
	 */
	public static final String BarriersOrgX = "BarriersOrgX";

	/**
	 *
	 */
	public static final String BarriersOrgY = "BarriersOrgY";

	/**
	 *
	 */
	public static final String BarriersLenX = "BarriersLenX";

	/**
	 *
	 */
	public static final String BarriersLenY = "BarriersLenY";

	/**
	 *
	 */
	public static final String BarriersHgt = "BarriersHgt";

	/**
	 *
	 */
	public static final String BarriersPors = "BarriersPors";

	/**
	 *
	 */
	public static final String BarriersWid = "BarriersWid";

	/**
	 *
	 */
	public static final String BarriersObj = "BarriersObj";    // Biomass

	/**
	 *
	 */
	public static final String BiomassHgt = "BiomassHgt";

	/**
	 *
	 */
	public static final String BiomassRSAI = "BiomassRSAI";

	/**
	 *
	 */
	public static final String BiomassRLAI = "BiomassRLAI";

	/**
	 *
	 */
	public static final String BiomassFlat = "BiomassFlat";

	/**
	 *
	 */
	public static final String BiomassStanding = "BiomassStanding";	// not currently used

	/**
	 *
	 */
	public static final String BiomassTotal = "BiomassTotal";		// not currently used

	/**
	 *
	 */
	public static final String CropHgt = "CropHgt";

	/**
	 *
	 */
	public static final String CropGSAI = "CropGSAI";

	/**
	 *
	 */
	public static final String CropGLAI = "CropGLAI";

	/**
	 *
	 */
	public static final String CropRowSpacing = "CropRowSpacing";

	/**
	 *
	 */
	public static final String CropRowPlacemnt = "CropRowPlacemnt";

	/**
	 *
	 */
	public static final String SoilIFCName = "SoilIFCName";    // Soil layers

	/**
	 *
	 */
	public static final String LayerOrigNum = "LayerOrigNum";

	/**
	 *
	 */
	public static final String LayerNum = "LayerNum";

	/**
	 *
	 */
	public static final String LayerThickness = "LayerThickness";

	/**
	 *
	 */
	public static final String LayerBD = "LayerBD";

	/**
	 *
	 */
	public static final String LayerSand = "LayerSand";

	/**
	 *
	 */
	public static final String LayerVFSand = "LayerVFSand";

	/**
	 *
	 */
	public static final String LayerSilt = "LayerSilt";

	/**
	 *
	 */
	public static final String LayerClay = "LayerClay";

	/**
	 *
	 */
	public static final String LayerRock = "LayerRock";

	/**
	 *
	 */
	public static final String LayerAggDen = "LayerAggDen";

	/**
	 *
	 */
	public static final String LayerAggSta = "LayerAggSta";

	/**
	 *
	 */
	public static final String LayerAggGMD = "LayerGMD";

	/**
	 *
	 */
	public static final String LayerAggMin = "LayerMinAggSiz";

	/**
	 *
	 */
	public static final String LayerAggMax = "LayerMaxAggSiz";

	/**
	 *
	 */
	public static final String LayerAggGSD = "LayerGSD";

	/**
	 *
	 */
	public static final String LayerWPWC = "LayerWPWC";
//	public static final String	HydroLayerWC	= "HydroLayerWC";

    // Soil surface
	/**
	 *
	 */
	public static final String SurfCrustFrac = "SurfCrustFrac";

	/**
	 *
	 */
	public static final String SurfCrustThk = "SurfCrustThk";

	/**
	 *
	 */
	public static final String SurfLMFrac = "SurfLMFrac";

	/**
	 *
	 */
	public static final String SurfLMMass = "SurfLMMass";

	/**
	 *
	 */
	public static final String SurfCrustDen = "SurfCrustDen";

	/**
	 *
	 */
	public static final String SurfCrustSta = "SurfCrustSta";

	/**
	 *
	 */
	public static final String SurfARR = "SurfARR";

	/**
	 *
	 */
	public static final String SurfRidgHgt = "SurfRidgHgt";

	/**
	 *
	 */
	public static final String SurfRidgSpacing = "SurfRidgSpacing";

	/**
	 *
	 */
	public static final String SurfRidgWid = "SurfRidgWid";

	/**
	 *
	 */
	public static final String SurfRidgOrient = "SurfRidgOrient";

	/**
	 *
	 */
	public static final String SurfDikeSpacing = "SurfDikeSpacing";

	/**
	 *
	 */
	public static final String SurfSnowDepth = "HydroSnowDepth";

	/**
	 *
	 */
	public static final String SurfWC = "HydroSurfWC";    // Weather

	/**
	 *
	 */
	public static final String WeaAirDen = "WeaAirDen";

	/**
	 *
	 */
	public static final String WeaWindDir = "WeaWindDir";

	/**
	 *
	 */
	public static final String WeaDailySteps = "WeaDailySteps";

	/**
	 *
	 */
	public static final String WeaAnemHgt = "WeaAnemHgt";

	/**
	 *
	 */
	public static final String WeaAeroRough = "WeaAeroRough";

	/**
	 *
	 */
	public static final String WeaZoLocFlg = "WeaZoLocFlg";

	/**
	 *
	 */
	public static final String WeaWindWeibull = "WeaWindWeibull";

	/**
	 *
	 */
	public static final String WeaCalmWind = "WeaCalmWind";

	/**
	 *
	 */
	public static final String WeaWeibullC = "WeaWeibullC";

	/**
	 *
	 */
	public static final String WeaWeibullK = "WeaWeibullK";

	/**
	 *
	 */
	public static final String WeaWindSpeeds = "WeaWindSpeeds";    // Plot flags

	/**
	 *
	 */
	public static final String PlotFlg = "PlotFlg";

	/**
	 *
	 */
	public static final String PlotFieldLen = "Plot-Length(m)";

	/**
	 *
	 */
	public static final String PlotBiomass = "Plot-bio_ht(m)";

	/**
	 *
	 */
	public static final String PlotSAI = "Plot-stem_area";

	/**
	 *
	 */
	public static final String PlotLAI = "Plot-lai_area";

	/**
	 *
	 */
	public static final String PlotFlatCover = "Plot-flat_cov";

	/**
	 *
	 */
	public static final String PlotVFSand = "Plot-vfsand";

	/**
	 *
	 */
	public static final String PlotSand = "Plot-sand";

	/**
	 *
	 */
	public static final String PlotSilt = "Plot-silt";

	/**
	 *
	 */
	public static final String PlotClay = "Plot-clay";

	/**
	 *
	 */
	public static final String PlotRock = "Plot-rock_vol";

	/**
	 *
	 */
	public static final String PlotAggStab = "Plot-ag_stab";

	/**
	 *
	 */
	public static final String PlotAggGMD = "Plot-ag_gmd";

	/**
	 *
	 */
	public static final String PlotAggMin = "Plot-ag_min";

	/**
	 *
	 */
	public static final String PlotAggMax = "Plot-ag_max";

	/**
	 *
	 */
	public static final String PlotAggStd = "Plot-ag_std";

	/**
	 *
	 */
	public static final String PlotCrustFrac = "Plot-crust_cv";

	/**
	 *
	 */
	public static final String PlotCrustThk = "Plot-crust_z(mm)";

	/**
	 *
	 */
	public static final String PlotLMFrac = "Plot-los_cv";

	/**
	 *
	 */
	public static final String PlotLMMass = "Plot-los(kg/m^2)";

	/**
	 *
	 */
	public static final String PlotCrustDen = "Plot-cr_den(Mg/m^3)";

	/**
	 *
	 */
	public static final String PlotCrustStab = "Plot-cr_se";

	/**
	 *
	 */
	public static final String PlotRandRough = "Plot-rr(mm)";

	/**
	 *
	 */
	public static final String PlotRidgeHgt = "Plot-z_rgh(mm)";

	/**
	 *
	 */
	public static final String PlotRidgeSpc = "Plot-x_rgs(mm)";

	/**
	 *
	 */
	public static final String PlotRidgeWid = "Plot-x_rgw(mm)";

	/**
	 *
	 */
	public static final String PlotRidgeOrient = "Plot-a_rgo(deg)";

	/**
	 *
	 */
	public static final String DataChanged = "DataChanged";

	/**
	 *
	 */
	public static final String SetFocus = "SetFocus";

	/**
	 *
	 */
	public static final String Commit = "Commit";

	/**
	 *
	 */
	public static final int MaxLayers = 3;

	/**
	 *
	 */
	public void init() {

		ht = new Hashtable<String, Object>();

		// Global
		setData(SimRegOrgX, "0");
		setData(SimRegOrgY, "0");
		setData(SimRegLenX, "0");
		setData(SimRegLenY, "0");
		setData(SimRegAngle, "0");
		setData(SimField, new usda.weru.erosion.barriereditor.FieldPolygon());
		// Accounting Regions - not currently displayed
		setData(AccRegNum, "1");
		setData(AccRegOrgX, "0");
		setData(AccRegOrgY, "0");
		setData(AccRegLenX, "0");
		setData(AccRegLenY, "0");
		// Subregions - not currently displayed
		setData(SubRegNum, "1");
		setData(SubRegOrgX, "0");
		setData(SubRegOrgY, "0");
		setData(SubRegLenX, "0");
		setData(SubRegLenY, "0");
		// Barriers
		setData(BarriersNum, "0");
                //0 iteration loop
//		for (int bdx = 0; bdx < 0; bdx++) {
//			// limit init to MaxBarriers barriers
//			setData(BarriersOrgX + bdx, "0");
//			setData(BarriersOrgY + bdx, "0");
//			setData(BarriersLenX + bdx, "0");
//			setData(BarriersLenY + bdx, "0");
//			setData(BarriersHgt + bdx, "0");
//			setData(BarriersPors + bdx, "0");
//			setData(BarriersWid + bdx, "0");
//		}
		for (int rdx = 0; rdx < 1; rdx++) {
            // go thru regions (currently 1)
			// Biomass
			setData(BiomassHgt + "+" + rdx, "0.0");
			setData(CropHgt + "+" + rdx, "0.0");
			setData(CropGSAI + "+" + rdx, "0.0");
			setData(CropGLAI + "+" + rdx, "0.0");
			setData(BiomassRSAI + "+" + rdx, "0.0");
			setData(BiomassRLAI + "+" + rdx, "0.0");
			setData(CropRowSpacing + "+" + rdx, "0.0");
			setData(CropRowPlacemnt + "+" + rdx, "0");
			setData(BiomassFlat + "+" + rdx, "0.0");
			setData(BiomassStanding + "+" + rdx, "0.0");
			setData(BiomassTotal + "+" + rdx, "0.0");
			// Soil layers
			setData(LayerNum + "+" + rdx, "0");
			for (int ldx = 0; ldx < MaxLayers; ldx++) {
				// go thru layers (max 3)
				setData(LayerThickness + ldx + "+" + rdx, "0.0");
				setData(LayerBD + ldx + "+" + rdx, "0.0");
				setData(LayerSand + ldx + "+" + rdx, "0.0");
				setData(LayerVFSand + ldx + "+" + rdx, "0.0");
				setData(LayerSilt + ldx + "+" + rdx, "0.0");
				setData(LayerClay + ldx + "+" + rdx, "0.0");
				setData(LayerRock + ldx + "+" + rdx, "0.0");
				setData(LayerAggDen + ldx + "+" + rdx, "0.0");
				setData(LayerAggSta + ldx + "+" + rdx, "0.0");
				setData(LayerAggGMD + ldx + "+" + rdx, "0.0");
				setData(LayerAggMin + ldx + "+" + rdx, "0.0");
				setData(LayerAggMax + ldx + "+" + rdx, "0.0");
				setData(LayerAggGSD + ldx + "+" + rdx, "0.0");
				setData(LayerWPWC + ldx + "+" + rdx, "0.0");
			}
			// Soil surface
			setData(SurfCrustFrac + "+" + rdx, "0.0");
			setData(SurfCrustThk + "+" + rdx, "1.0");
			setData(SurfLMFrac + "+" + rdx, "0.0");
			setData(SurfLMMass + "+" + rdx, "0.0");
			setData(SurfCrustDen + "+" + rdx, "1.8");
			setData(SurfCrustSta + "+" + rdx, "2.75");
			setData(SurfARR + "+" + rdx, "6.0");
			setData(SurfRidgHgt + "+" + rdx, "0.0");
			setData(SurfRidgSpacing + "+" + rdx, "10.0");
			setData(SurfRidgWid + "+" + rdx, "0.0");
			setData(SurfRidgOrient + "+" + rdx, "0.0");
			setData(SurfDikeSpacing + "+" + rdx, "0.0");
			setData(SurfSnowDepth + "+" + rdx, "0.0");
			for (int wdx = 0; wdx < 24; wdx++) {
				setData(SurfWC + wdx + "+" + rdx, "0.0");
			}
		}
		// Weather
		setData(WeaAirDen, "1.16");
		setData(WeaWindDir, "0.0");
		setData(WeaDailySteps, "0");
		setData(WeaAnemHgt, "10.0");
		setData(WeaAeroRough, "25.0");
		setData(WeaZoLocFlg, "0");
		setData(WeaWindWeibull, "1");
		setData(WeaCalmWind, "0.0");
		setData(WeaWeibullC, "0.0");
		setData(WeaWeibullK, "0.0");
		setData(WeaWindSpeeds, "");

		changes.firePropertyChange(DataChanged, "", "0");
	}

	private String getLine(BufferedReader in) throws IOException {
		String temp;
		while ((temp = in.readLine()) != null) {
			lineNum++;
			if (temp.length() == 0) {
				return temp;
			}
			if (temp.charAt(0) != '#') {
				return temp;
			}
		}
		return null;
	}

	private void parseLayerLine(String property, String inputStr, int numLayers, int subReg) {
		StringTokenizer st = new StringTokenizer(inputStr);
		for (int idx = 0; idx < numLayers; idx++) {
			setData(property + idx + "+" + subReg, st.nextToken(), true);
		}
	}

	/**
	 *
	 * @param inpFile
	 */
	public void readTextFile(TFile inpFile) {
		clearBarriers();

		lineNum = 0;
		init();
		try {
			BufferedReader in = new BufferedReader(new TFileReader(inpFile));

            // Global
//			setData(DebugCode		, getLine(in), true); 
//			setData(InitFlg			, getLine(in), true); 
//			setData(PrintFlg		, getLine(in), true);
			getLine(in);            // skip debug code
			getLine(in);            // skip init flag
			getLine(in);            // skip print flag
			String inputStr = getLine(in);
			StringTokenizer st = new StringTokenizer(inputStr, ", ");
			String x1 = st.nextToken();
//			setData(SimRegOrgX		, inputX, true); 
			String y1 = st.nextToken();
//			setData(SimRegOrgY		, inputY, true); 
//            setData(SimX1Y1, new OrderedPair(inputX, inputY));
			String x2 = st.nextToken();
			String y2 = st.nextToken();
//            setData(SimX2Y2, new OrderedPair(inputX, inputY));
			setData(SimField, new FieldPolygon(x1, y1, x2, y2));
//			setData(SimRegLenX		, st.nextToken(), true); 
//			setData(SimRegLenY		, st.nextToken(), true); 
			setData(SimRegAngle, getLine(in), true);

            // Accounting Regions - not currently displayed
			inputStr = getLine(in);
			setData(AccRegNum, inputStr, true);
			int cnt = Integer.parseInt(inputStr.trim());
			for (int idx = 0; idx < cnt; idx++) {
				inputStr = getLine(in);
				st = new StringTokenizer(inputStr, ", ");
				setData(AccRegOrgX + "+" + idx, st.nextToken(), true);
				setData(AccRegOrgY + "+" + idx, st.nextToken(), true);
				setData(AccRegLenX + "+" + idx, st.nextToken(), true);
				setData(AccRegLenY + "+" + idx, st.nextToken(), true);
			}

            // Barriers
			inputStr = getLine(in);
			setData(BarriersNum, inputStr, true);
			cnt = Integer.parseInt(inputStr.trim());
			for (int idx = 0; idx < cnt; idx++) {
				inputStr = getLine(in);
				st = new StringTokenizer(inputStr, ", ");
				String tmp1 = st.nextToken();
				String tmp2 = st.nextToken();
				String tmp3 = st.nextToken();
				String tmp4 = st.nextToken();
				String tmp8 = (st.hasMoreTokens()) ? st.nextToken("") : "Barrier " + (idx + 1);
                //setData(BarriersOrgX+idx, tmp1, true); 
				//setData(BarriersOrgY+idx, tmp2, true); 
				//setData(BarriersLenX+idx, tmp3, true); 
				//setData(BarriersLenY+idx, tmp4, true); 
				inputStr = getLine(in);
				st = new StringTokenizer(inputStr, ", ");
				String tmp5 = st.nextToken();
				String tmp6 = st.nextToken();
				String tmp7 = st.nextToken();
				String tmp9 = (st.hasMoreTokens()) ? st.nextToken("") : "Barrier " + (idx + 1);

                //setData(BarriersHgt	+idx, tmp5, true); 
				//setData(BarriersPors+idx, tmp6, true); 
				//setData(BarriersWid	+idx, tmp7, true);
				setData(BarriersObj + "-" + tmp8, new BarrierPolygon(tmp1, tmp2, tmp3, tmp4,
						tmp5, tmp6, tmp7, tmp8, tmp9));
			}

            // Subregions - only 1 currently displayed (must be whole area)
			inputStr = getLine(in);
//			setData(SubRegNum 		, inputStr, true); 
			cnt = Integer.parseInt(inputStr.trim());
			for (int idx = 0; idx < cnt; idx++) {
				inputStr = getLine(in);
				st = new StringTokenizer(inputStr, ", ");
				setData(SubRegOrgX + "+" + idx, st.nextToken(), true);
				setData(SubRegOrgY + "+" + idx, st.nextToken(), true);
				setData(SubRegLenX + "+" + idx, st.nextToken(), true);
				setData(SubRegLenY + "+" + idx, st.nextToken(), true);

                // Biomass
				inputStr = getLine(in);
				setData(BiomassHgt + "+" + idx, inputStr /*getLine(in)*/, true);
				inputStr = getLine(in);
				setData(CropHgt + "+" + idx, inputStr /*getLine(in)*/, true);
				inputStr = getLine(in);
				st = new StringTokenizer(inputStr, ", ");
				setData(CropGSAI + "+" + idx, st.nextToken(), true);
				setData(CropGLAI + "+" + idx, st.nextToken(), true);
				inputStr = getLine(in);
				st = new StringTokenizer(inputStr, ", ");
				setData(BiomassRSAI + "+" + idx, st.nextToken(), true);
				setData(BiomassRLAI + "+" + idx, st.nextToken(), true);
				inputStr = getLine(in);
				st = new StringTokenizer(inputStr, ", ");
				setData(CropRowSpacing + "+" + idx, st.nextToken(), true);
				setData(CropRowPlacemnt + "+" + idx, st.nextToken(), true);
				inputStr = getLine(in);
				st = new StringTokenizer(inputStr, ", ");
				setData(BiomassFlat + "+" + idx, st.nextToken(), true); // not used
				//		setData(BiomassStanding+"+"+idx	, st.nextToken(), true); // not used
				//		setData(BiomassTotal+"+"+idx		, st.nextToken(), true);

                // Soil layers
				inputStr = getLine(in);
				st = new StringTokenizer(inputStr, ", ");
				String layStr = st.nextToken();
				int numLayers = Integer.parseInt(layStr.trim());
				if (numLayers > MaxLayers) {
					numLayers = 3;
				}
				setData(LayerNum + "+" + idx, Integer.toString(numLayers), true);
                                
				parseLayerLine(LayerThickness, getLine(in), numLayers, idx);
				parseLayerLine(LayerBD, getLine(in), numLayers, idx);
				parseLayerLine(LayerSand, getLine(in), numLayers, idx);
				parseLayerLine(LayerVFSand, getLine(in), numLayers, idx);
				parseLayerLine(LayerSilt, getLine(in), numLayers, idx);
				parseLayerLine(LayerClay, getLine(in), numLayers, idx);
				parseLayerLine(LayerRock, getLine(in), numLayers, idx);
				parseLayerLine(LayerAggDen, getLine(in), numLayers, idx);
				parseLayerLine(LayerAggSta, getLine(in), numLayers, idx);
				parseLayerLine(LayerAggGMD, getLine(in), numLayers, idx);
				parseLayerLine(LayerAggMin, getLine(in), numLayers, idx);
				parseLayerLine(LayerAggMax, getLine(in), numLayers, idx);
				parseLayerLine(LayerAggGSD, getLine(in), numLayers, idx);

                // Soil surface
				inputStr = getLine(in);
				st = new StringTokenizer(inputStr, ", ");
				setData(SurfCrustFrac + "+" + idx, st.nextToken(), true);
				setData(SurfCrustThk + "+" + idx, st.nextToken(), true);
				setData(SurfLMFrac + "+" + idx, st.nextToken(), true);
				setData(SurfLMMass + "+" + idx, st.nextToken(), true);
				setData(SurfCrustDen + "+" + idx, st.nextToken(), true);
				setData(SurfCrustSta + "+" + idx, st.nextToken(), true);
				setData(SurfARR + "+" + idx, getLine(in), true);
				inputStr = getLine(in);
				st = new StringTokenizer(inputStr, ", ");
				setData(SurfRidgHgt + "+" + idx, st.nextToken(), true);
				setData(SurfRidgSpacing + "+" + idx, st.nextToken(), true);
				setData(SurfRidgWid + "+" + idx, st.nextToken(), true);
				setData(SurfRidgOrient + "+" + idx, st.nextToken(), true);
				setData(SurfDikeSpacing + "+" + idx, getLine(in), true);

                // Hydrology
				setData(SurfSnowDepth + "+" + idx, getLine(in), true);
//				setData(HydroWPWC+"+"+idx		, getLine(in), true);
//				setData(HydroLayerWC+"+"+idx			, getLine(in), true);
				parseLayerLine(LayerWPWC, getLine(in), numLayers, idx);
				inputStr = getLine(in);			// skip layer WCs
//				st = new StringTokenizer(inputStr, ", ");
//				setData(HydroLayerWC+"+"+idx			, st.nextToken(), true);
//				setData(HydroSurfWC+"1"+"+"+idx			, getLine(in), true);
//				setData(HydroSurfWC+"2"+"+"+idx			, getLine(in), true);
				inputStr = getLine(in);
				st = new StringTokenizer(inputStr, ", \t");
				for (int wdx = 0; wdx < 24; wdx++) {		// 24 hours/day
					if (!st.hasMoreTokens()) {
						inputStr = getLine(in);
						st = new StringTokenizer(inputStr, ", \t");
					}
					setData(SurfWC + wdx + "+" + idx, st.nextToken(), true);
				}
			}

            // Weather
			setData(WeaAirDen, getLine(in), true);
			setData(WeaWindDir, getLine(in), true);
			inputStr = getLine(in);
			setData(WeaDailySteps, inputStr, true);
			int numSteps = Integer.parseInt(inputStr.trim());
			inputStr = getLine(in);
			st = new StringTokenizer(inputStr, ", ");
			setData(WeaAnemHgt, st.nextToken(), true);
			setData(WeaAeroRough, st.nextToken(), true);
			setData(WeaZoLocFlg, st.nextToken(), true);
			inputStr = getLine(in);
//			setData(WeaWindWeibull	, inputStr, true);
			if (inputStr.trim().startsWith("0")) {  // old style file
				inputStr = getLine(in);
				st = new StringTokenizer(inputStr, ", ");
				setData(WeaCalmWind, st.nextToken(), true);
				setData(WeaWeibullC, st.nextToken(), true);
				setData(WeaWeibullK, st.nextToken(), true);
			} else {
				String[] inpElms = inputStr.trim().split("\\s+");
				if (inpElms.length == 4) {
					setData(WeaCalmWind, inpElms[1], true);
					setData(WeaWeibullC, inpElms[2], true);
					setData(WeaWeibullK, inpElms[3], true);
				}
				StringBuffer sb = new StringBuffer();
				inputStr = getLine(in);
				st = new StringTokenizer(inputStr, ", \t");
				for (int wdx = 0; wdx < numSteps; wdx++) {
					if (!st.hasMoreTokens()) {
						inputStr = getLine(in);
						st = new StringTokenizer(inputStr, ", \t");
					}
					sb.append(st.nextToken());
					sb.append(" ");
				}
				setData(WeaWindSpeeds, sb.toString(), true);
			}

            // Plot flags
			// set up default values in case file lies about having plot flags
			setData(PlotFieldLen, "1", true);
			setData(PlotBiomass, "1", true);
			setData(PlotSAI, "1", true);
			setData(PlotLAI, "1", true);
			setData(PlotFlatCover, "1", true);
			setData(PlotVFSand, "1", true);
			setData(PlotSand, "1", true);
			setData(PlotSilt, "1", true);
			setData(PlotClay, "1", true);
			setData(PlotRock, "1", true);
			setData(PlotAggStab, "1", true);
			setData(PlotAggGMD, "1", true);
			setData(PlotAggMin, "1", true);
			setData(PlotAggMax, "1", true);
			setData(PlotAggStd, "1", true);
			setData(PlotCrustFrac, "1", true);
			setData(PlotCrustThk, "1", true);
			setData(PlotLMFrac, "1", true);
			setData(PlotLMMass, "1", true);
			setData(PlotCrustDen, "1", true);
			setData(PlotCrustStab, "1", true);
			setData(PlotRandRough, "1", true);
			setData(PlotRidgeHgt, "1", true);
			setData(PlotRidgeSpc, "1", true);
			setData(PlotRidgeWid, "1", true);
			setData(PlotRidgeOrient, "1", true);

			String plotFlg = getLine(in).trim();

			setData(PlotFlg, plotFlg, true);
			if (!plotFlg.equals("-1")) {
				setData(PlotFieldLen, getLine(in), true);
				getLine(in);
				setData(PlotBiomass, getLine(in), true);
				getLine(in);
				setData(PlotSAI, getLine(in), true);
				getLine(in);
				setData(PlotLAI, getLine(in), true);
				getLine(in);
				setData(PlotFlatCover, getLine(in), true);
				getLine(in);
				setData(PlotVFSand, getLine(in), true);
				getLine(in);
				setData(PlotSand, getLine(in), true);
				getLine(in);
				setData(PlotSilt, getLine(in), true);
				getLine(in);
				setData(PlotClay, getLine(in), true);
				getLine(in);
				setData(PlotRock, getLine(in), true);
				getLine(in);
				setData(PlotAggStab, getLine(in), true);
				getLine(in);
				setData(PlotAggGMD, getLine(in), true);
				getLine(in);
				setData(PlotAggMin, getLine(in), true);
				getLine(in);
				setData(PlotAggMax, getLine(in), true);
				getLine(in);
				setData(PlotAggStd, getLine(in), true);
				getLine(in);
				setData(PlotCrustFrac, getLine(in), true);
				getLine(in);
				setData(PlotCrustThk, getLine(in), true);
				getLine(in);
				setData(PlotLMFrac, getLine(in), true);
				getLine(in);
				setData(PlotLMMass, getLine(in), true);
				getLine(in);
				setData(PlotCrustDen, getLine(in), true);
				getLine(in);
				setData(PlotCrustStab, getLine(in), true);
				getLine(in);
				setData(PlotRandRough, getLine(in), true);
				getLine(in);
				setData(PlotRidgeHgt, getLine(in), true);
				getLine(in);
				setData(PlotRidgeSpc, getLine(in), true);
				getLine(in);
				setData(PlotRidgeWid, getLine(in), true);
				getLine(in);
				setData(PlotRidgeOrient, getLine(in), true);
				getLine(in);
			}
			in.close();
		} catch (IOException f) {
			//System.err.println("DS_rTF: " + lineNum + " " + f);
			f.printStackTrace();
		} catch (java.util.NoSuchElementException g) {
			//System.err.println("DS_rTF: " + lineNum + " " + g);
			g.printStackTrace();
		} catch (NullPointerException npe) {
                    npe.printStackTrace();
                    this.reset();
                }
		changes.firePropertyChange(DataChanged, "", "0");
	}

	/**
	 *
	 */
	public String[] validateMsgs = {
		"No error",
		"Crust fraction not equal 0 and crust thickness equals 0",
		"Crust fraction not equal 0 and crust density equals 0",
		"Crust fraction not equal 0 and crust stability equals 0",
		"Loose material fraction not 0 and loose material mass equals 0"
	};

	/**
	 *
	 */
	public String[] validateFields = {
		"",
		SurfCrustThk,
		SurfCrustDen,
		SurfCrustSta,
		SurfLMMass
	};

	/**
	 *
	 * @return
	 */
	public int validate() {

		String subRegStr = (String) ht.get(SubRegNum);
		int numSubr = Integer.parseInt(subRegStr);

		for (int rdx = 0; rdx < numSubr; rdx++) {

			double crsFra = Double.parseDouble(getData(SurfCrustFrac + "+" + rdx, true));
			double crsThk = Double.parseDouble(getData(SurfCrustThk + "+" + rdx, true));
			double crsDen = Double.parseDouble(getData(SurfCrustDen + "+" + rdx, true));
			double crsSta = Double.parseDouble(getData(SurfCrustSta + "+" + rdx, true));
			if (crsFra != 0.0) {
				if (crsThk == 0.0) {
					return 1;
				}
				if (crsDen == 0.0) {
					return 2;
				}
				if (crsSta == 0.0) {
					return 3;
				}
			}
			double looMat = Double.parseDouble(getData(SurfLMFrac + "+" + rdx, true));
			double looMas = Double.parseDouble(getData(SurfLMMass + "+" + rdx, true));
			if (looMat != 0.0) {
				if (looMas == 0.0) {
					return 4;
				}
			}
		}
		return 0;
	}

	private String calBD(String rockStr, String lepStr, String bdStr, int numLayers) {
		StringTokenizer rst = new StringTokenizer(rockStr);
		StringTokenizer lst = new StringTokenizer(lepStr);
		StringTokenizer bst = new StringTokenizer(bdStr);
		StringBuffer sb = new StringBuffer();
		for (int idx = 0; idx < numLayers; idx++) {
			double rf = Double.parseDouble(rst.nextToken());
			double lep = Double.parseDouble(lst.nextToken());
			double bd = Double.parseDouble(bst.nextToken());
			double dbd = 0;

			if (rf == 0.0) {
				dbd = bd * java.lang.Math.pow((lep / 100) + 1, 3);
			} else {
				dbd = bd * java.lang.Math.pow((lep / (100 * (1 - rf))) + 1, 3);
			}
			sb.append(dbd);
			sb.append(" ");
		}
		return sb.toString();
	}

	/**
	 * loads soil data from an IFC file
	 *
	 * @param inpFile
	 * @param subrIdx
	 */
	public void readIFCFile(TFile inpFile, int subrIdx) {
		lineNum = 0;
                if(inpFile.isDirectory()) {
                    System.err.println("ERROR: Cannot select directory. Please select file instead.");
                    return;
                }
		try {
			BufferedReader in = new BufferedReader(new TFileReader(inpFile));

			getLine(in);	// skip version
			setData(SoilIFCName + "+" + subrIdx, getLine(in), true);
			getLine(in);	// skip local phase
			getLine(in);	// skip soil order
			getLine(in);	// skip soil loss tolerance
			getLine(in);	// skip albedo
			getLine(in);	// skip slope
			getLine(in);	// skip surface fragment cover
			getLine(in);	// skip bedrock
			getLine(in);	// skip root restricting

            // Soil layers
			String inputStr = getLine(in);
			int numLayers = Integer.parseInt(inputStr.trim());
			if (numLayers > MaxLayers) {
				numLayers = 3;
			}
			setData(LayerNum + "+" + subrIdx, "" + numLayers, true);
			parseLayerLine(LayerOrigNum, " 1 2 3", numLayers, subrIdx);
			parseLayerLine(LayerThickness, getLine(in), numLayers, subrIdx);
			parseLayerLine(LayerSand, getLine(in), numLayers, subrIdx);
			parseLayerLine(LayerSilt, getLine(in), numLayers, subrIdx);
			parseLayerLine(LayerClay, getLine(in), numLayers, subrIdx);
			String rockStr = getLine(in);
			parseLayerLine(LayerRock, rockStr, numLayers, subrIdx);
			getLine(in);	// skip sand very coarse
			getLine(in);	// skip sand coarse
			getLine(in);	// skip sand medium
			getLine(in);	// skip sand fine
			parseLayerLine(LayerVFSand, getLine(in), numLayers, subrIdx);
//			parseLayerLine(LayerBD			, getLine(in), numLayers, subrIdx); 
			String bdStr = getLine(in);
			getLine(in);	// skip organic matter
			getLine(in);	// skip soil ph
			getLine(in);	// skip CaCO3
			getLine(in);	// skip CEC
//			getLine(in);	// skip linear ext
			String lepStr = getLine(in);
			String dbdStr = calBD(rockStr, lepStr, bdStr, numLayers);
			parseLayerLine(LayerBD, dbdStr, numLayers, subrIdx);
			parseLayerLine(LayerAggGMD, getLine(in), numLayers, subrIdx);
			parseLayerLine(LayerAggGSD, getLine(in), numLayers, subrIdx);
			parseLayerLine(LayerAggMax, getLine(in), numLayers, subrIdx);
			parseLayerLine(LayerAggMin, getLine(in), numLayers, subrIdx);
			parseLayerLine(LayerAggDen, getLine(in), numLayers, subrIdx);
			parseLayerLine(LayerAggSta, getLine(in), numLayers, subrIdx);

            // Soil crust
			setData(SurfCrustThk + "+" + subrIdx, getLine(in), true);
			setData(SurfCrustDen + "+" + subrIdx, getLine(in), true);
			setData(SurfCrustSta + "+" + subrIdx, getLine(in), true);
			setData(SurfCrustFrac + "+" + subrIdx, getLine(in), true);
			setData(SurfLMMass + "+" + subrIdx, getLine(in), true);
			setData(SurfLMFrac + "+" + subrIdx, getLine(in), true);
			setData(SurfARR + "+" + subrIdx, getLine(in), true);
			setData(SurfRidgOrient + "+" + subrIdx, getLine(in), true);
			setData(SurfRidgHgt + "+" + subrIdx, getLine(in), true);
			setData(SurfRidgSpacing + "+" + subrIdx, getLine(in), true);
			setData(SurfRidgWid + "+" + subrIdx, getLine(in), true);
			setData(SurfDikeSpacing + "+" + subrIdx, "0.0", true);

			getLine(in);	// skip init BD
			getLine(in);				// skip wc
			getLine(in);	// skip saturated SWC
			getLine(in);	// skip field capacity SWC
			parseLayerLine(LayerWPWC, getLine(in), numLayers, subrIdx);

			in.close();
		} catch (IOException f) {
			//System.err.println("DS_rTF: " + lineNum + " " + f);
			f.printStackTrace();
		} catch (java.util.NoSuchElementException g) {
			//System.err.println("DS_rTF: " + lineNum + " " + g);
			g.printStackTrace();
		}
	}

	private void writeLayer(PrintWriter outprt, String prop, int sdx, int numLay) {
		for (int idx = 0; idx < numLay; idx++) {
			outprt.print(" " + ht.get(prop + idx + "+" + sdx));
		}
		outprt.println();
	}

	Vector<BarrierPolygon> makeBarVec() {
		Vector<BarrierPolygon> barVec = new Vector<>();
		for (Object obj : ht.values()) {
			if (obj instanceof BarrierPolygon) {
				BarrierPolygon bp = (BarrierPolygon) obj;
//                if (bp.getX1() == 0.0 && bp.getX2() == 0.0 &&
//                        bp.getY1() == 0.0 && bp.getY2() == 0.0) continue;
				barVec.add(bp);
			}
		}
		return barVec;
	}

	/**
	 *
	 */
	public void clearBarriers() {
		List<String> keys = new Vector<String>();
		for (Object key : ht.keySet()) {
			Object obj = ht.get(key);
			if (obj instanceof BarrierPolygon) {
				//ki.remove();
				keys.add(key.toString());
			}
		}
		for (String key : keys) {
			setData(key, null);
		}
	}

	/**
	 *
	 * @param outFile
	 */
	public void writeTextFile(TFile outFile) {
            
		try {
			String fileName = outFile.getCanonicalPath();
			if (!fileName.endsWith(DataStore.InputExt)) {		// add .in if needed
				fileName += DataStore.InputExt;
				outFile = new TFile(fileName);
			}
			PrintWriter outprt = new PrintWriter(new BufferedWriter(new TFileWriter(outFile)));

			outprt.println("#****************************************************************");
			outprt.println("#  File name  " + outFile.getName() + "  Creation timestamp  " + new java.sql.Timestamp(System.currentTimeMillis()));
			outprt.println("#****************************************************************");
			outprt.println("#");
			outprt.println("#     +++ PURPOSE +++");
			outprt.println("#");
			outprt.println("#     Input file which is read by subroutine erodin.for");
			outprt.println("#");
			outprt.println("#     All lines beginning with a '#' character are assumed to");
			outprt.println("#     be comment lines and are skipped.");
			outprt.println("#");
			outprt.println("#     +++ DEFINITIONS +++");
			outprt.println("#");
			outprt.println("#     * = inputs NOT presently used by erosion");
			outprt.println("#         (most of these are expected to be used in the future)");
			outprt.println("#     All other input values must be correctly specified.");
			outprt.println("#");
			outprt.println("#     All comments prior to each line of data input");
			outprt.println("#     in this template input file have the following format:");
			outprt.println("#");
			outprt.println("#     Variable_Name, Var_type, (src include file)  Text Definition");
			outprt.println("#");
			outprt.println("#     where Var_type is: I = integer L = logical R = real");
			outprt.println("#");
			outprt.println("#");
			outprt.println("# +++ DEBUG STUFF +++");
			outprt.println("#");
			outprt.println("#     debugflg - debug flag for providing different levels of debug info");
			outprt.println("#                value of 0 will print no debug information");
			outprt.println("#                value of 1 will print out and number all input lines");
			outprt.println("#                value of 2 will print out and number all data input lines");
			outprt.println("#                value of 3 will do both 1 and 2 input line debug output");
//			outprt.println(" 0");
			outprt.println(" 3");
//			outprt.println(" " + ht.get(DebugCode));
			outprt.println("#");
			outprt.println("#");
			outprt.println("# +++ INIT STUFF +++");
			outprt.println("#");
			outprt.println("#     am0eif, L, (m1flag.inc) EROSION initialization flag");
			outprt.println(" .TRUE.");
//			outprt.println(" " + ht.get(InitFlg));
			outprt.println("#     am0efl, L, (m1flag.inc) EROSION 'print' flag");
			outprt.println(" 1");
//			outprt.println(" " + ht.get(PrintFlg));
			outprt.println("#");
			outprt.println("# +++ SIMULATION REGION +++");
			outprt.println("#");
			outprt.println("#     amxsim(x,y), R, (m1geo.inc) Simulation Region diag. coordinates (m)");
			outprt.println("#                     Input x,y coordinates in this form: x1,y1  x2,y2");
//			outprt.println("  0.0, 0.0, 1000.0, 200.0");

			FieldPolygon fp = (FieldPolygon) ht.get(SimField);
////System.out.println("DS_wTF: " + fp);            
			outprt.printf("%10.1f %10.1f %10.1f %10.1f\n", fp.getX1(), fp.getY1(), fp.getX2(), fp.getY2());
//			outprt.println(" " + ht.get(SimRegOrgX) + " " +ht.get(SimRegOrgY) + " "
//						   + ht.get(SimRegLenX) + " " + ht.get(SimRegLenY) + " ");
//			
			outprt.println("#");
			outprt.println("#     amasim, R, (m1geo.inc) Simulation Region orientation angle (deg. from North)");
			outprt.println(" " + ht.get(SimRegAngle));
//			outprt.println(" 0.0");
			outprt.println("#");
			outprt.println("# +++ ACCOUNTING REGIONS +++");
			outprt.println("#");
			outprt.println("#     nacctr, I, (m1geo.inc) Number of accounting regions (must be 1 for now)");
			outprt.println(" 1");
			outprt.println("#");
			outprt.println("#     amxar(x,y,a), R, (m1geo.inc) Accounting Region diag. coordinates (m)");
			outprt.println("#                     Input x,y coordinates in this form: x1,y1  x2,y2");
			outprt.println("#                     for each accounting region specified (nacctr)");
			// just use sim region for accounting region for now
			outprt.printf("%10.1f %10.1f %10.1f %10.1f\n", fp.getX1(), fp.getY1(), fp.getX2(), fp.getY2());
//
//            outprt.println(" " + ht.get(SimRegOrgX) + " " +ht.get(SimRegOrgY) + " "
//						   + ht.get(SimRegLenX) + " " + ht.get(SimRegLenY) + " ");
//			outprt.println(" 0.0, 0.0, 1000.0, 200.0");
			outprt.println("#");
			outprt.println("# +++ BARRIERS +++");
			outprt.println("#");
			outprt.println("#     nbr, I, (m1geo.inc) Number of barriers (0-5)");
			Vector<BarrierPolygon> barVec = makeBarVec();
			int barCnt = barVec.size();
////System.out.println("DS_wTF: barrier count " + barCnt);     
			outprt.println("" + barCnt);
//			String barriersStr = (String) ht.get(BarriersNum);
//			int numBarriers = Integer.parseInt(barriersStr);
//
//			outprt.println("  " + barriersStr);
			outprt.println("#     NOTE: Remaining BARRIER inputs are repeated for each barrier specified");
			outprt.println("#     If no barriers specified (nbr=0), then no BARRIER inputs will be here");
			outprt.println("#");
//			for (int bdx = 0; bdx < numBarriers; bdx++) {
			for (Object obj : barVec) {
				outprt.println("#     amxbr(x,y,b), R, (m1geo.inc) Barrier linear coordinates (m)");
				outprt.println("#                     Input x,y coordinates in this form: x1,y1  x2,y2");
				outprt.println("#                     for each barrier specified (nbr)");
				BarrierPolygon bp = (BarrierPolygon) obj;
				outprt.printf("%10.1f %10.1f %10.1f %10.1f %s\n", bp.getX1(), bp.getY1(),
						bp.getX2(), bp.getY2(), bp.getName());
//				outprt.println(" 0.0 0.0 0.0 200.0");
//				outprt.print(" " + ht.get(BarriersOrgX+bdx));
//				outprt.print(" " + ht.get(BarriersOrgY+bdx));
//				outprt.print(" " + ht.get(BarriersLenX+bdx));
//				outprt.print(" " + ht.get(BarriersLenY+bdx));
//				outprt.println();
				outprt.println("#       amzbr(b), R, (m1geo.inc) Barrier height (m)");
				outprt.println("#       ampbr(b), R, (m1geo.inc) Barrier porosity (m^2/m^2)");
				outprt.println("#       amxbrw(b), R, (m1geo.inc) Barrier width (m)");
				outprt.printf("%10.3f %10.3f %10.3f %s\n", bp.getHgt(), bp.getPorosity(),
						bp.getWid(), bp.getType());
//				outprt.print(" " + ht.get(BarriersHgt+bdx));
//				outprt.print(" " + ht.get(BarriersPors+bdx));
//				outprt.print(" " + ht.get(BarriersWid+bdx));
//				outprt.println();
//				outprt.println(" 0.2 0.5 15.0");
				outprt.println("#");
			}

			outprt.println("# +++ SUBREGION REGIONS +++");
			outprt.println("#");
			outprt.println("#     nsubr, I, (m1subr.inc) Number of subregions (1-5)");

			String subRegStr = (String) ht.get(SubRegNum);
			int numSubr = Integer.parseInt(subRegStr);

//			outprt.println(" 1");
			outprt.println(" " + subRegStr);
			outprt.println("#");
			outprt.println("#     NOTE: Remaining SUBREGION inputs (BIOMASS, SOIL, and HYDROLOGY,");
			outprt.println("#     ie. variables defined by subregion) are repeated for nsubr");
			outprt.println("#     subregions specified");
			outprt.println("#");
			outprt.println("#");
			for (int rdx = 0; rdx < numSubr; rdx++) {
				outprt.println("#     amxsr(x,y,s), R, (m1subr.inc) Subregion diag. coordinates (m)");
				outprt.println("#                     Input x,y coordinates in this form: x1,y1  x2,y2");
				outprt.println("#                     for each subregion specified (subr)");
//				outprt.println(" 0.0, 0.0, 1000.0, 200.0");
				// just use sim region for accounting region for now
//				outprt.println(" " + ht.get(SimRegOrgX) + " " +ht.get(SimRegOrgY) + " "
//							   + ht.get(SimRegLenX) + " " + ht.get(SimRegLenY) + " ");
				outprt.printf("%10.1f %10.1f %10.1f %10.1f\n", fp.getX1(), fp.getY1(), fp.getX2(), fp.getY2());
				outprt.println("#     +++ BIOMASS +++");
				outprt.println("#");
				outprt.println("#       abzht(s), R, (b1glob.inc) Overall biomass height (m)");
//			outprt.println(" 0.21");
				outprt.println(" " + ht.get(BiomassHgt + "+" + rdx));
				outprt.println("#");
				outprt.println("#       aczht(s), R, (c1glob.inc) Crop height (m)");
//			outprt.println(" 0");
				outprt.println(" " + ht.get(CropHgt + "+" + rdx));
				outprt.println("#");
				outprt.println("#       acrsai(s), R, (c1glob.inc) Crop stem area index (m^2/m^2)");
				outprt.println("#       acrlai(s), R, (c1glob.inc) Crop leaf area index (m^2/m^2)");
//			outprt.println(" 0 0");
				outprt.println(" " + ht.get(CropGSAI + "+" + rdx) + " " + ht.get(CropGLAI + "+" + rdx));
				outprt.println("#");
				outprt.println("#       adrsaitot(s), R, (d1glob.inc) Residue stem area index (m^2/m^2)");
				outprt.println("#       adrlaitot(s), R, (d1glob.inc) Residue leaf area index (m^2/m^2)");
//			outprt.println(" 0.02  0.00");
				outprt.println(" " + ht.get(BiomassRSAI + "+" + rdx) + " " + ht.get(BiomassRLAI + "+" + rdx));
				outprt.println("#");
				outprt.println("#      acxrow(s), R, (c1gen.inc) crop row spacing (m), 0=broadcast");
				outprt.println("#      ac0rg(s) , I, (c1gen.inc) seed location (0=furrow,1=ridge)");
//			outprt.println("  0.3, 0");
				outprt.println(" " + ht.get(CropRowSpacing + "+" + rdx) + " " + ht.get(CropRowPlacemnt + "+" + rdx));
				outprt.println("# These are not implemented within EROSION");
				outprt.println("#       abrsaz(h,s), R, (b1geom.inc) Biomass stem area index by ht (1/m)");
				outprt.println("# (should be 5 values here when used)");
				outprt.println("#       abrlaz(h,s), R, (b1geom.inc) Biomass leaf area index by ht (1/m)");
				outprt.println("# (should be 5 values here when used)");
				outprt.println("#");
				outprt.println("# Only abffcv(s) is currently implemented within EROSION");
				outprt.println("#       abffcv(s), R, (b1geom.inc) Flat biomass cover (m^3/m^3)");
				outprt.println("#       abfscv(s), R, (b1geom.inc) Standing biomass cover (m^3/m^3)");
				outprt.println("#       abftcv(s), R, (b1geom.inc) Total biomass cover (m^3/m^3)");
				outprt.println("# (should be 3 values here when abffcv(s) and abfscv(s) get used in the future)");
				outprt.println("# 0.098 with residue");
//			outprt.println(" 0.0 no residue");
//				outprt.println(" " + ht.get(BiomassTotal+"+"+rdx));
				outprt.println(" " + ht.get(BiomassFlat + "+" + rdx));
				outprt.println("#");
				outprt.println("#     +++ SOIL +++");
				outprt.println("#");
				outprt.println("#     nslay(s), I, (s1layr.inc) Number of soil layers (1-10)");
				String soilIFCName = (String) ht.get(SoilIFCName + "+" + rdx);
				outprt.println(" " + ht.get(LayerNum + "+" + rdx) + "  " + ((soilIFCName == null) ? "User created" : soilIFCName));
				int numLay = Integer.parseInt(((String) ht.get(LayerNum + "+" + rdx)).trim());
				if (numLay == 0) {
					numLay = 1;
//				outprt.println(" 1");
				}
				outprt.println("#");
				outprt.println("#     NOTE: Remaining SOIL inputs are repeated for each layer specified");
				outprt.println("#");
				outprt.println("#     aszlyt(l,s), R, (s1layr.inc) Soil layer thickness (mm)");
//				outprt.println(" 1000.0");
				writeLayer(outprt, LayerThickness, rdx, numLay);
				outprt.println("#");
				outprt.println("#     asdblk(l,s), R, (s1phys.inc) Soil layer bulk density (Mg/m^3)");
				writeLayer(outprt, LayerBD, rdx, numLay);
//				outprt.println(" 1.8");
				outprt.println("#");
				outprt.println("#     asfsan(l,s), R, (s1dbh.inc) Soil layer sand content (Mg/Mg)");
				writeLayer(outprt, LayerSand, rdx, numLay);
//				outprt.println(" 0.90");
				outprt.println("#     asfvfs(l,s), R  (s1dbh.inc) Soil layer very fine sand(Mg/Mg)");
				writeLayer(outprt, LayerVFSand, rdx, numLay);
//				outprt.println(" 0.21");
				outprt.println("#     asfsil(l,s), R, (s1dbh.inc) Soil layer silt content (Mg/Mg)");
				writeLayer(outprt, LayerSilt, rdx, numLay);
//				outprt.println(" 0.08");
				outprt.println("#     asfcla(l,s), R, (s1dbh.inc) Soil layer clay content (Mg/Mg)");
				writeLayer(outprt, LayerClay, rdx, numLay);
//				outprt.println(" 0.02");
				outprt.println("#");
				outprt.println("#     asvroc(l,s), R, (s1dbh.inc) Soil layer rock volume (m^3/m^3)");
				writeLayer(outprt, LayerRock, rdx, numLay);
//				outprt.println(" 0.30");
				outprt.println("#");
				outprt.println("#     asdagd(l,s), R, (s1agg.inc) Soil layer agg density (Mg/m^3)");
				writeLayer(outprt, LayerAggDen, rdx, numLay);
//				outprt.println(" 1.8");
				outprt.println("#     aseags(l,s), R, (s1agg.inc) Soil layer agg stability ln(J/kg)");
				writeLayer(outprt, LayerAggSta, rdx, numLay);
//				outprt.println(" 2.50");
				outprt.println("#     aslagm(l,s), R, (s1agg.inc) Soil layer GMD (mm)");
				writeLayer(outprt, LayerAggGMD, rdx, numLay);
//				outprt.println(" 0.47");
				outprt.println("#     aslagn(l,s), R, (s1agg.inc) Soil layer minimum agg size (mm)");
				writeLayer(outprt, LayerAggMin, rdx, numLay);
//				outprt.println(" 0.043");
				outprt.println("#     aslagx(l,s), R, (s1agg.inc) Soil layer maximum agg size (mm)");
				writeLayer(outprt, LayerAggMax, rdx, numLay);
//				outprt.println(" 89.8");
				outprt.println("#     as0ags(l,s), R, (s1agg.inc) Soil layer GSD (mm/mm)");
				writeLayer(outprt, LayerAggGSD, rdx, numLay);
//				outprt.println(" 12.0");
				outprt.println("#");
				outprt.println("#");
				outprt.println("#     asfcr(s), R, (s1surf.inc) Surface crust fraction (m^2/m^2)");
				outprt.println("#     aszcr(s), R, (s1surf.inc) Surface crust thickness (mm)");
				outprt.println("#     asflos(s), R, (s1surf.inc) Fraction of loose material on surface (m^2/m^2)");
				outprt.println("#     asmlos(s), R, (s1surf.inc) Mass of loose material on crust (kg/m^2)");
				outprt.println("#     asdcr(s), R, (s1surf.inc) Soil crust density (Mg/m^3)");
				outprt.println("#     asecr(s), R, (s1surf.inc) Soil crust stability ln(J/kg)");
				outprt.print(" " + ht.get(SurfCrustFrac + "+" + rdx));
				outprt.print(" " + ht.get(SurfCrustThk + "+" + rdx));
				outprt.print(" " + ht.get(SurfLMFrac + "+" + rdx));
				outprt.print(" " + ht.get(SurfLMMass + "+" + rdx));
				outprt.print(" " + ht.get(SurfCrustDen + "+" + rdx));
				outprt.print(" " + ht.get(SurfCrustSta + "+" + rdx));
				outprt.println();
//				outprt.println(" 0.6 7.0 0.2 0.4 0.1 1.0");
				outprt.println("#");
				outprt.println("#");
				outprt.println("#");
				outprt.println("#     aslrr(s), R, (s1sgeo.inc) Allmaras random roughness (mm)");
				outprt.println(" " + ht.get(SurfARR + "+" + rdx));
//				outprt.println(" 5.0");
				outprt.println("#     aszrgh(s), R, (s1sgeo.inc) Ridge height (mm)");
				outprt.println("#     asxrgs(s), R, (s1sgeo.inc) Ridge spacing (mm)");
				outprt.println("#     asxrgw(s), R, (s1sgeo.inc) Ridge width (mm)");
				outprt.println("#     asxrgo(s), R, (s1sgeo.inc) Ridge orientation (deg)");
//				outprt.println(" 0.0 0.0 0.0 0");
				outprt.print(" " + ht.get(SurfRidgHgt + "+" + rdx));
				outprt.print(" " + ht.get(SurfRidgSpacing + "+" + rdx));
				outprt.print(" " + ht.get(SurfRidgWid + "+" + rdx));
				outprt.print(" " + ht.get(SurfRidgOrient + "+" + rdx));
				outprt.println();
				outprt.println("#     asxdks(s), R, (s1sgeo.inc) Dike spacing (mm)");
				outprt.println(" " + ht.get(SurfDikeSpacing + "+" + rdx));
//				outprt.println(" 0.0");
				outprt.println("#");
				outprt.println("#     +++ HYDROLOGY +++");
				outprt.println("#");
				outprt.println("#     ahzsnd(s), R, (s1sgeo.inc) Snow depth (mm)");
				outprt.println(" " + ht.get(SurfSnowDepth + "+" + rdx));
//				outprt.println(" 0.0");
				outprt.println("#");
				outprt.println("#     ahrwcw(l,s), R, (h1db1.inc) Soil layer wilting point water content (Mg/Mg)");
//				outprt.println(" " + ht.get(HydroWPWC+"+"+rdx) + " 0.0 0.0");
				writeLayer(outprt, LayerWPWC, rdx, numLay);
//				outprt.println(" 0.077");
				outprt.println("#");
				outprt.println("#     ahrwca(l,s), R, (h1db1.inc) Soil layer water content (Mg/Mg)");
//				outprt.println(" " + ht.get(HydroLayerWC+"+"+rdx));
				outprt.println("  0.0 0.0 0.0");
//				outprt.println(" 0.0");
				outprt.println("#");
				outprt.println("#     ahrwc0(h,s), R, (h1db1.inc) Surface layer water content (Mg/Mg)");
				outprt.println("#                  NOTE: the near surface water content is specified on an");
				outprt.println("#                        hourly basis.  We read in the hrly water content");
				outprt.println("#                        on two lines, with 12 values in each line.");
				for (int jdx = 0; jdx < 24; jdx++) {
					outprt.print(" " + ht.get(SurfWC + jdx + "+" + rdx));
					if ((jdx % 12) == 11) {
						outprt.println();
					}
				}
//				outprt.println(" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0");
//				outprt.println(" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0");
				outprt.println("#");
			}

			outprt.println("#");
			outprt.println("# NOTE: This is the end of the SUBREGION variables");
			outprt.println("#");
			outprt.println("#     +++ WEATHER +++");
			outprt.println("#");
			outprt.println("#     awdair, R, (w1pavg.inc) Air density (kg/m^3)");
//			outprt.println(" 1.2");
			outprt.println(" " + ht.get(WeaAirDen));
			outprt.println("#");
			outprt.println("#     awadir, R, (w1wind.inc) Wind direction (deg)");
			outprt.println(" " + ht.get(WeaWindDir));
//			outprt.println(" 270");
			outprt.println("#");
			outprt.println("#     ntstep, I, (local variable) Number of intervals/day to run EROSION");
			outprt.println(" " + ht.get(WeaDailySteps));
//			outprt.println(" 24");
			outprt.println("#");
			outprt.println("#     anemht, R  anemometer height (m)");
			outprt.println("#     awzzo,  R  aerodynamic roughness at anemometer site (mm)");
			outprt.println("#     wzoflg, I (global variable) zo location flag");
			outprt.println("#               (flag =0 - zo fixed at wx sta. location)");
			outprt.println("#               (flag = 1 - zo variable at field location)");
			outprt.print(" " + ht.get(WeaAnemHgt));
			outprt.print(" " + ht.get(WeaAeroRough));
			outprt.print(" " + ht.get(WeaZoLocFlg));
			outprt.println();
//			outprt.println("    10.0,  10.00  0");
			outprt.println("#     wflg, I, (local variable) Wind/Weibull flag");
			outprt.println("#              (0 - read in Weibull parameters, 1 - read in wind speeds)");
//			String weiFlg = (String) ht.get(WeaWindWeibull);
//			outprt.println(" 1");
////System.out.println("DS_wTF: " + weiFlg);			
//			if (weiFlg.trim().equals("0")) {
//    			outprt.println(" " + weiFlg);
//				outprt.println("#");
//				outprt.println("# NOTE: This is only present when (wflg=0)");
//				outprt.println("#     wfcalm, R, (local variable) Fraction of time winds are calm (hr/hr)");
//				outprt.println("#     wuc, R, (local variable) Weibull 'c' factor (m/s)");
//				outprt.println("#     w0k, R, (local variable) Weibull 'k' factor (unitless)");
//				outprt.println("#");
//				outprt.println(" " + ht.get(WeaCalmWind) + " " + ht.get(WeaWeibullC) + " " + ht.get(WeaWeibullK));
//			} else {
			outprt.println(" " + "1" + " " + ht.get(WeaCalmWind) + " " + ht.get(WeaWeibullC) + " " + ht.get(WeaWeibullK));
			outprt.println("# NOTE: The remaining data is only present when (wflg=1)");
			outprt.println("#");
			outprt.println("#     awu(i), R, (w1wind) Wind speed for (ntstep) intervals (m/s)");
			outprt.println("# I think I can read multiple lines with variable number of values");
			outprt.println("# We will try and see - LEW  ( Note: no blank lines allowed - LH)");
			String windStr = (String) ht.get(WeaWindSpeeds);
			StringTokenizer wst = new StringTokenizer(windStr);
			for (int wdx = 0; wst.hasMoreTokens(); wdx++) {
				outprt.print(wst.nextToken() + (((wdx % 6) == 5) ? "\n" : "\t"));
			}
//				outprt.println(ht.get(WeaWindSpeeds));
//				outprt.println("8.181	4.068	4.068	4.426	5.052	5.052	");
//				outprt.println("4.739	4.292	4.515	3.353	3.621	2.280	");
//				outprt.println("5.275	6.750	7.242	7.868	9.835	13.814	");
//				outprt.println("17.211	12.651	11.712	12.964	10.014	8.583	");
			outprt.println("#");
//			}
			outprt.println("#    + + + DATA TO PLOT + + +");
			outprt.println("#");
			outprt.println("#    names and values to input for plot");
			outprt.println("# place 1 flag in 1st line after #-name line for variables to include in plot");
			outprt.println("#");
			outprt.println("#  initial xplot value,I, (-1=no plot, 0 = output indep.variables with 1 flag)");
			outprt.println(" -1");
//            outprt.println(" " + ht.get(PlotFlg));
//            outprt.println("####");
//            outprt.println("#    xin(i), R, (field length)");
////			outprt.println("   1");
//            outprt.println(" " + ht.get(PlotFieldLen));
//            outprt.println("  Length(m)");
//            outprt.println("# abzht, R, (biomass ht.(m))");
////			outprt.println("   1");
//            outprt.println(" " + ht.get(PlotBiomass));
//            outprt.println(" bio_ht(m)");
//            outprt.println("# abrsai, R (stem area index)");
////			outprt.println("  1");
//            outprt.println(" " + ht.get(PlotSAI));
//            outprt.println(" stem_area");
//            outprt.println("#   abrlai(s), R, (b1geom.inc) Biomass leaf area index (m^2/m^2)");
////			outprt.println("  1");
//            outprt.println(" " + ht.get(PlotLAI));
//            outprt.println(" lai_area");
//            outprt.println("# abffcv, R,( biomass flat fraction cover)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotFlatCover));
//            outprt.println(" flat_cov");
//            outprt.println("#     asfvfs(1,s), R, (soil fraction very fine sand in layer 1)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotVFSand));
//            outprt.println("  vfsand");
//            outprt.println("#     asfsan(1,s), R, (soil fraction sand in layer 1)");
////			outprt.println("  1");
//            outprt.println(" " + ht.get(PlotSand));
//            outprt.println("   sand");
//            outprt.println("#     asfsil(1,s), R (soil fraction silt in layer 1)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotSilt));
//            outprt.println("  silt");
//            outprt.println("#     asfcla(1,s), R (soil fraction clay in layer 1)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotClay));
//            outprt.println("  clay");
//            outprt.println("#     asvoc(1,s), R (soil volume roc in layer 1)(m^3/m^3)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotRock));
//            outprt.println("  rock_vol");
//            outprt.println("#     aseags(1,s), R (soil aggregate stability) (ln J/m^3)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotAggStab));
//            outprt.println("  ag_stab");
//            outprt.println("#     aslagm(1,s), R (soil aggregate geom. mean dia.) (mm)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotAggGMD));
//            outprt.println("  ag_gmd");
//            outprt.println("#     aslagn(1,s), R (soil aggregate min. dia.) (mm)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotAggMin));
//            outprt.println("  ag_min");
//            outprt.println("#     aslagx(1,s), R (soil aggregate max. dia.) (mm)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotAggMax));
//            outprt.println("  ag_max");
//            outprt.println("#     as0ags(1,s), R (soil aggregate geo. std. dev.)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotAggStd));
//            outprt.println("  ag_std");
//            outprt.println("#     asfcr(s), R, (s1surf.inc) Surface crust fraction (m^2/m^2)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotCrustFrac));
//            outprt.println("  crust_cv");
//            outprt.println("#     aszcr(s), R, (s1surf.inc) Surface crust thickness (mm)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotCrustThk));
//            outprt.println(" crust_z(mm)");
//            outprt.println("#     asflos(s), R, (s1surf.inc) Fraction of loose material on surface (m^2/m^2)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotLMFrac));
//            outprt.println("  los_cv");
//            outprt.println("#     asmlos(s), R, (s1surf.inc) Mass of loose material on crust (kg/m^2)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotLMMass));
//            outprt.println("  los(kg/m^2)");
//            outprt.println("#     asdcr(s), R, (s1surf.inc) Soil crust density (Mg/m^3)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotCrustDen));
//            outprt.println("  cr_den(Mg/m^3)");
//            outprt.println("#     asecr(s), R, (s1surf.inc) Soil crust stability ln(J/kg)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotCrustStab));
//            outprt.println("  cr_se");
//            outprt.println("#     aslrr(s), R, (s1sgeo.inc) Allmaras random roughness (mm)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotRandRough));
//            outprt.println("  rr(mm)");
//            outprt.println("#     aszrgh(s), R, (s1sgeo.inc) Ridge height (mm)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotRidgeHgt));
//            outprt.println("  z_rgh(mm)");
//            outprt.println("#     asxrgs(s), R, (s1sgeo.inc) Ridge spacing (mm)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotRidgeSpc));
//            outprt.println("  x_rgs(mm)");
//            outprt.println("#     asxrgw(s), R, (s1sgeo.inc) Ridge width (mm)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotRidgeWid));
//            outprt.println("  x_rgw(mm)");
//            outprt.println("#     asxrgo(s), R, (s1sgeo.inc) Ridge orientation (deg)");
////			outprt.println("  0");
//            outprt.println(" " + ht.get(PlotRidgeOrient));
//            outprt.println("  a_rgo(deg)");
//            outprt.println("#");
//            outprt.println("");
			outprt.close();
		} catch (java.io.IOException e) {
			//System.err.println("E_wF: " + e);
			e.printStackTrace();
		}
		changes.firePropertyChange(DataChanged, "", "0");

	}
	/**
	 * **** Data store methods *****
	 */
	Hashtable<String, Object> ht = new Hashtable<String, Object>(200);

	private String getData(String idxstr, boolean flag) {
		String s = (String) ht.get(idxstr);
		if (flag) {
			if (s == null) {
				s = "";
			}
			if (s.trim().length() == 0) {
				s = "0.0";
			}
		}
		return s;
	}

	private void setData(String idxstr, String newData) {
		setData(idxstr, newData, true);
	}

	private void setData(String idxstr, String newData, boolean trimNewData) {

		String oldData = "";

		if (newData == null) {
			ht.remove(idxstr);
		} else {
			if (trimNewData) {
				newData = newData.trim();      //1148, only trim when told to.
			}
			oldData = (String) ht.get(idxstr);
			if (newData.equals(oldData)) {
				return;
			}
			ht.put(idxstr, newData);
		}
               	changes.firePropertyChange(idxstr, oldData, newData);
		changes.firePropertyChange(DataChanged, "", "1");
	}

	private void setData(String idxstr, Object newData) {

		Object oldData = null;

		if (newData == null) {
			ht.remove(idxstr);
		} else {
			oldData = ht.get(idxstr);
//            if (newData instanceof BarrierPolygon || newData instanceof FieldPolygon) {
//                ht.put(idxstr, newData);
//            } else {
			if (newData.equals(oldData)) {
				return;
			}
			ht.put(idxstr, newData);
//            }

		}
		changes.firePropertyChange(idxstr, oldData, newData);
		changes.firePropertyChange(DataChanged, "", "1");
	}

	/**
	 * method to blank current record -- currently not implemented
	 */
	public void reset() {
		clearBarriers();
		init();
	}
	/**
	 * **** Property change support methods ****
	 */
	/**
	 * RunFileData throws a property change each time setData is called. Wrapper classes listen to
	 * determine if the the event is relevant to them.
	 */
	private final PropertyChangeSupport changes = new PropertyChangeSupport(this);

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

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

	/**
	 * Recognizes and takes appropriate actions on registered properties from different screens to
	 * update and synchronize data and GUI screens as needed.
	 *
	 * @param e The event itself that is responsible for triggering the change required for
	 * registered properties/components.
	 */
	@Override
	public void propertyChange(PropertyChangeEvent e) {

		String property = e.getPropertyName();
		if (property.equals(DataStore.SetFocus)) {
			changes.firePropertyChange(e);
			return;
		}
                if((e.getOldValue() == null) || (!e.getOldValue().equals(e.getNewValue())))
                {
                    //No need to churn if the data is identical.
                    try {
                            String value = (String) e.getNewValue();	
                            setData(property, value, true);
                    } catch (ClassCastException f) {
                            if (e.getSource() == this) {
                                    return;
                            }
                            setData(property, e.getNewValue());
                    }
                    changes.firePropertyChange(DataChanged, "", "1");
                }
	}
}
