package usda.weru.soil;

import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.TFileReader;
import de.schlichtherle.truezip.file.TFileWriter;
import java.awt.*;
import java.util.*;

import java.text.*;
import javax.swing.JPanel;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import java.beans.*;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
import usda.weru.util.*;

/**
 *
 * @author maxerdwien
 */
public class IFC {

    private static final Logger LOGGER = Logger.getLogger(IFC.class.getName());
    //Logs for errors and warnings.
    WepsMessageLog c_log = new WepsMessageLog();

    String errorsInIfcFile = "";	// list of variables adjusted on output
    String mySavedFilename = null;

    /**
     * definition for identifying info
     */
    static final int MaxInfo = 11;

    /**
     * state
     */
    public String state = "state";

    /**
     * county
     */
    public String county = "county";

    /**
     * soil survey area name
     */
    public String soilSurveyAreaName = "survey name";

    /**
     * soil surver ID
     */
    public String soilSurveyID = "survey ID";

    /**
     * Map Unit Symbols
     */
    public String mapUnitSymbol = "map symbol";

    /**
     * Component name
     */
    public String componentName = "component name";

    /**
     * component percent
     */
    public String componentPercent = "component percent";

    /**
     * taxorder
     */
    public String taxOrder = "tax order";

    /**
     * number of soil layers
     */
    public int nsl;

    /**
     * surface texture
     */
    public String surfaceTexture = "surface texture";

    /**
     *
     */
    public String localPhase = "local phase";

    /**
     *
     */
    public int soilLossTolerance = 0;

    // defintion for surface characteristics
    /**
     *
     */
    public final int MaxSurf = 16;

    /**
     * sct - soil crust thickness
     */
    public double crustThickness = 0.01;

    /**
     * scd - soil crust density
     */
    public double crustDensity = Double.NaN;

    /**
     * scs - soil crust stability
     */
    public double crustStability = Double.NaN;

    /**
     * scf - soil crust fraction
     */
    public double crustFraction = 0;

    /**
     * lmcm - loose material on crust - mass
     */
    public double crustLooseMaterialMass = 0;

    /**
     * lmcf - loose material on crust - fraction
     */
    public double crustLooseMaterialFraction = 0;

    /**
     * rr - random roughness
     */
    public double randomRoughness = 4.0;

    /**
     * ro - roughness orientation
     */
    public double roughnessOrientation = 0;

    /**
     * rh - roughness height
     */
    public double roughnessHeight = 0;

    /**
     * rs - roughness spacing
     */
    public double roughnessSpacing = 10.0;

    /**
     * rw - roughness width
     */
    public double roughnessWidth = 10.0;

    /**
     * sa - soil albedo
     */
    public double surfaceAlbedo = Double.NaN;

    /**
     * ss - soil slope
     * A negative slope is ignored by weps.
     */
    public double surfaceSlope = -1;

    /**
     *
     */
    public double surfaceFragmentCover = 0;

    /**
     *
     */
    public double bedrockDepth = 9999;

    /**
     *
     */
    public double impermiableDepth = 9999;

    // array of surface variables to interface with grid12
    //	double	survar[] = {sct, scd, scs, scf, lmcm, lmcf, rr,ro,rh,rs,rw,cng,cnp,sa,cns,crh,crsd,crsf};
    //  definition for ifc layers
    static final int MaxLayr = 30;

    /**
     * thickness in mm
     */
    public double layerThickness[];

    /**
     * depth of bottom of layer
     */
    public double layerDepthBottom[];

    /**
     * depth of top of layer
     */
    public double layerDepthTop[];

    /**
     * % sand
     */
    public double fractionSand[];

    /**
     * % silt
     */
    public double fractionSilt[];

    /**
     * % clay
     */
    public double fractionClay[];

    /**
     * rock %
     */
    public double fractionRock[];

    /**
     * sand fraction coarse
     */
    public double veryCoarseSandFraction[];

    /**
     * sand fraction coarse
     */
    public double coarseSandFraction[];

    /**
     * sand fraction medium
     */
    public double mediumSandFraction[];

    /**
     * sand fraction fine
     */
    public double fineSandFraction[];

    /**
     * sand fraction very find
     */
    public double veryFineSandFraction[];

    /**
     * bulk density dry
     */
    public double dryBulkDensity[];

    /**
     * initial density dry
     */
    public double initialBulkDensity[];

    /**
     * bulk density 1/3 bar
     */
    public double wetBulkDensity[];

    /**
     * aggregate mean diameter
     */
    public double aggregateMeanDiameter[];

    /**
     * aggregate standard deviation
     */
    public double aggregateStdDeviation[];

    /**
     * max aggregate size
     */
    public double maxAggregateSize[];

    /**
     * min aggregate size
     */
    public double minAggregateSize[];

    /**
     * aggregate density
     */
    public double aggregateDensity[];

    /**
     * aggregate stability
     */
    public double aggregateStability[];

    /**
     * initial soil water content (swc)
     */
    public double initialSWC[];

    /**
     * saturated swc
     */
    public double saturatedSWC[];

    /**
     * field capacity swc
     */
    public double fieldCapacitySWC[];

    /**
     * wilting point swc
     */
    public double wiltingPointSWC[];

    /**
     * 0.1 bar on sand soil
     */
    public double tenthBarSWC[];

    /**
     * soil CB
     */
    public double soilCB[];

    /**
     * air entry potential
     */
    public double airEntryPotential[];

    /**
     * sat hydraulic conductivity
     */
    public double saturatedHydraulicConductivity[];

    /**
     * organic matter
     */
    public double organicMaterial[];

    /**
     * soil pH
     */
    public double soilpH[];

    /**
     * calcium carbonate equiv
     */
    public double calciumCarbonateEquivalent[];

    /**
     * cation exchange capacity
     */
    public double cationExchangeCapacity[];

    /**
     * linear extensibility
     */
    public double linearExtensibility[];

    private boolean interact = false;

    public IFC() {
    }

    IFC(int inpnsl) {
        initIfc(inpnsl);
    }

    IFC(NASIS nasinp) {
        Util.debugPrint(true, nasinp.compname);
        errorsInIfcFile = nasinp.errIncFile;
        nsl = nasinp.adjlay;
        copyNasData(nasinp);
        convertUnits();
        calculateFactors();
        ER_crustLooseMaterialFraction.setHighValue(crustFraction);
        ER_crustFraction.setLowValue(crustLooseMaterialFraction);
        //System.out.println("IFC_IFC num_lay: " + nsl + errorsInIfcFile);

    }

    public void sendErrorsToInternalVariable() {
        for (WepsMessage message : c_log.getMessages(
                WepsMessage.MessageSeverity.ERROR, WepsMessage.MessageSeverity.WARNING)) {
            errorsInIfcFile += "# " + message.toString();
            if (!errorsInIfcFile.endsWith("\n")) {
                errorsInIfcFile += "\n";
            }
        }
    }

    private void initIfc(int inpnsl) {

        nsl = inpnsl;

        double[] tmpArr = new double[inpnsl];
        for (int idx = 0; idx < inpnsl; idx++) {
            tmpArr[idx] = Double.NaN;
        }

        // create layer arrays
        layerDepthTop = tmpArr.clone();			// depth to top of layer
        layerDepthBottom = tmpArr.clone();			// depth to bottom of layer
        layerThickness = tmpArr.clone();			// thickness in mm
        fractionSand = tmpArr.clone();			// % sand
        fractionSilt = tmpArr.clone();			// % silt
        fractionClay = tmpArr.clone();			// % clay
        fractionRock = tmpArr.clone();			// rock %
        veryCoarseSandFraction = tmpArr.clone();			// sand fraction coarse
        coarseSandFraction = tmpArr.clone();			// sand fraction coarse
        mediumSandFraction = tmpArr.clone();			// sand fraction medium
        fineSandFraction = tmpArr.clone();			// sand fraction fine
        veryFineSandFraction = tmpArr.clone();			// sand fraction very find
        dryBulkDensity = tmpArr.clone();			// bulk density dry
        initialBulkDensity = tmpArr.clone();			// bulk density dry
        wetBulkDensity = tmpArr.clone();			// bulk density 1/3 bar
        aggregateMeanDiameter = tmpArr.clone();			// aggregate mean diameter
        aggregateStdDeviation = tmpArr.clone();			// aggregate standard deviation
        maxAggregateSize = tmpArr.clone();		// max aggregate size
        minAggregateSize = tmpArr.clone();		// min aggregate size
        aggregateDensity = tmpArr.clone();		// aggregate density
        aggregateStability = tmpArr.clone();		// aggregate stability
        initialSWC = tmpArr.clone();			// initial soil water content (swc)
        saturatedSWC = tmpArr.clone();			// saturated swc
        fieldCapacitySWC = tmpArr.clone();			// field capacity swc
        wiltingPointSWC = tmpArr.clone();			// wilting point swc
        tenthBarSWC = tmpArr.clone();			// 0.1 bar on sand soil
        soilCB = tmpArr.clone();			// soil CB
        airEntryPotential = tmpArr.clone();			// air entry potential
        saturatedHydraulicConductivity = tmpArr.clone();			// sat hydraulic conductivity
        organicMaterial = tmpArr.clone();			// organic matter
        soilpH = tmpArr.clone();			// soil pH
        calciumCarbonateEquivalent = tmpArr.clone();			// calcium carbonate equiv
        cationExchangeCapacity = tmpArr.clone();			// cation exchange capacity
        linearExtensibility = tmpArr.clone();			// linear extensibility

    }

    private void writeArray(PrintWriter outprt, String nam, double arr[], int numdig) {

        outprt.println("# " + nam);
        for (int ldx = 0; ldx < nsl; ldx++) {	// check to make sure nsl is correct
            if (Double.isNaN(arr[ldx])) {
                throw new ArithmeticException("Soil property not found in one or more layers - " + nam);
            }
            outprt.print(Util.formatDouble(arr[ldx], numdig) + "     ");
        }
        outprt.println();
    }

    private void writeValue(PrintWriter outprt, String nam, double val, int numdig) {
        outprt.println("# " + nam);
        if (Double.isNaN(val)) {
            throw new ArithmeticException("Soil property not found in one or more layers - " + nam);
        }
        outprt.println(Util.formatDouble(val, numdig));
    }

    private void writeValue(PrintWriter outprt, String nam, int val) {
        outprt.println("# " + nam);
        outprt.println(val);
    }

    private void writeValue(PrintWriter outprt, String nam, String val) {
        outprt.println("# " + nam);
        outprt.println(val);
    }

    /**
     *
     * @return
     */
    public String getFileName() {
        StringBuilder filnam = new StringBuilder();
        filnam.append(componentName).append("_");
        filnam.append(mapUnitSymbol).append("_");
        filnam.append(componentPercent).append("_");
        filnam.append(surfaceTexture);
        return filnam.toString();
    }

    /**
     *
     * @param path
     * @param changes
     */
    public void writeNewIfc(String path, PropertyChangeSupport changes) throws ArithmeticException {
        if (new TFile(path).isDirectory()) {
            StringBuilder filnam = new StringBuilder();
            filnam.append(componentName).append("_");
            filnam.append(mapUnitSymbol).append("_");
            filnam.append(componentPercent).append("_");
            filnam.append(surfaceTexture);

            for (int idx = 0; idx < filnam.length(); idx++) {
                if (!Character.isLetterOrDigit(filnam.charAt(idx))) {
                    filnam.setCharAt(idx, '_');
                }
            }
            path = new TFile(path).getAbsolutePath().concat(de.schlichtherle.truezip.file.TFile.separator)
                    .concat(filnam.toString());
        }
        writeNewIfc(path);

        try {
            if (!path.endsWith(WepsFileChooser.getFileExtension(WepsFileChooser.Filetype.SOIL))) {
                path += WepsFileChooser.getFileExtension(WepsFileChooser.Filetype.SOIL);
            }
            if (changes != null) {
                changes.firePropertyChange(usda.weru.weps.RunFileData.SoilFile,
                        null,
                        new TFile(path).getCanonicalPath());
            }
        } catch (IOException e) {
        }
    }

    private String writeNotes() {
        StringTokenizer st = new StringTokenizer(errorsInIfcFile, "\n");

        StringBuilder sb = new StringBuilder("# Notes:\n");
        while (st.hasMoreTokens()) {
            sb.append("# " + st.nextToken() + "\n");
        }

        return sb.toString();
    }

    /**
     *
     * @param filePath
     */
    public void writeNewIfc(String filePath) throws ArithmeticException {

        //System.out.println("IFC_wNI: " + filePath);
        updateRecordFromGrid();

        adjustIfc();

        if (chkSoilandSandPcts()) {
            JOptionPane.showMessageDialog(new JPanel(),
                    "Output file not written",
                    "Error in soil or sand fractions", JOptionPane.ERROR_MESSAGE);
            errorsInIfcFile = "";
            return;
        }

        PrintWriter outprt = null;

        try {

            if (!filePath.endsWith(WepsFileChooser.getFileExtension(WepsFileChooser.Filetype.SOIL))) {
                filePath += WepsFileChooser.getFileExtension(WepsFileChooser.Filetype.SOIL);
            }

            outprt = new PrintWriter(new TFileWriter(new TFile(filePath)));

            outprt.println("Version: 1.0");
            outprt.println("#");
            outprt.println("# Soil ID");
            outprt.println(soilSurveyID + "-" + mapUnitSymbol + "-" + componentName
                    + "-" + componentPercent + "-" + surfaceTexture
                    + "-" + state + "-" + county + "-" + soilSurveyAreaName);
            outprt.println("#");

            writeValue(outprt, idList[9].title, localPhase);  // local phase
            writeValue(outprt, idList[8].title, taxOrder);  // tax order

            writeValue(outprt, idList[11].title, soilLossTolerance);
            writeValue(outprt, surfaceList[12].title, surfaceAlbedo, 3);
            writeValue(outprt, surfaceList[13].title, surfaceSlope, 3);
            writeValue(outprt, surfaceList[14].title, surfaceFragmentCover, 3);

            outprt.println("#");
            writeValue(outprt, surfaceList[15].title, bedrockDepth, 0);
            writeValue(outprt, surfaceList[16].title, impermiableDepth, 0);
            outprt.println("#");

            writeValue(outprt, layerList[0].title, nsl);  // number of layers
            writeArray(outprt, layerList[1].title, layerThickness, 0);  // soil characteristics by layer
            outprt.println("#");

            writeArray(outprt, layerList[3].title, fractionSand, 3);				// soil fractions
            writeArray(outprt, layerList[4].title, fractionSilt, 3);
            writeArray(outprt, layerList[5].title, fractionClay, 3);
            writeArray(outprt, layerList[6].title, fractionRock, 3);
            writeArray(outprt, layerList[7].title, veryCoarseSandFraction, 3);
            writeArray(outprt, layerList[8].title, coarseSandFraction, 3);
            writeArray(outprt, layerList[9].title, mediumSandFraction, 3);
            writeArray(outprt, layerList[10].title, fineSandFraction, 3);
            writeArray(outprt, layerList[11].title, veryFineSandFraction, 3);
            outprt.println("#");

            writeArray(outprt, layerList[12].title, wetBulkDensity, 3);
            writeArray(outprt, layerList[2].title, organicMaterial, 4);				// soil chemical properties
            writeArray(outprt, layerList[27].title, soilpH, 2);
            writeArray(outprt, layerList[28].title, calciumCarbonateEquivalent, 2);
            writeArray(outprt, layerList[29].title, cationExchangeCapacity, 2);
            writeArray(outprt, layerList[30].title, linearExtensibility, 3);
            outprt.println("#");

            writeArray(outprt, layerList[14].title, aggregateMeanDiameter, 3);	// aggregate characteristics
            writeArray(outprt, layerList[15].title, aggregateStdDeviation, 3);
            writeArray(outprt, layerList[16].title, maxAggregateSize, 3);
            writeArray(outprt, layerList[17].title, minAggregateSize, 3);
            writeArray(outprt, layerList[18].title, aggregateDensity, 3);
            writeArray(outprt, layerList[19].title, aggregateStability, 3);
            outprt.println("#");

            writeValue(outprt, surfaceList[1].title, crustThickness, 3);  // crust and surface characteristics
            writeValue(outprt, surfaceList[2].title, crustDensity, 3);
            writeValue(outprt, surfaceList[3].title, crustStability, 2);
            writeValue(outprt, surfaceList[4].title, crustFraction, 2);
            writeValue(outprt, surfaceList[5].title, crustLooseMaterialMass, 2);
            writeValue(outprt, surfaceList[6].title, crustLooseMaterialFraction, 2);
            outprt.println("#");

            writeValue(outprt, surfaceList[7].title, randomRoughness, 2);
            writeValue(outprt, surfaceList[8].title, roughnessOrientation, 2);
            writeValue(outprt, surfaceList[9].title, roughnessHeight, 2);
            writeValue(outprt, surfaceList[10].title, roughnessSpacing, 2);
            writeValue(outprt, surfaceList[11].title, roughnessWidth, 2);
            outprt.println("#");

            writeArray(outprt, layerList[13].title, initialBulkDensity, 3);  // hydrology by layers
            writeArray(outprt, layerList[20].title, initialSWC, 3);  // hydrology by layers
            writeArray(outprt, layerList[21].title, saturatedSWC, 3);
            writeArray(outprt, layerList[22].title, fieldCapacitySWC, 3);
            writeArray(outprt, layerList[23].title, wiltingPointSWC, 3);
            outprt.println("#");

            writeArray(outprt, layerList[24].title, soilCB, 3);
            writeArray(outprt, layerList[25].title, airEntryPotential, 3);
            writeArray(outprt, layerList[26].title, saturatedHydraulicConductivity, 10);
            outprt.println("#");

            outprt.println(writeNotes());
            outprt.close();
        } catch (FileNotFoundException e) {
            Util.debugPrint(true, e.toString());
        } catch (NullPointerException f) {
            Util.debugPrint(true, f.toString());
            f.printStackTrace();
        } catch (ArithmeticException g) {
            JOptionPane.showMessageDialog(new JPanel(),
                    "NaN (not a number) attempted to be written to IFC file\n" + g.getMessage(),
                    "Output file not written",
                    JOptionPane.ERROR_MESSAGE);
            outprt.close();
            try {
                (new TFile(filePath)).rm();
            } catch (IOException e) {

            }
        }
    }

    /**
     * reads line from file skipping comments
     */
    private String readLine(BufferedReader inpf) {
        String line;
        try {
            line = inpf.readLine();
        } catch (IOException e) {
            return null;
        }
        if (line == null || line.length() == 0) {
            return null;
        }
        if (line.charAt(0) == '#') {
            line = readLine(inpf);
        }
        return line;
    }

    /**
     * reads in a single double
     */
    private double readDouble(BufferedReader inpf) {
        String line = readLine(inpf);
        return Double.valueOf(line.trim()).doubleValue();
    }

    /**
     * reads in a line of doubles
     */
    private double[] readDoubles(BufferedReader inpf, int numlay) {
        double rtnval[] = new double[numlay];
        String line = readLine(inpf);
        java.util.StringTokenizer st = new java.util.StringTokenizer(line, " ");
        for (int ldx = 0; ldx < numlay; ldx++) {
            String dblstr = st.nextToken();
            rtnval[ldx] = Double.valueOf(dblstr.trim()).doubleValue();
        }
        return rtnval;

    }

    /**
     * parse Soil ID line
     */
    private void prsSoilID(String inplin, boolean newFlg) {
        if (!newFlg) {
            if (!inplin.startsWith("Soil ID ")) {
                return;
            }
            inplin = inplin.substring(8);
        }
        soilSurveyID = inplin.substring(0, inplin.indexOf('-'));
        inplin = inplin.substring(inplin.indexOf('-') + 1);
        mapUnitSymbol = inplin.substring(0, inplin.indexOf('-'));
        inplin = inplin.substring(inplin.indexOf('-') + 1);
        componentName = inplin.substring(0, inplin.indexOf('-'));
        inplin = inplin.substring(inplin.indexOf('-') + 1);
        componentPercent = inplin.substring(0, inplin.indexOf('-'));
        inplin = inplin.substring(inplin.indexOf('-') + 1);
        surfaceTexture = inplin.substring(0, inplin.indexOf('-'));
        inplin = inplin.substring(inplin.indexOf('-') + 1);
        state = inplin.substring(0, inplin.indexOf('-'));
        inplin = inplin.substring(inplin.indexOf('-') + 1);
        county = inplin.substring(0, inplin.indexOf('-'));
        inplin = inplin.substring(inplin.indexOf('-') + 1);
        soilSurveyAreaName = inplin.trim();
    }

    /**
     * reads ifc file
     */
    private void readNewIFC(BufferedReader inpf) {
        try {
            prsSoilID(readLine(inpf), true);

            localPhase = readLine(inpf);
            taxOrder = readLine(inpf);

            soilLossTolerance = Double.valueOf(readLine(inpf).trim()).intValue();
            surfaceAlbedo = readDouble(inpf);
            surfaceSlope = readDouble(inpf);
            surfaceFragmentCover = readDouble(inpf);

            bedrockDepth = readDouble(inpf);
            impermiableDepth = readDouble(inpf);

            nsl = Integer.valueOf(readLine(inpf).trim()).intValue();
            layerThickness = readDoubles(inpf, nsl);
            layerDepthTop = new double[nsl];
            layerDepthBottom = new double[nsl];

            fractionSand = readDoubles(inpf, nsl);
            fractionSilt = readDoubles(inpf, nsl);
            fractionClay = readDoubles(inpf, nsl);
            fractionRock = readDoubles(inpf, nsl);
            veryCoarseSandFraction = readDoubles(inpf, nsl);
            coarseSandFraction = readDoubles(inpf, nsl);
            mediumSandFraction = readDoubles(inpf, nsl);
            fineSandFraction = readDoubles(inpf, nsl);
            veryFineSandFraction = readDoubles(inpf, nsl);
            wetBulkDensity = readDoubles(inpf, nsl);

            organicMaterial = readDoubles(inpf, nsl);
            soilpH = readDoubles(inpf, nsl);
            calciumCarbonateEquivalent = readDoubles(inpf, nsl);
            cationExchangeCapacity = readDoubles(inpf, nsl);
            linearExtensibility = readDoubles(inpf, nsl);

            aggregateMeanDiameter = readDoubles(inpf, nsl);
            aggregateStdDeviation = readDoubles(inpf, nsl);
            maxAggregateSize = readDoubles(inpf, nsl);
            minAggregateSize = readDoubles(inpf, nsl);
            aggregateDensity = readDoubles(inpf, nsl);
            aggregateStability = readDoubles(inpf, nsl);

            crustThickness = readDouble(inpf);
            crustDensity = readDouble(inpf);
            crustStability = readDouble(inpf);
            crustFraction = readDouble(inpf);
            crustLooseMaterialMass = readDouble(inpf);
            crustLooseMaterialFraction = readDouble(inpf);

            randomRoughness = readDouble(inpf);
            roughnessOrientation = readDouble(inpf);
            roughnessHeight = readDouble(inpf);
            roughnessSpacing = readDouble(inpf);
            roughnessWidth = readDouble(inpf);

            initialBulkDensity = readDoubles(inpf, nsl);
            initialSWC = readDoubles(inpf, nsl);
            saturatedSWC = readDoubles(inpf, nsl);
            fieldCapacitySWC = readDoubles(inpf, nsl);
            wiltingPointSWC = readDoubles(inpf, nsl);

            soilCB = readDoubles(inpf, nsl);
            airEntryPotential = readDoubles(inpf, nsl);
            saturatedHydraulicConductivity = readDoubles(inpf, nsl);

            readNotes(inpf);
        } finally {
            try {
                inpf.close();
            } catch (IOException e) {
                LOGGER.log(Level.SEVERE, "Unable to close soil input stream.", e);
            }
        }
        //System.out.println(errorsInIfcFile);
    }

    private void readNotes(BufferedReader br) {
        try {
            String inpLin;
            // loops through the last lines of the ifc file, reading the notes.
            // for some reason, it adds the lines to 'errorsInIfcFile',
            // despite the fact that the lines are not errors.
            while (!"".equals(inpLin = br.readLine())) {
                if(inpLin == null) break;
                if (inpLin.charAt(0) != '#') {
                    continue;
                }
                if (inpLin.trim().equals("# Notes:")) {
                    continue;
                }
                errorsInIfcFile += inpLin.substring(1).trim() + '\n';
            }
        } catch (IOException e) {
        }
    }

    /**
     *
     * @param fname
     * @throws FileNotFoundException
     */
    public void readIfc(String fname) throws FileNotFoundException {
        if(fname.equals("")) return;
        readIfc(new TFile(fname));
    }

    /**
     * reads ifc file
     * @param file
     */
    public void readIfc(TFile file) {
        BufferedReader inpf = null;
        try {
            inpf = new BufferedReader(new TFileReader(file));

            String firstLine = readLine(inpf);
            if (firstLine.startsWith("Version")) {
                readNewIFC(inpf);
            } else {
                JOptionPane.showMessageDialog(new JPanel(),
                        "Old format soil file cannot be read\nCreate new soil file",
                        "Error - soil file not usable", JOptionPane.ERROR_MESSAGE);
                try {
                    inpf.close();
                } catch (IOException e) {
                    LOGGER.log(Level.SEVERE, "Unable to close soil file: " + file.getAbsolutePath(), e);
                }
            }
        } catch (FileNotFoundException e) {

        }
    }

    private void updateRecordFromGrid() {

        int col;

        if (GridID == null) {
            return;
        }
        for (col = 1; col <= MaxInfo; col++) {
            String label;
            try {
                label = GridID.getValue(0, col);
            } catch (NullPointerException e) {
                label = "Error " + col;
            }
            switch (col) {
                case 1:
                    state = label;
                    break;
                case 2:
                    county = label;
                    break;
                case 3:
                    soilSurveyAreaName = label;
                    break;
                case 4:
                    soilSurveyID = label;
                    break;
                case 5:
                    mapUnitSymbol = label;
                    break;
                case 6:
                    componentName = label;
                    break;
                case 7:
                    componentPercent = label;
                    break;
                case 8:
                    taxOrder = label;
                    break;
                case 9:
                    localPhase = label;
                    break;
                case 10:
                    surfaceTexture = label;
                    break;
                case 11:
                    soilLossTolerance = Integer.valueOf(label.trim()).intValue();
                    break;
            }
        }

        for (col = 1; col <= MaxSurf; col++) {
            String label;
            try {
                label = GridSurfProp.getValue(0, col);
            } catch (NullPointerException e) {
                label = "NaN";
            }
            double updval = 0;
            updval = Double.valueOf(label.trim()).doubleValue();
            //System.out.println("IFC_uRFG: " + col + " " + label + " " + up);
            switch (col) {
                case 1:
                    crustThickness = updval;
                    break;
                case 2:
                    crustDensity = updval;
                    break;
                case 3:
                    crustStability = updval;
                    break;
                case 4:
                    crustFraction = updval;
                    break;
                case 5:
                    crustLooseMaterialMass = updval;
                    break;
                case 6:
                    crustLooseMaterialFraction = updval;
                    break;
                case 7:
                    randomRoughness = updval;
                    break;
                case 8:
                    roughnessOrientation = updval;
                    break;
                case 9:
                    roughnessHeight = updval;
                    break;
                case 10:
                    roughnessSpacing = updval;
                    break;
                case 11:
                    roughnessWidth = updval;
                    break;
                case 12:
                    surfaceAlbedo = updval;
                    break;
                case 13:
                    surfaceSlope = updval;
                    break;
                case 14:
                    surfaceFragmentCover = updval;
                    break;
                case 15:
                    bedrockDepth = updval;
                    break;
                case 16:
                    impermiableDepth = updval;
                    break;
            }
        }

        Util.debugPrint(true, "nsl " + nsl);

        layerThickness = new double[nsl];			// thickness in mm
        layerDepthTop = new double[nsl];
        layerDepthBottom = new double[nsl];
        fractionSand = new double[nsl];			// % sand
        fractionSilt = new double[nsl];			// % silt
        fractionClay = new double[nsl];			// % clay
        fractionRock = new double[nsl];			// rock %
        veryCoarseSandFraction = new double[nsl];			// sand fraction coarse
        coarseSandFraction = new double[nsl];			// sand fraction coarse
        mediumSandFraction = new double[nsl];			// sand fraction medium
        fineSandFraction = new double[nsl];			// sand fraction fine
        veryFineSandFraction = new double[nsl];			// sand fraction very find
        dryBulkDensity = new double[nsl];		// bulk density dry
        wetBulkDensity = new double[nsl];			// bulk density 1/3 bar
        initialBulkDensity = new double[nsl];			// bulk density 1/3 bar
        aggregateMeanDiameter = new double[nsl];		// aggregate mean diameter
        aggregateStdDeviation = new double[nsl];		// aggregate standard deviation
        maxAggregateSize = new double[nsl];		// max aggregate size
        minAggregateSize = new double[nsl];		// min aggregate size
        aggregateDensity = new double[nsl];		// aggregate density
        aggregateStability = new double[nsl];		// aggregate stability
        initialSWC = new double[nsl];			// initial soil water content (swc)
        saturatedSWC = new double[nsl];			// saturated swc
        fieldCapacitySWC = new double[nsl];			// field capacity swc
        wiltingPointSWC = new double[nsl];			// wilting point swc
        tenthBarSWC = new double[nsl];			// 0.1 bar on sand soil
        soilCB = new double[nsl];			// soil CB
        airEntryPotential = new double[nsl];			// air entry potential
        saturatedHydraulicConductivity = new double[nsl];			// sat hydraulic conductivity
        organicMaterial = new double[nsl];			// organic matter
        soilpH = new double[nsl];			// soil pH
        calciumCarbonateEquivalent = new double[nsl];		// calcium carbonate equiv
        cationExchangeCapacity = new double[nsl];			// cation exchange capacity
        linearExtensibility = new double[nsl];

        for (int row = 0; row < nsl; row++) {
            for (col = 1; col <= MaxLayr; col++) {
                String label;
                try {
                    label = GridLayrProp.getValue(row, col);
                } catch (NullPointerException e) {
                    label = "NaN";
                }
                double updval = Double.valueOf(label.trim()).doubleValue();
                //System.out.print(GridLayrProp.getValue(row, col) + " ");
                switch (col) {
                    case 1:
                        layerThickness[row] = updval;
                        break;			// thickness in mm
                    case 2:
                        organicMaterial[row] = updval;
                        break;			// organic matter
                    case 3:
                        fractionSand[row] = updval;
                        break;			// % sand
                    case 4:
                        fractionSilt[row] = updval;
                        break;			// % silt
                    case 5:
                        fractionClay[row] = updval;
                        break;			// % clay
                    case 6:
                        fractionRock[row] = updval;
                        break;			// rock %
                    case 7:
                        veryCoarseSandFraction[row] = updval;
                        break;			// sand fraction coarse
                    case 8:
                        coarseSandFraction[row] = updval;
                        break;			// sand fraction coarse
                    case 9:
                        mediumSandFraction[row] = updval;
                        break;			// sand fraction medium
                    case 10:
                        fineSandFraction[row] = updval;
                        break;			// sand fraction fine
                    case 11:
                        veryFineSandFraction[row] = updval;
                        break;			// sand fraction very find
//				case 12 : dryBulkDensity[row] = updval; break;		// bulk density dry
                    case 12:
                        wetBulkDensity[row] = updval;
                        break;			// bulk density 1/3 bar
                    case 13:
                        initialBulkDensity[row] = updval;
                        break;			// bulk density 1/3 bar
                    case 14:
                        aggregateMeanDiameter[row] = updval;
                        break;		// aggregate mean diameter
                    case 15:
                        aggregateStdDeviation[row] = updval;
                        break;		// aggregate standard deviation
                    case 16:
                        maxAggregateSize[row] = updval;
                        break;		// max aggregate size
                    case 17:
                        minAggregateSize[row] = updval;
                        break;		// min aggregate size
                    case 18:
                        aggregateDensity[row] = updval;
                        break;		// aggregate density
                    case 19:
                        aggregateStability[row] = updval;
                        break;		// aggregate stability
                    case 20:
                        initialSWC[row] = updval;
                        break;			// initial soil water content (swc)
                    case 21:
                        saturatedSWC[row] = updval;
                        break;			// saturated swc
                    case 22:
                        fieldCapacitySWC[row] = updval;
                        break;			// field capacity swc
                    case 23:
                        wiltingPointSWC[row] = updval;
                        break;			// wilting point swc
                    case 24:
                        soilCB[row] = updval;
                        break;			// soil CB
                    case 25:
                        airEntryPotential[row] = updval;
                        break;			// air entry potential
                    case 26:
                        saturatedHydraulicConductivity[row] = updval;
                        break;			// sat hydraulic conductivity
                    case 27:
                        soilpH[row] = updval;
                        break;			// soil pH
                    case 28:
                        calciumCarbonateEquivalent[row] = updval;
                        break;		// calcium carbonate equiv
                    case 29:
                        cationExchangeCapacity[row] = updval;
                        break;			// cation exchange capacity
                    case 30:
                        linearExtensibility[row] = updval;
                        break;
                }
            }
        }
        //System.out.println("IFC_uRGF: " + NotesDisplay.getText());
        errorsInIfcFile = NotesDisplay.getText();
    }

    /**
     * updates surface variables
     * @param col
     * @param row
     * @param typ
     * @param label
     * @return
     */
    public boolean updateRecordFromGrid(int col, int row, int typ, String label) {
        interact = true;			// update from grid has occurred
        double updval = 0;
        switch (typ) {
            case 1:
                row -= GridID.getHeaderRowCount();
                break;
            case 2:
                row -= GridSurfProp.getHeaderRowCount();
                break;
            case 3:
                row -= GridLayrProp.getHeaderRowCount();
                break;
        }

        ER_crustLooseMaterialFraction.hiValue = crustFraction;
        ER_crustFraction.loValue = crustLooseMaterialFraction;

        int chkRng = checkRange(row, col, typ, label);
        if (chkRng != 0) {
            return false;
        }
        switch (typ) {
            case 1:
                checkRange(row, col, typ, label);
                switch (col) {
                    case 1:
                        state = label;
                        break;
                    case 2:
                        county = label;
                        break;
                    case 3:
                        soilSurveyAreaName = label;
                        break;
                    case 4:
                        soilSurveyID = label;
                        break;
                    case 5:
                        mapUnitSymbol = label;
                        break;
                    case 6:
                        componentName = label;
                        break;
                    case 7:
                        componentPercent = label;
                        break;
                    case 8:
                        taxOrder = label;
                        break;
                    case 9:
                        localPhase = label;
                        break;
                    case 10:
                        surfaceTexture = label;
                        break;
                    case 11:
                        soilLossTolerance = Integer.valueOf(label.trim()).intValue();
                        break;
                }
                break;
            case 2:
                updval = Double.valueOf(label.trim()).doubleValue();
                switch (col) {
                    case 1:
                        crustThickness = updval;
                        break;
                    case 2:
                        crustDensity = updval;
                        break;
                    case 3:
                        crustStability = updval;
                        break;
                    case 4:
                        crustFraction = updval;
                        break;
                    case 5:
                        crustLooseMaterialMass = updval;
                        break;
                    case 6:
                        crustLooseMaterialFraction = updval;
                        break;
                    case 7:
                        randomRoughness = updval;
                        break;
                    case 8:
                        roughnessOrientation = updval;
                        break;
                    case 9:
                        roughnessHeight = updval;
                        break;
                    case 10:
                        roughnessSpacing = updval;
                        break;
                    case 11:
                        roughnessWidth = updval;
                        break;
                    case 12:
                        surfaceAlbedo = updval;
                        break;
                    case 13:
                        surfaceSlope = updval;
                        break;
                    case 14:
                        surfaceFragmentCover = updval;
                        break;
                    case 15:
                        bedrockDepth = updval;
                        break;
                    case 16:
                        impermiableDepth = updval;
                        break;
                }
                break;
            case 3:
                updval = Double.valueOf(label.trim()).doubleValue();
                try {
                    switch (col) {
                        case 1:
                            layerThickness[row] = updval;
                            break;			// thickness in mm
                        case 2:
                            organicMaterial[row] = updval;
                            break;			// organic matter
                        case 3:
                            fractionSand[row] = updval;
                            break;			// % sand
                        case 4:
                            fractionSilt[row] = updval;
                            break;			// % silt
                        case 5:
                            fractionClay[row] = updval;
                            break;			// % clay
                        case 6:
                            fractionRock[row] = updval;
                            break;			// rock %
                        case 7:
                            veryCoarseSandFraction[row] = updval;
                            break;			// sand fraction coarse
                        case 8:
                            coarseSandFraction[row] = updval;
                            break;			// sand fraction coarse
                        case 9:
                            mediumSandFraction[row] = updval;
                            break;			// sand fraction medium
                        case 10:
                            fineSandFraction[row] = updval;
                            break;			// sand fraction fine
                        case 11:
                            veryFineSandFraction[row] = updval;
                            break;			// sand fraction very find
                        case 12:
                            wetBulkDensity[row] = updval;
                            break;			// bulk density 1/3 bar
                        case 13:
                            initialBulkDensity[row] = updval;
                            break;			// bulk density 1/3 bar
                        case 14:
                            aggregateMeanDiameter[row] = updval;
                            break;		// aggregate mean diameter
                        case 15:
                            aggregateStdDeviation[row] = updval;
                            break;		// aggregate standard deviation
                        case 16:
                            maxAggregateSize[row] = updval;
                            break;		// max aggregate size
                        case 17:
                            minAggregateSize[row] = updval;
                            break;		// min aggregate size
                        case 18:
                            aggregateDensity[row] = updval;
                            break;		// aggregate density
                        case 19:
                            aggregateStability[row] = updval;
                            break;		// aggregate stability
                        case 20:
                            initialSWC[row] = updval;
                            break;			// initial soil water content (swc)
                        case 21:
                            saturatedSWC[row] = updval;
                            break;			// saturated swc
                        case 22:
                            fieldCapacitySWC[row] = updval;
                            break;			// field capacity swc
                        case 23:
                            wiltingPointSWC[row] = updval;
                            break;			// wilting point swc
                        case 24:
                            soilCB[row] = updval;
                            break;			// soil CB
                        case 25:
                            airEntryPotential[row] = updval;
                            break;			// air entry potential
                        case 26:
                            saturatedHydraulicConductivity[row] = updval;
                            break;			// sat hydraulic conductivity
                        case 27:
                            soilpH[row] = updval;
                            break;			// soil pH
                        case 28:
                            calciumCarbonateEquivalent[row] = updval;
                            break;		// calcium carbonate equiv
                        case 29:
                            cationExchangeCapacity[row] = updval;
                            break;			// cation exchange capacity
                        case 30:
                            linearExtensibility[row] = updval;
                            break;			//
                    }
                } catch (java.lang.ArrayIndexOutOfBoundsException e) {
                }
                break;
        }
        return true;
    }

    /**
     * wjr
     * @param type
     * @return
     */
    public String[][] getGridValues(int type) {
        switch (type) {
            case 1: {
                int jdx = 0;
                String[][] gridValues = new String[1][];
                gridValues[0] = new String[MaxInfo + 1];
                gridValues[0][jdx++] = "blank";
                gridValues[0][jdx++] = state;
                gridValues[0][jdx++] = county;
                gridValues[0][jdx++] = soilSurveyAreaName;
                gridValues[0][jdx++] = soilSurveyID;
                gridValues[0][jdx++] = mapUnitSymbol;
                gridValues[0][jdx++] = componentName;
                gridValues[0][jdx++] = componentPercent;
                gridValues[0][jdx++] = taxOrder;
                gridValues[0][jdx++] = localPhase;
                gridValues[0][jdx++] = surfaceTexture;
                gridValues[0][jdx++] = Integer.toString(soilLossTolerance);
                return gridValues;
            }
            case 2: {
                int jdx = 0;
                String[][] gridValues = new String[1][];
                gridValues[0] = new String[MaxSurf + 1];
                gridValues[0][jdx++] = "blank";
                gridValues[0][jdx++] = Util.formatDouble(crustThickness, 3);
                gridValues[0][jdx++] = Util.formatDouble(crustDensity, 3);
                gridValues[0][jdx++] = Util.formatDouble(crustStability, 3);
                gridValues[0][jdx++] = Util.formatDouble(crustFraction, 3);
                gridValues[0][jdx++] = Util.formatDouble(crustLooseMaterialMass, 3);
                gridValues[0][jdx++] = Util.formatDouble(crustLooseMaterialFraction, 3);
                gridValues[0][jdx++] = Util.formatDouble(randomRoughness, 3);
                gridValues[0][jdx++] = Util.formatDouble(roughnessOrientation, 3);
                gridValues[0][jdx++] = Util.formatDouble(roughnessHeight, 3);
                gridValues[0][jdx++] = Util.formatDouble(roughnessSpacing, 3);
                gridValues[0][jdx++] = Util.formatDouble(roughnessWidth, 3);
                gridValues[0][jdx++] = Util.formatDouble(surfaceAlbedo, 3);
                gridValues[0][jdx++] = Util.formatDouble(surfaceSlope, 3);
                gridValues[0][jdx++] = Util.formatDouble(surfaceFragmentCover, 3);
                gridValues[0][jdx++] = Util.formatDouble(bedrockDepth, 0);
                gridValues[0][jdx++] = Util.formatDouble(impermiableDepth, 0);
                return gridValues;
            }
            case 3: {
                String[][] gridValues = new String[nsl][];
                for (int ldx = 0, jdx = 0; ldx < nsl; ldx++, jdx = 0) {
                    gridValues[ldx] = new String[MaxLayr + 1];
                    //System.out.println("nsl " + nsl + " ldx " + ldx + " jdx "
                    //+ jdx + " layerThickness.length " + lthk.length);
                    gridValues[ldx][jdx++] = "blank";
                    gridValues[ldx][jdx++] = Util.formatDouble(layerThickness[ldx], 0);
                    gridValues[ldx][jdx++] = Util.formatDouble(organicMaterial[ldx], 4);
                    gridValues[ldx][jdx++] = Util.formatDouble(fractionSand[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(fractionSilt[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(fractionClay[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(fractionRock[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(veryCoarseSandFraction[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(coarseSandFraction[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(mediumSandFraction[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(fineSandFraction[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(veryFineSandFraction[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(wetBulkDensity[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(initialBulkDensity[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(aggregateMeanDiameter[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(aggregateStdDeviation[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(maxAggregateSize[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(minAggregateSize[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(aggregateDensity[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(aggregateStability[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(initialSWC[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(saturatedSWC[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(fieldCapacitySWC[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(wiltingPointSWC[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(soilCB[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(airEntryPotential[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(saturatedHydraulicConductivity[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(soilpH[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(calciumCarbonateEquivalent[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(cationExchangeCapacity[ldx], 3);
                    gridValues[ldx][jdx++] = Util.formatDouble(linearExtensibility[ldx], 3);
                }
                return gridValues;
            }
        }
        return null;
    }

    static final ErrorRange[] idList = {
        new ErrorRange("Dummy"), // 0
        new ErrorRange("State"), // 1
        new ErrorRange("County"), // 2
        new ErrorRange("Soil Survery Area Name"), // 3
        new ErrorRange("Soil Survery ID"), // 4
        new ErrorRange("Map Unit Symbol"), // 5
        new ErrorRange("Component Name"), // 6
        new ErrorRange("Component Percent", 0.0, 100.0), // 7
        new ErrorRange("Soil Order"), // 8
        new ErrorRange("Local Phase"), // 9
        new ErrorRange("Surface texture"), // 15
        new ErrorRange("Soil Loss Tolerance (tons/acre/year)", 0, 5), // 16
    };

    static final ErrorRange[] layerList = {
        new ErrorRange("Number of layers", 1.0, 100.0), // 0
        new ErrorRange("Layer thickness (mm)", 0.0, 20000.0), // 1
        new ErrorRange("Organic matter (kg/kg)", 0.0, 1.0), // 2
        new ErrorRange("Sand fraction", 0.0, 1.0), // 3
        new ErrorRange("Silt fraction", 0.0, 1.0), // 4
        new ErrorRange("Clay fraction", 0.0, 1.0), // 5
        new ErrorRange("Rock fragments", 0.0, 1.0), // 6
        new ErrorRange("Sand fraction very coarse", 0.0, 1.0), // 7
        new ErrorRange("Sand fraction coarse", 0.0, 1.0), // 8
        new ErrorRange("Sand fraction medium", 0.0, 1.0), // 9
        new ErrorRange("Sand fraction fine", 0.0, 1.0), // 10
        new ErrorRange("Sand fraction very fine", 0.0, 1.0), // 11
        new ErrorRange("Bulk Density (1/3 bar)(Mg/m^3)", 0.1, 10.0), // 12
        new ErrorRange("Initial Bulk Density (1/3 bar)(Mg/m^3)", 0.1, 10.0), // 13
        new ErrorRange("Aggregate geometric mean diameter (mm)", 0.03, 30.0), // 14
        new ErrorRange("Aggregate geometric standard deviation", 1.0, 20.0), // 15
        new ErrorRange("Maximum aggregate size (mm)", 1.0, 1000.0), // 16
        new ErrorRange("Minimum aggregate size (mm)", 0.001, 5.0), // 17
        new ErrorRange("Aggregate density (Mg/m^3)", 0.6, 2.5), // 18
        new ErrorRange("Aggregate stability (ln(J/m^2))", 0.1, 7.0), // 19
        new ErrorRange("Initial soil water content (m^3/m^3)", 0.011, 0.379), // 20
        new ErrorRange("Saturation soil water content (m^3/m^3)", 0.208, 0.550), // 21
        new ErrorRange("Field capacity water content (m^3/m^3)", 0.012, 0.335), // 22
        new ErrorRange("Wilting point water content (m^3/m^3)", 0.005, 0.242), // 23
        new ErrorRange("Soil CB value (exponent to Campbell's SWRC)", 0.917, 27.027), // 24
        new ErrorRange("Air entry potential (J/kg)", -17.91, 0.0), // 25
        new ErrorRange("Saturated hydraulic conductivity (m/s)", 0.0, 0.001), // 26
        new ErrorRange("Soil PH (0-14)", 0.0, 14.0), // 27
        new ErrorRange("Calcium carbonate equivalent (CaCO3)", 0.0, 1.0), // 28
        new ErrorRange("Cation exchange capacity (CEC) (meq/100g)", 0.0, 400.0), // 29
        new ErrorRange("Linear extensibility", 0.0, 30.0), // 30
        new ErrorRange("end", 0.0, 0.0)};

    static final ErrorRange[] surfaceList = {
        //	new ErrorRange("0", 0.0, 0.0), // 0
        new ErrorRange("Dummy", 0.0, 23.0), // 0
        new ErrorRange("Crust thickness (mm)", 0.0, 23.0), // 1
        new ErrorRange("Crust density (Mg/m^3)", 0.6, 2.0), // 2
        new ErrorRange("Crust stability (ln(J/m^2))", 0.1, 7.0), // 3
        new ErrorRange("Crust surface fraction (m^2/m^2)", 0.0, 1.0), // 4
        new ErrorRange("Mass of loose material on crust (kg/m^2)", 0.0, 3.0), // 5
        new ErrorRange("Fraction of loose material on crust (m^2/m^2)", 0.0, 1.0), // 6
        new ErrorRange("Random roughness (mm)", 1.0, 30.0), // 7
        new ErrorRange("Ridge orientation (deg)", 0.0, 179.99), // 8
        new ErrorRange("Ridge height (mm)", 0.0, 500.0), // 9
        new ErrorRange("Spacing between ridge tops (mm)", 10.0, 2000.0), // 10
        new ErrorRange("Ridge width (mm)", 10.0, 4000.0), // 11
        new ErrorRange("Dry soil albedo (fraction)", 0.02, 1.0), // 12
        new ErrorRange("Slope gradient (fraction)", 0.0, 0.999), // 13
        new ErrorRange("Surface fragment cover or surface layer fragments (area fraction)", 0.0, 0.999),// 14
        new ErrorRange("Depth to bedrock (mm)", 0.0, 99999), // 15
        new ErrorRange("Depth to root restricting layer (mm)", 0.0, 99999), // 16
        new ErrorRange("end", 0.0, 0.0)};

    static final ErrorRange ER_crustLooseMaterialFraction = surfaceList[6];				// loose material fraction
    static final ErrorRange ER_crustFraction = surfaceList[4];				// soil crust surface fraction

    /**
     *
     * @param row
     * @param col
     * @param type
     * @param label
     * @return
     */
    public int checkRange(int row, int col, int type, String label) {
        ErrorRange[] rangeList = null;
        switch (type) {
            case 1:
                rangeList = idList;
                break;
            case 2:
                rangeList = surfaceList;
                break;
            case 3:
                rangeList = layerList;
                break;
        }
        return rangeList[col].errorBox(label);
    }

    /**
     *
     * @param type
     * @return
     */
    public ErrorRange[] getToolTipText(int type) {
        switch (type) {
            case 1:
                return idList.clone();
            case 2:
                return surfaceList.clone();
            case 3:
                return layerList.clone();
        }
        return null;
    }

    private boolean chkSoilandSandPcts() {
        NumberFormat.getInstance().setMaximumFractionDigits(4);
        for (int ldx = 0; ldx < nsl; ldx++) {
            if (Math.abs(fractionSand[ldx] + fractionSilt[ldx] + fractionClay[ldx] - 1.0) > 0.0001) {
                WepsMessage msg = WepsMessage.warningMessage("Bad soil fractions for layer "
                        + (ldx + 1) + " sand " + Util.formatDouble(fractionSand[ldx], 4)
                        + " silt " + Util.formatDouble(fractionSilt[ldx], 4) + " clay "
                        + Util.formatDouble(fractionClay[ldx], 4));
                c_log.logMessage(msg);
                if (interact) {
                    JOptionPane.showMessageDialog(new JPanel(),
                            "Sand, silt and clay fractions do not add to 1.0 on layer " + (ldx + 1),
                            "Check soil fractions", JOptionPane.ERROR_MESSAGE);
                    return true;
                }

            }

            if (veryCoarseSandFraction[ldx] + coarseSandFraction[ldx] + mediumSandFraction[ldx]
                    + fineSandFraction[ldx] + veryFineSandFraction[ldx] > fractionSand[ldx] + 0.0001) {
                WepsMessage msg = WepsMessage.warningMessage("sand fractions exceed total sand for layer "
                        + (ldx + 1) + " sand " + Util.formatDouble(fractionSand[ldx], 4)
                        + " veryCoarseSandFraction " + Util.formatDouble(veryCoarseSandFraction[ldx], 4)
                        + " coarseSandFraction " + Util.formatDouble(coarseSandFraction[ldx], 4)
                        + " mediumSandFraction " + Util.formatDouble(mediumSandFraction[ldx], 4)
                        + " fineSandFraction " + Util.formatDouble(fineSandFraction[ldx], 4)
                        + " veryFineSandFraction " + Util.formatDouble(veryFineSandFraction[ldx], 4));
                c_log.logMessage(msg);
                if (interact) {
                    JOptionPane.showMessageDialog(new JPanel(),
                            "Sand fractions exceed total soil-sand fraction on layer " + (ldx + 1),
                            "Check sand fractions", JOptionPane.ERROR_MESSAGE);
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * adjust values in all rows noting errors
     */
    public void adjustIfc() {
        double rtnval;

        for (int ldx = 0; ldx < nsl; ldx++) {
            rtnval = layerList[14].adjValue(aggregateMeanDiameter[ldx]);
            if (rtnval != aggregateMeanDiameter[ldx]) {

                String msgText = layerList[14].title + " adjusted: old value "
                        + Util.formatDouble(aggregateMeanDiameter[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                aggregateMeanDiameter[ldx] = rtnval;
            }

            rtnval = layerList[15].adjValue(aggregateStdDeviation[ldx]);
            if (rtnval != aggregateStdDeviation[ldx]) {
                String msgText = layerList[15].title + " adjusted: old value "
                        + Util.formatDouble(aggregateStdDeviation[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                aggregateStdDeviation[ldx] = rtnval;
            }

            rtnval = layerList[16].adjValue(maxAggregateSize[ldx]);
            if (rtnval != maxAggregateSize[ldx]) {
                String msgText = layerList[16].title + " adjusted: old value "
                        + Util.formatDouble(maxAggregateSize[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                maxAggregateSize[ldx] = rtnval;
            }

            rtnval = layerList[17].adjValue(minAggregateSize[ldx]);
            if (rtnval != minAggregateSize[ldx]) {
                String msgText = layerList[17].title + " adjusted: old value "
                        + Util.formatDouble(minAggregateSize[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                minAggregateSize[ldx] = rtnval;
            }

            rtnval = layerList[18].adjValue(aggregateDensity[ldx]);
            if (rtnval != aggregateDensity[ldx]) {
                String msgText = layerList[18].title + " adjusted: old value "
                        + Util.formatDouble(aggregateDensity[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                aggregateDensity[ldx] = rtnval;
            }

            rtnval = layerList[19].adjValue(aggregateStability[ldx]);
            if (rtnval != aggregateStability[ldx]) {
                String msgText = layerList[19].title + " adjusted: old value "
                        + Util.formatDouble(aggregateStability[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                aggregateStability[ldx] = rtnval;
            }
        }
        rtnval = surfaceList[2].adjValue(crustDensity);
        if (rtnval != crustDensity) {
            String msgText = surfaceList[2].title + " adjusted: old value "
                    + Util.formatDouble(crustDensity, 4) + " new value " + rtnval;
            c_log.logMessage(WepsMessage.warningMessage(msgText));
            crustDensity = rtnval;
        }
        rtnval = surfaceList[3].adjValue(crustStability);
        if (rtnval != crustStability) {
            String msgText = surfaceList[3].title + " adjusted: old value "
                    + Util.formatDouble(crustStability, 4) + " new value " + rtnval;
            c_log.logMessage(WepsMessage.warningMessage(msgText));
            crustStability = rtnval;
        }

    }

    /**
     * wjr
     * @param pj
     */
    public void printIfc(PrintJob pj) {
        int vpos = 40;
        int hpos = 20;
        int vheight = 12;
        Graphics po = pj.getGraphics();
        po.setFont(new Font("monospaced", Font.BOLD, 20));
        po.drawString("Initial Field Conditions Data", hpos, 35);
        po.setFont(new Font("monospaced", Font.PLAIN, vheight - 2));

        po.drawString("Soil ID " + soilSurveyID + "-" + mapUnitSymbol + "-" + componentName
                + "-" + componentPercent + "-" + surfaceTexture
                + "-" + state + "-" + county + "-" + soilSurveyAreaName, hpos, vpos += vheight);
        po.drawString("Taxorder " + taxOrder, hpos, vpos += vheight);
        po.drawString("Number of soil layers " + nsl, hpos, vpos += vheight);

        printArray(po, layerList[1].title, layerThickness, 0, hpos, vpos += vheight);  // soil characteristics by layer
        printArray(po, layerList[2].title, organicMaterial, 3, hpos, vpos += vheight);
        printArray(po, layerList[3].title, fractionSand, 3, hpos, vpos += vheight);
        printArray(po, layerList[4].title, fractionSilt, 3, hpos, vpos += vheight);
        printArray(po, layerList[5].title, fractionClay, 3, hpos, vpos += vheight);
        printArray(po, layerList[6].title, fractionRock, 3, hpos, vpos += vheight);
        printArray(po, layerList[7].title, veryCoarseSandFraction, 3, hpos, vpos += vheight);
        printArray(po, layerList[8].title, coarseSandFraction, 3, hpos, vpos += vheight);
        printArray(po, layerList[9].title, mediumSandFraction, 3, hpos, vpos += vheight);
        printArray(po, layerList[10].title, fineSandFraction, 3, hpos, vpos += vheight);
        printArray(po, layerList[11].title, veryFineSandFraction, 3, hpos, vpos += vheight);
        printArray(po, layerList[12].title, wetBulkDensity, 3, hpos, vpos += vheight);
        printArray(po, layerList[13].title, initialBulkDensity, 3, hpos, vpos += vheight);
        printArray(po, layerList[14].title, aggregateMeanDiameter, 3, hpos, vpos += vheight);
        printArray(po, layerList[15].title, aggregateStdDeviation, 3, hpos, vpos += vheight);
        printArray(po, layerList[16].title, maxAggregateSize, 3, hpos, vpos += vheight);
        printArray(po, layerList[17].title, minAggregateSize, 3, hpos, vpos += vheight);
        printArray(po, layerList[18].title, aggregateDensity, 3, hpos, vpos += vheight);
        printArray(po, layerList[19].title, aggregateStability, 3, hpos, vpos += vheight);

//po.dispose();
        printValue(po, surfaceList[0].title, crustThickness, 3, hpos, vpos += vheight);  // crust and surface characteristics
        printValue(po, surfaceList[1].title, crustDensity, 3, hpos, vpos += vheight);
        printValue(po, surfaceList[2].title, crustStability, 2, hpos, vpos += vheight);
        printValue(po, surfaceList[3].title, crustFraction, 2, hpos, vpos += vheight);
        printValue(po, surfaceList[4].title, crustLooseMaterialMass, 2, hpos, vpos += vheight);
        printValue(po, surfaceList[5].title, crustLooseMaterialFraction, 2, hpos, vpos += vheight);
        printValue(po, surfaceList[6].title, randomRoughness, 2, hpos, vpos += vheight);
        printValue(po, surfaceList[7].title, roughnessOrientation, 2, hpos, vpos += vheight);
        printValue(po, surfaceList[8].title, roughnessHeight, 2, hpos, vpos += vheight);
        printValue(po, surfaceList[9].title, roughnessSpacing, 2, hpos, vpos += vheight);
        printValue(po, surfaceList[10].title, roughnessWidth, 2, hpos, vpos += vheight);

        printArray(po, layerList[20].title, initialSWC, 3, hpos, vpos += vheight);  // hydrology by layers
        printArray(po, layerList[21].title, saturatedSWC, 3, hpos, vpos += vheight);
        printArray(po, layerList[22].title, fieldCapacitySWC, 3, hpos, vpos += vheight);
        printArray(po, layerList[23].title, wiltingPointSWC, 3, hpos, vpos += vheight);
        printArray(po, layerList[24].title, soilCB, 3, hpos, vpos += vheight);
        printArray(po, layerList[25].title, airEntryPotential, 3, hpos, vpos += vheight);
        printArray(po, layerList[26].title, saturatedHydraulicConductivity, 10, hpos, vpos += vheight);

        printValue(po, surfaceList[11].title, surfaceAlbedo, 3, hpos, vpos += vheight);
        printValue(po, surfaceList[12].title, surfaceSlope, 3, hpos, vpos += vheight);

        printArray(po, layerList[27].title, soilpH, 2, hpos, vpos += vheight);
        printArray(po, layerList[28].title, calciumCarbonateEquivalent, 2, hpos, vpos += vheight);
        printArray(po, layerList[29].title, cationExchangeCapacity, 2, hpos, vpos += vheight);
        printArray(po, layerList[30].title, linearExtensibility, 3, hpos, vpos += vheight);

        po.dispose();
    }

    private void printArray(Graphics po, String nam, double arr[], int numdig, int hpos, int vpos) {

        StringBuilder sb = new StringBuilder(nam + " ");
        for (int ldx = 0; ldx < arr.length; ldx++) {
            sb.append(Util.formatDouble(arr[ldx], numdig) + "  ");
        }
        po.drawString(sb.toString(), hpos, vpos);
    }

    private void printValue(Graphics po, String nam, double val, int numdig, int hpos, int vpos) {
        String outstr = nam;
        outstr += " " + Util.formatDouble(val, numdig);
        po.drawString(outstr, hpos, vpos);
    }

    private void copyNasData(NASIS nasinp) {

        // create ifc structure
        initIfc(nsl);

        layerDepthBottom = nasinp.hzdepb.clone();
        layerThickness[0] = nasinp.hzdepb[0];
        for (int ldx = 1; ldx < nsl; ldx++) {					// fill in top depth & thickness
            layerDepthTop[ldx] = nasinp.hzdepb[ldx - 1];					// current top is previous bottom
            layerThickness[ldx] = nasinp.hzdepb[ldx] - layerDepthTop[ldx];	// thickness is bottom - top
        }

        fractionClay = nasinp.claytotal.clone();			// clay
        fractionSand = nasinp.sandtotal.clone();			// sand
        for (int ldx = 0; ldx < nsl; ldx++) {				// remainder is silt
            if (fractionClay[ldx] < 1) {
                fractionClay[ldx] = 1;				// define minimum clay to be 1%
            }
            if (fractionSand[ldx] > 99) {
                fractionSand[ldx] = 99;				// define maximum sand to be 99%
            }
            fractionSilt[ldx] = 100 - (fractionClay[ldx] + fractionSand[ldx]);
            if (fractionSilt[ldx] < 0) {
                fractionSilt[ldx] = Double.NaN;
            }
        }
        fractionRock = nasinp.fragvol.clone();				// rock %
        veryCoarseSandFraction = nasinp.sandvco.clone();				// coarseSandFraction
        coarseSandFraction = nasinp.sandco.clone();				// coarseSandFraction
        mediumSandFraction = nasinp.sandmed.clone();				// mediumSandFraction
        fineSandFraction = nasinp.sandfine.clone();				// fineSandFraction
        veryFineSandFraction = nasinp.sandvf.clone();				// veryFineSandFraction
        wetBulkDensity = nasinp.dbthirdbar.clone();			// wetBulkDensity
        initialBulkDensity = nasinp.dbthirdbar.clone();			// wetBulkDensity
        tenthBarSWC = nasinp.wtenthbar.clone();			// b1ss
        fieldCapacitySWC = nasinp.wthirdbar.clone();			// fieldCapacitySWC
        wiltingPointSWC = nasinp.w15thbar.clone();				// wiltingPointSWC
        saturatedHydraulicConductivity = nasinp.ksat.clone();					// satk
        organicMaterial = nasinp.om.clone();						// om
        linearExtensibility = nasinp.lep.clone();					// lep

        double[] phtmp = new double[nasinp.adjlay];
        for (int ldx = 0; ldx < nasinp.adjlay; ldx++) {
            // ph
            phtmp[ldx] = (!Double.isNaN(nasinp.ph1to1h2o[ldx])) ? nasinp.ph1to1h2o[ldx] : nasinp.ph01mcacl2[ldx];
        }

        soilpH = phtmp;

        double[] cectmp = new double[nasinp.adjlay];
        for (int ldx = 0; ldx < nasinp.adjlay; ldx++) {
            cectmp[ldx] = (!Double.isNaN(nasinp.cec7[ldx]))
                    ? nasinp.cec7[ldx] : nasinp.ecec[ldx];			// cec
        }
        cationExchangeCapacity = cectmp;

// I think this should be commented out because of above code to deal with populated cec7 and ecec fields varying by layer
// So, I will do so and test it - LEW
//	if (nasinp.cec7[0] > 0)											// cec
//		cec = nasinp.cec7/*.clone()*/;
//	else
//		cec = nasinp.ecec/*.clone()*/;
////System.out.println("cND: " + nasinp.calciumCarbonateEquivalent[cdx]
        calciumCarbonateEquivalent = nasinp.caco3/*.clone()*/;				// caco3

        state = nasinp.state;
        county = nasinp.county;
        soilSurveyAreaName = nasinp.ssaname;
        soilSurveyID = nasinp.ssaid;
        mapUnitSymbol = nasinp.musym;
        componentName = nasinp.compname;
        componentPercent = nasinp.comppct;
        taxOrder = nasinp.taxorder;
        surfaceAlbedo = nasinp.albedodry;
        surfaceSlope = nasinp.slope;
        surfaceTexture = nasinp.texture[0];				// surface texture
        localPhase = nasinp.localphase;

        //1143.2
        bedrockDepth = nasinp.bedrockDepth;
        impermiableDepth = nasinp.impermiableDepth;

        soilLossTolerance = (int) nasinp.losstolerance;

    }

    private void convertUnits() {

////System.out.println("split nsl: " + nsl);
        for (int ldx = 0; ldx < nsl; ldx++) {
            layerThickness[ldx] *= 10.;				// thk				// cvt from cm to mm
            layerDepthBottom[ldx] *= 10.;				// depb
            layerDepthTop[ldx] *= 10.;				// dept
            fractionSand[ldx] /= 100.;				// sand				// cvt from % to fraction
            fractionClay[ldx] /= 100.;				// clay
            fractionSilt[ldx] /= 100.;				// silt
            fractionRock[ldx] /= 100.;				// rock
            veryCoarseSandFraction[ldx] /= 100.;				// sand coarse
            coarseSandFraction[ldx] /= 100.;				// sand coarse
            mediumSandFraction[ldx] /= 100.;				// sand medium
            fineSandFraction[ldx] /= 100.;				// sand fine
            veryFineSandFraction[ldx] /= 100.;				// sand very fine
//		[ldx]/= 100.;					// water dispersible clay
            fieldCapacitySWC[ldx] /= 100.;				// field capacity swc
            wiltingPointSWC[ldx] /= 100.;				// wilting point swc
            organicMaterial[ldx] /= 100.;				// organic matter
            calciumCarbonateEquivalent[ldx] /= 100.;				// caco3
            saturatedHydraulicConductivity[ldx] /= 1000000.;			// saturation k		// cvt from ppm to p
            //linearExtensibility[ldx] /= 100;	// linear extensibility, 1143.3 commented out so that units remain as LEP
        }

        surfaceSlope /= 100;							// surface slope from % to fraction
        bedrockDepth *= 10;                                                           //Bedrockdepth cm -> mm
        impermiableDepth *= 10;                                                       //Restrictive Depth cm -> mm
    }

    public void estimateFactors() {
        c_log.clear();
        //System.out.println("IFC_eF:");
        double depth = 0;
        try {
            updateRecordFromGrid();
        } catch (NullPointerException f) {
            Util.debugPrint(true, f.toString());
            f.printStackTrace();
        }

        //Check for required variables
        boolean errors = false;
        for (int ldx = 0; ldx < nsl; ldx++) {
            errors = true;
            if (layerList[1].errorBox(layerThickness[ldx]) != 0) {
                break;
            }
            if (layerList[2].errorBox(organicMaterial[ldx]) != 0) {
                break;
            }
            if (layerList[3].errorBox(fractionSand[ldx]) != 0) {
                break;
            }
            if (layerList[5].errorBox(fractionClay[ldx]) != 0) {
                break;
            }
            if (layerList[11].errorBox(veryFineSandFraction[ldx]) != 0) {
                break;
            }
            if (layerList[12].errorBox(wetBulkDensity[ldx]) != 0) {
                break;
            }
            if (layerList[28].errorBox(calciumCarbonateEquivalent[ldx]) != 0) {
                break;
            }
            errors = false;
        }
        if (errors) {
            throw new IllegalStateException();
        }

        //End check
        for (int ldx = 0; ldx < nsl; ldx++) {				// remainder is silt
            if (Double.isNaN(fractionSilt[ldx])) {
                fractionSilt[ldx] = 0.0;
            }
            if (Double.isNaN(veryCoarseSandFraction[ldx])) {
                veryCoarseSandFraction[ldx] = 0.0;
            }
            if (Double.isNaN(coarseSandFraction[ldx])) {
                coarseSandFraction[ldx] = 0.0;
            }
            if (Double.isNaN(mediumSandFraction[ldx])) {
                mediumSandFraction[ldx] = 0.0;
            }
            if (Double.isNaN(fineSandFraction[ldx])) {
                fineSandFraction[ldx] = 0.0;
            }
            if (Double.isNaN(fractionRock[ldx])) {
                fractionRock[ldx] = 0.0;
            }

            if (fractionClay[ldx] < .01) {
                fractionClay[ldx] = .01;				// define minimum clay to be 1%
            }
            if (fractionSand[ldx] > .99) {
                fractionSand[ldx] = .99;				// define maximum sand to be 99%
            }
            fractionSilt[ldx] = 1 - (fractionClay[ldx] + fractionSand[ldx]);
            if (fractionSilt[ldx] < 0) {
                fractionSilt[ldx] = Double.NaN;
            }

            layerDepthTop[ldx] = depth;
            depth += layerThickness[ldx];
            layerDepthBottom[ldx] = depth;

            if (Double.isNaN(initialBulkDensity[ldx])) {
                initialBulkDensity[ldx] = wetBulkDensity[ldx];
            }
        }

        calculateFactors(true);

        try {
            adjustIfc();
        } catch (NullPointerException f) {
            Util.debugPrint(true, f.toString());
            f.printStackTrace();
        }
        errorsInIfcFile += "\n# SOIL VALUES ESTIMATED\n";
        errorsInIfcFile += "# " + new Date().toString() + "\n";
        for (WepsMessage message : c_log.getMessages()) {
            errorsInIfcFile += "# " + message.toString() + "\n";
        }
        c_log.clear();
    }

    /**
     * split2() computes the 60+ parameters which are not computed in split()
     */
    private void calculateFactors() {
        calculateFactors(false);
    }

    private void calculateFactors(boolean force) {

        for (int ldx = 0; ldx < nsl; ldx++) {									// parameters by layer
            // formula from 12/6/95 memo from LJH to JT

            double rtnval = 0;

            aggregateMeanDiameter[ldx] = Math.exp(1.343 - 2.235 * fractionSand[ldx] - // aggregate geometric mean diameter
                    1.226 * fractionSilt[ldx] - 0.0238 * fractionSand[ldx] / fractionClay[ldx]
                    + 33.6 * organicMaterial[ldx] + 6.85
                    * calciumCarbonateEquivalent[ldx]) * (1 + 0.006 * layerDepthBottom[ldx]);
            rtnval = layerList[14].adjValue(aggregateMeanDiameter[ldx]);
            if (rtnval != aggregateMeanDiameter[ldx]) {
                String msgText = layerList[14].title + " adjusted: old value "
                        + Util.formatDouble(aggregateMeanDiameter[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                aggregateMeanDiameter[ldx] = rtnval;
            }

            aggregateStdDeviation[ldx] = 1 / (0.012448 + 0.002463 * aggregateMeanDiameter[ldx]
                    + (0.093467 / (Math.pow(aggregateMeanDiameter[ldx], 0.5))));
            rtnval = layerList[15].adjValue(aggregateStdDeviation[ldx]);
            if (rtnval != aggregateStdDeviation[ldx]) {
                String msgText = layerList[15].title + " adjusted: old value "
                        + Util.formatDouble(aggregateStdDeviation[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                aggregateStdDeviation[ldx] = rtnval;
            }

            maxAggregateSize[ldx] = Math.pow(aggregateStdDeviation[ldx],
                    (1.52 * (Math.pow(aggregateMeanDiameter[ldx], -0.449)))) * aggregateMeanDiameter[ldx];
            rtnval = layerList[16].adjValue(maxAggregateSize[ldx]);
            if (rtnval != maxAggregateSize[ldx]) {
                String msgText = layerList[16].title + " adjusted: old value "
                        + Util.formatDouble(maxAggregateSize[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                maxAggregateSize[ldx] = rtnval;
            }

            minAggregateSize[ldx] = 0.01;												// minimum aggregate size

            aggregateDensity[ldx] = 1.8;
            rtnval = layerList[18].adjValue(aggregateDensity[ldx]);
            if (rtnval != aggregateDensity[ldx]) {
                String msgText = layerList[18].title + " adjusted: old value "
                        + Util.formatDouble(aggregateDensity[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                aggregateDensity[ldx] = rtnval;
            }

            aggregateStability[ldx] = (fractionClay[ldx] > 0.5) ? 2.73 : 0.83 + 15.7 * fractionClay[ldx]
                    - 23.8 * Math.pow(fractionClay[ldx], 2);								// aggregate stability
            rtnval = layerList[19].adjValue(aggregateStability[ldx]);
            if (rtnval != aggregateStability[ldx]) {
                String msgText = layerList[19].title + " adjusted: old value "
                        + Util.formatDouble(aggregateStability[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                aggregateStability[ldx] = rtnval;
            }

            /**
             * saxton95.for
             * calculate cb, thetas & pote.  do not calc satk, thetaw or thetaf as they
             * come from input file.
             */
            double sax_e = -3.140, sax_f = -2.22e-3, sax_g = -3.484e-5;			// coef used to calc CB
            double sax_m = -0.108, sax_n = 0.341;								// coef used to calc POTE  (not used in this code)
            double sax_x = 0.332, sax_y = -7.251e-4, sax_z = 0.1276;			// coef used to calc THETAS

            saturatedSWC[ldx] = sax_x + sax_y * fractionSand[ldx] * 100. + // saturated soil water content
                    sax_z * (Math.log(fractionClay[ldx] * 100.) / Math.log(10.));
            rtnval = layerList[21].adjValue(saturatedSWC[ldx]);
            if (rtnval != saturatedSWC[ldx]) {
                String msgText = layerList[21].title + " adjusted: old value "
                        + Util.formatDouble(saturatedSWC[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                saturatedSWC[ldx] = rtnval;
            }

            soilCB[ldx] = -(sax_e + // cb(k) == ifc3_layer[][23]
                    (sax_f * Math.pow(fractionClay[ldx] * 100., 2.0))
                    + (sax_g * Math.pow(fractionSand[ldx] * 100., 2.0) * fractionClay[ldx] * 100.));
            rtnval = layerList[24].adjValue(soilCB[ldx]);
            if (rtnval != soilCB[ldx]) {
                String msgText = layerList[24].title + " adjusted: old value "
                        + Util.formatDouble(soilCB[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                soilCB[ldx] = rtnval;
            }

            double sax_a = 100 * Math.exp(-4.396 - // calc A factor for pote
                    0.0715 * (fractionClay[ldx] * 100.) - // using two steps because that is how
                    (4.880e-4) * Math.pow(fractionSand[ldx] * 100., 2) - // saxton95 does it
                    (4.285e-5) * Math.pow(fractionSand[ldx] * 100., 2) * (fractionClay[ldx] * 100.));

            airEntryPotential[ldx] = -sax_a * Math.pow(saturatedSWC[ldx], -soilCB[ldx]); // calc pote
            rtnval = layerList[25].adjValue(airEntryPotential[ldx]);
            if (rtnval != airEntryPotential[ldx]) {
                String msgText = layerList[25].title + " adjusted: old value "
                        + Util.formatDouble(airEntryPotential[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                airEntryPotential[ldx] = rtnval;
            }

            if (force || fieldCapacitySWC[ldx] == 0.0 || Double.isNaN(fieldCapacitySWC[ldx])) {
                fieldCapacitySWC[ldx] = Math.pow((33.0 / sax_a), (1 / -soilCB[ldx]));
                rtnval = layerList[22].adjValue(fieldCapacitySWC[ldx]);
                if (rtnval != fieldCapacitySWC[ldx]) {
                    String msgText = layerList[22].title + " adjusted: old value "
                            + Util.formatDouble(fieldCapacitySWC[ldx], 4) + " new value " + rtnval;
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                    fieldCapacitySWC[ldx] = rtnval;
                } else {
                    String msgText = "field capacity layer " + (ldx + 1)
                            + " input as 0.0 or NaN; replaced with estimate " + Util.formatDouble(fieldCapacitySWC[ldx], 4);
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                }

            }

            if (force || wiltingPointSWC[ldx] == 0.0 || Double.isNaN(wiltingPointSWC[ldx])) {
                wiltingPointSWC[ldx] = Math.pow((1500.0 / sax_a), (1 / -soilCB[ldx]));
                rtnval = layerList[23].adjValue(wiltingPointSWC[ldx]);
                if (rtnval != wiltingPointSWC[ldx]) {
                    String msgText = layerList[23].title + " adjusted: old value "
                            + Util.formatDouble(wiltingPointSWC[ldx], 4) + " new value " + rtnval;
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                    wiltingPointSWC[ldx] = rtnval;
                } else {
                    String msgText = "wilting point layer " + (ldx + 1)
                            + " input as 0.0 or NaN; replaced with estimate " + Util.formatDouble(wiltingPointSWC[ldx], 4);
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                }
            }

            if (force || saturatedHydraulicConductivity[ldx] == 0.0 || Double.isNaN(saturatedHydraulicConductivity[ldx])) {
                double sk = 9.6 - 0.81 * Math.log(fractionSilt[ldx] * 100.) / Math.log(10.)
                        - 1.09 * Math.log(fractionClay[ldx] * 100.) / Math.log(10.) - 4.64 * initialBulkDensity[ldx];
                saturatedHydraulicConductivity[ldx] = Math.pow(10, sk) * 0.24 * (1.0 / 86400);
                rtnval = layerList[26].adjValue(saturatedHydraulicConductivity[ldx]);
                if (rtnval != saturatedHydraulicConductivity[ldx]) {
                    String msgText = layerList[26].title + " adjusted: old value "
                            + Util.formatDouble(saturatedHydraulicConductivity[ldx], 4) + " new value " + rtnval;
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                    saturatedHydraulicConductivity[ldx] = rtnval;
                } else {
                    String msgText = "satk layer " + (ldx + 1)
                            + " input as 0.0 or NaN; replaced with estimate "
                            + Util.formatDouble(saturatedHydraulicConductivity[ldx], 4);
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                }
            }

            if (force || soilpH[ldx] == 0.0 || Double.isNaN(soilpH[ldx])) {
                rtnval = 7;
                String msgText = layerList[27].title + " adjusted: old value "
                        + Util.formatDouble(soilpH[ldx], 4) + " new value " + rtnval;
                c_log.logMessage(WepsMessage.warningMessage(msgText));
                soilpH[ldx] = rtnval;
            }

            if (force || cationExchangeCapacity[ldx] == 0.0 || Double.isNaN(cationExchangeCapacity[ldx])) {
                cationExchangeCapacity[ldx] = fractionClay[ldx] * 100 * 0.5 + organicMaterial[ldx] * 100. * 2.0;
                rtnval = layerList[29].adjValue(cationExchangeCapacity[ldx]);
                if (rtnval != cationExchangeCapacity[ldx]) {
                    String msgText = layerList[29].title + " adjusted: old value "
                            + Util.formatDouble(cationExchangeCapacity[ldx], 4) + " new value " + rtnval;
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                    cationExchangeCapacity[ldx] = rtnval;
                } else {
                    String msgText = "cec layer " + (ldx + 1)
                            + " input as 0.0 or NaN; replaced with estimate "
                            + Util.formatDouble(cationExchangeCapacity[ldx], 4);
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                }
            }

            if (force || linearExtensibility[ldx] == 0.0 || Double.isNaN(linearExtensibility[ldx])) {
                double bsd = SoilUtil.estimateSettledBulkDensity(fractionClay[ldx], fractionSand[ldx], organicMaterial[ldx]);

                if (wetBulkDensity[ldx] > bsd) {
                    bsd = wetBulkDensity[ldx];
                    String msgText = "Settled bulk density adjusted: Set to wet bulk density.";
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                } else {
                    String msgText = "Settled bulk density estimated: " + Util.formatDouble(bsd, 4);
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                }

                linearExtensibility[ldx] = SoilUtil.estimateLinearExtensibility(bsd, wetBulkDensity[ldx]);
                rtnval = layerList[30].adjValue(linearExtensibility[ldx]);
                if (rtnval != linearExtensibility[ldx]) {
                    String msgText = layerList[30].title + " adjusted: old value "
                            + Util.formatDouble(linearExtensibility[ldx], 4) + " new value " + rtnval;
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                    linearExtensibility[ldx] = rtnval;
                } else {
                    String msgText = "cec layer " + (ldx + 1)
                            + " input as 0.0 or NaN; replaced with estimate "
                            + Util.formatDouble(linearExtensibility[ldx], 4);
                    c_log.logMessage(WepsMessage.warningMessage(msgText));
                }
            }

            initialSWC[ldx] = (fieldCapacitySWC[ldx] + wiltingPointSWC[ldx]) / 2;			// initial soil water content

        }

        // parameters not by layer
        crustThickness = 0.01;											// soil crust thickness
        crustDensity = aggregateDensity[0];								// soil crust density
        crustStability = aggregateStability[0];								// soil crust stability
        randomRoughness = 4;												// random roughness
        if (force || surfaceAlbedo == 0.0 || Double.isNaN(surfaceAlbedo)) {
            surfaceAlbedo = 0.6 / (Math.exp(0.4 * organicMaterial[0] * 100.0));
            String msgText = "dry albedo input as 0.0 or NaN; replaced with estimate"
                    + Util.formatDouble(surfaceAlbedo, 4);
            c_log.logMessage(WepsMessage.warningMessage(msgText));
        }

    }

    /**
     * wjr
     * @param numRows
     * @param chggrid
     */
    public void rowsChanged(int numRows, Grid chggrid) {
        //System.out.println("rC: " + numRows);
        GridID.updateValue(0, 8, " " + numRows);
        nsl = numRows;
    }

    Grid GridID = null;
    Grid GridSurfProp = null;
    Grid GridLayrProp = null;
    JTextArea NotesDisplay = null;

    /**
     *
     * @param id
     * @param surf
     * @param layr
     * @param notes
     */
    public void setGrids(Grid id, Grid surf, Grid layr, JTextArea notes) {
        GridID = id;
        GridSurfProp = surf;
        GridLayrProp = layr;
        NotesDisplay = notes;
    }

    /**
     * wjr
     * @param filetmp
     */
    public void setFilename1(String filetmp) {
        mySavedFilename = filetmp;
    }

    /**
     *
     * @return
     */
    public String getFilename1() {
        return mySavedFilename;
    }

    /**
     *
     * @return
     */
    public WepsMessageLog getLog() {
        return c_log;
    }
}

/*	alfisols
 andisols
 aridisols
 entisols
 gelisols
 histosols
 inceptisols
 mollisols
 oxisols
 spodosols
 ultisols
 vertisols
 other*/
