V2_1.java [src/java/m/rusle2] Revision: 704f75a26e2fa3e986a5faacb9ed3caa64f250a5  Date: Wed Apr 05 15:35:42 MDT 2017
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package m.rusle2;

import c.GIS_DB;
import c.GIS_DB_Factory;
import csip.Client;
import csip.Config;
import csip.Executable;
import csip.ServiceException;
import java.io.File;
import java.io.FileOutputStream;
import java.util.*;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;
import org.codehaus.jettison.json.JSONException;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import csip.ModelDataService;
import static csip.ModelDataService.EXEC_FAILED;
import static csip.ModelDataService.EXEC_OK;
import static csip.ModelDataService.KEY_REQUEST_RESULTS;
import static csip.ModelDataService.REPORT_DIM;
import static csip.ModelDataService.REPORT_NAME;
import static csip.ModelDataService.REPORT_TYPE;
import static csip.ModelDataService.REPORT_VALUE;
import static csip.ModelDataService.VALUE;
import csip.annotations.Polling;
import csip.annotations.Resource;
import csip.annotations.ResourceType;
import static csip.annotations.ResourceType.ARCHIVE;
import static csip.annotations.ResourceType.FILE;
import static csip.annotations.ResourceType.REFERENCE;
import static util.ErosionConst.*;

import csip.utils.Binaries;
import csip.utils.JSONUtils;
import csip.utils.Services;
import java.io.IOException;
import java.io.StringReader;
import java.util.logging.Level;
import javax.ws.rs.Path;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import static m.rusle2.V2_1.PYROME;
import static m.rusle2.V2_1.PYROMESRC;
import static m.rusle2.V2_1.PYTHON;
import static m.rusle2.V2_1.PYTHONZIP;
import static m.rusle2.V2_1.ROMEDLL;
import oms3.annotations.Description;
import oms3.annotations.Name;
import oms3.annotations.VersionInfo;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * REST Web Service. Front end callable.
 *
 * @author wlloyd, od
 */
@Name("Rusle2")
@Description("IET / Phacil pyrome version of R2. References sdmONLINE")
@VersionInfo("2.1")
@Path("m/rusle2/2.1")
@Polling(first = 1000, next = 1000)

//        Binaries.unpackResource("/bin/win-x86/pyrome.py", new File(binDir));
//        Binaries.unpackResource("/bin/win-x86/_pyrome.pyd", new File(binDir));  

@Resource(type = FILE, file = "/bin/win-x86/RomeDLL.dll", id = ROMEDLL)
@Resource(type = FILE, file = "/bin/win-x86/pyrome.py", id = PYROMESRC)
@Resource(type = FILE, file = "/bin/win-x86/_pyrome.pyd", id = PYROME)
@Resource(type = ARCHIVE, file = "/bin/win-x86/Python34.zip", id = PYTHONZIP)
@Resource(type = REFERENCE, file = "${csip.dir}/bin/win-x86/Python34/python.exe", wine = true, id = PYTHON)

public class V2_1 extends ModelDataService {

    static final boolean PRODUCTION_MODE = true;
    //
    static final String R2_TMP_FILENAME = "rusle2csip";
    static final String ROMEDLL = "RomeDLL.dll";
    static final String PYROMESRC = "pyrome.py";
    static final String PYROME = "_pyrome.pyd";
    static final String PYTHONZIP = "Python34.zip";
    static final String PYTHON = "python.exe";
    static final String R2_TMP_FILEEXT = ".py";
    static final String IO_TIMING_FILENAME = "/tmp/io-timing";
    static final String IO_TIMING_FILEEXT = ".txt";
    static final String REPORT_JSON_TEMPLATE_FILENAME = "Rusle2_Report.json";
    static final String REPORT_PY_FILENAME = "rusle2_report.py";
    static final String KEY_COKEY = "cokey";

    /*
     * The R2 Run
     */
    final R2Run r2run = new R2Run();
    static final List<String> potResults = Collections.unmodifiableList(Arrays.asList(
            RES_SLOPE_DELIVERY,
            RES_SLOPE_T_VALUE,
            RES_SLOPE_DEGRAD,
            RES_SLOPE_EQUIV_DIESEL_USE_PER_AREA,
            RES_SOIL_COND_INDEX_STIR_VAL,
            RES_SOIL_COND_INDEX_RESULT,
            RES_SEG_SIM_DAY_LIVE_BIOMASS,
            RES_SEG_SIM_DAY_COVER_MASS_SUM,
            RES_SEG_SIM_DAY_STAND_MASS_SUM,
            RES_SEG_SIM_DAY_CANOPY_COVER,
            RES_SEG_SIM_DAY_PERENN_VEG_LIVE_HEIGHT,
            RES_SLOPE_SIM_DAY_DEGRAD,
            RES_SURF_RES_OUTPUTS_SURF_COV_AT_OP,
            RES_SOIL_COND_INDEX_OM_SUBFACTOR,
            RES_SOIL_COND_INDEX_FO_SUBFACTOR,
            RES_SOIL_COND_INDEX_ER_SUBFACTOR));
    //
    String climate;
    String soil;
    String mgmt;
    List<String> operations;
    List<String> vegetations;
    List<String> residues;

    //

    @Override
    protected void preProcess() throws Exception {
        // check for requested output.

        try {
            LOG.info("\n\n\n\n\nMETAINFO:");
            LOG.info("\n" + getMetainfo().toString());
            LOG.info("\n\n\n");
            JSONUtils.checkValidResultRequest(getMetainfo(), potResults);
        } catch (ServiceException se) {
            LOG.severe("\n\n\nERROR!!!\n\n\n" + se.toString());
            LOG.warning("No Rusle2 return parameters requested! Will use defaults: SLOPE_DELIVERY, SLOPE_T_VALUE, SLOPE_DEGRAD");
            List<String> params = new LinkedList<String>();
            params.add(RES_SLOPE_DELIVERY);
            params.add(RES_SLOPE_T_VALUE);
            params.add(RES_SLOPE_DEGRAD);

            // check if these are being set
            if (JSONUtils.checkKeyExistsB(getParamMap(), KEY_CONTOUR_SYSTEM_PTR)) {
                params.add("CONTOUR_SYSTEM_PTR");
            }

            if (JSONUtils.checkKeyExistsB(getParamMap(), KEY_STRIP_BARRIER_SYSTEM_PTR)) {
                params.add("STRIP_BARRIER_SYSTEM_PTR");
            }

            if (JSONUtils.checkKeyExistsB(getParamMap(), KEY_HYD_ELEM_SYSTEM_PTR)) {
                params.add("HYD_ELEM_SYSTEM_PTR");
            }

            getMetainfo().put(KEY_REQUEST_RESULTS, params);
        }

//        if (JSONUtils.checkKeyExistsB(getParamMap(), KEY_TOPO_LENGTH))
//        {
//            JSONArray aTopoLength = JSONUtils.getJSONArrayParam(param, KEY_TOPO_LENGTH);
//            for (int i=0;i<aTopoLength.length();i++)
//            {
//                params.add("");
//            }
//        }
        // check if sufficient input is there.
        //JSONUtils.checkKeyExists(getParamMap(), KEY_CLIMATES);
        JSONUtils.checkKeyExists(getParamMap(), KEY_SOILS);
//        JSONUtils.checkKeyExists(getParamMap(), KEY_MANAGEMENTS);
        JSONUtils.checkKeyExists(getParamMap(), KEY_LENGTH);
        JSONUtils.checkKeyExists(getParamMap(), KEY_STEEPNESS);

        JSONUtils.checkKeyExists(getParamMap(), KEY_MGMTS);

        File r2script = new File(getWorkspaceDir(), R2_TMP_FILENAME + R2_TMP_FILEEXT);
        createInputFile(r2script, getMetainfo(), getParamMap());
    }

    @Override
    protected void doProcess() throws Exception {
        try  {
            Executable python = getResourceExe(V2_1.PYTHON);
            LOG.log(Level.INFO, "EXECUTING PYROME FROM doProcess()...");
            int result = r2run.executePyrome(new File(getWorkspaceDir(), R2_TMP_FILENAME + R2_TMP_FILEEXT), python);
        }
        catch (Exception e) {
            LOG.log(Level.SEVERE, "ERROR EXECUTING PYTHON-RUSLE2", e);
            throw e;
        }
    }    

//    @Override
//    protected String process() throws Exception {
//        Executable python = getResourceExe(V2_0_1.PYTHON);
//        
//        LOG.log(Level.INFO, "EXECUTING PYROME FROM process()...");
//        int result = r2run.executePyrome(new File(getWorkspaceDir(), R2_TMP_FILENAME + R2_TMP_FILEEXT), python);
//        if (result != 0) {
//            return EXEC_FAILED;
//        }
//        return EXEC_OK;
//    }

    @Override
    protected void postProcess() throws Exception {
        
    }
    
    @Override
    protected JSONArray createResults() throws Exception {
        JSONArray results = new JSONArray();
        int errors = 0;
        for (int i = 0; i < operations.size(); i++) {
            String op = operations.get(i);
            if (r2run.isUrlReachable(op)) {
                results.put(JSONUtils.dataDesc("OPERATION_" + (i + 1), op, "operation is valid"));
            } else {
                results.put(JSONUtils.dataDesc("OPERATION_INVALID_" + (i + 1), op, "OPERATION IS MISSING!"));
                errors++;
            }
        }
        for (int i = 0; i < vegetations.size(); i++) {
            String vege = vegetations.get(i);
            if (r2run.isUrlReachable(vege)) {
                results.put(JSONUtils.dataDesc("VEGETATION_" + (i + 1), vege, "vegetation is valid"));
            } else {
                results.put(JSONUtils.dataDesc("VEGETATION_INVALID_" + (i + 1), vege, "VEGETATION IS MISSING"));
                errors++;
            }
        }
        for (int i = 0; i < residues.size(); i++) {
            String res = residues.get(i);
            if (r2run.isUrlReachable(res)) {
                results.put(JSONUtils.dataDesc("RESIDUE_" + (i + 1), res, "RESIDUE IS VALID"));
            } else {
                results.put(JSONUtils.dataDesc("RESIDUE_INVALID_" + (i + 1), res, "RESIDUE IS MISSING"));
                errors++;
            }
        }

//      results.put(JSONUtils.data(KEY_SLOPE_DELIVERY, 3.0));
        for (String r : JSONUtils.getRequestedResults(getMetainfo())) {
            if ((errors > 0) && (r.equals(RES_SLOPE_DEGRAD))) {
                results.put(JSONUtils.dataDesc(r, r2run.getResultPyrome(r), R2_MISSING_XML_FILES_WARNING_MSG));
            } else {
                results.put(JSONUtils.data(r, r2run.getResultPyrome(r)));
            }
        }

        // Get erosion for segments
        if (JSONUtils.checkKeyExistsB(getParamMap(), KEY_TOPO_LENGTH)) {
            JSONArray aTopoLength = JSONUtils.getJSONArrayParam(getParamMap(), KEY_TOPO_LENGTH);
            if (aTopoLength.length() > 0) {
                JSONArray aSoilLoss = new JSONArray(r2run.getResultPyromeArray("SEG_SOIL_LOSS", false, false, true));
                results.put(JSONUtils.data("SEG_SOIL_LOSS", aSoilLoss));
                results.put(JSONUtils.data(KEY_CLIMATES, climate));
                LOG.info("\n\n\n\n\n\nSEG SOIL OUTPUT=" + r2run.getResultPyromeArray("SEG_SOIL", true, true, true) + "\n\n\n\n");
                LOG.info("\n\n\n\n\n\nSEG SOIL OUTPUT=" + r2run.getResultPyromeArray("SEG_MAN", true, true, true) + "\n\n\n\n");
                JSONArray aSoil = new JSONArray(r2run.getResultPyromeArray("SEG_SOIL", true, true, true));
                results.put(JSONUtils.data(KEY_SOILS, aSoil));
                JSONArray aMgmt = new JSONArray(r2run.getResultPyromeArray("SEG_MAN", true, true, true));
                results.put(JSONUtils.data(KEY_MANAGEMENTS, aMgmt));
                if (JSONUtils.checkKeyExistsB(getParamMap(), KEY_DIVERSIONS)) {
                    JSONArray aHydElemSystems = new JSONArray(r2run.getResultPyromeArray("HYD_ELEM_SYS", true, true, true));
                    results.put(JSONUtils.data(KEY_DIVERSIONS, aHydElemSystems));
                }
                if (JSONUtils.checkKeyExistsB(getParamMap(), KEY_STRIP_BARRIER_SYSTEMS)) {
                    JSONArray aStripBarrierSystems = new JSONArray(r2run.getResultPyromeArray("STRIP_BARRIER_SYS", true, true, true));
                    results.put(JSONUtils.data(KEY_STRIP_BARRIER_SYSTEMS, aStripBarrierSystems));
                }
//                if (JSONUtils.checkKeyExistsB(getParamMap(), KEY_CONTOURSYSTEMS)) {
//                    JSONArray aContourSystems = new JSONArray(r2run.getResultPyromeArray("CONTOUR_SYS", true, true));
//                    results.put(JSONUtils.data(KEY_CONTOURSYSTEMS, aContourSystems));
//                }
            }
        } else {
            results.put(JSONUtils.data(KEY_CLIMATES, climate));
//            results.put(JSONUtils.data(KEY_SOILS, soil));
//            results.put(JSONUtils.data(KEY_MANAGEMENTS, mgmt));
            JSONArray aSoil = new JSONArray(r2run.getResultPyromeArray("SEG_SOIL", true, true, true));
            results.put(JSONUtils.data(KEY_SOILS, aSoil));
            JSONArray aMgmt = new JSONArray(r2run.getResultPyromeArray("SEG_MAN", true, true, true));
            results.put(JSONUtils.data(KEY_MANAGEMENTS, aMgmt));
        }
        return results;
    }


    private void createInputFile(File file, JSONObject metainfo, Map<String, JSONObject> param)
            throws Exception {

        double steepness = JSONUtils.getDoubleParam(param, KEY_STEEPNESS, 0.0);
        double length = JSONUtils.getDoubleParam(param, KEY_LENGTH, 0.0);
        boolean resolveLoc = JSONUtils.getBooleanParam(param, KEY_RESOLVE_LOCATION, false);
        double latitude = JSONUtils.getDoubleParam(param, KEY_LATITUDE, 0.0);
        double longitude = JSONUtils.getDoubleParam(param, KEY_LONGITUDE, 0.0);
        double simpleRockCoverPercent = JSONUtils.getDoubleParam(param, KEY_SIMPLE_ROCK_COVER, 0.0);

        LOG.info("Rock cover read by service is=" + simpleRockCoverPercent);

        JSONArray aRockCover = JSONUtils.getJSONArrayParam(param, KEY_SIMPLE_ROCK_COVER);
        for (int i = 0; i < aRockCover.length(); i++) {
            LOG.info("Rock cover [" + i + "]=" + aRockCover.getDouble(i));
            // this is temporary, since R2 will be using slope segments soon
            if (i == 0) {
                simpleRockCoverPercent = aRockCover.getDouble(i);
            }
        }

        String climatePtr = JSONUtils.getStringParam(param, KEY_CLIMATES, "");

        JSONArray aSoils = JSONUtils.getJSONArrayParam(param, KEY_SOILS);
        String soilPtr[] = new String[(aSoils.length())];
        for (int i = 0; i < aSoils.length(); i++) {
            LOG.info("soil [" + i + "]=" + aSoils.getInt(i));
            // this is temporary, since R2 will be using slope segments soon
//            if (i==0)
//                soilPtr = Integer.toString(aSoils.getInt(i));
        }

        //JSONArray diversions = new JSONArray();
        //JSONArray contoursytems = new JSONArray();
        //JSONArray stripBarrrierSystems = new JSONArray();

        // scalar variables for non-segmented runs
        String contourSystem = "";
        String stripBarrierSystem = "";
        String hydElemSystem = "";

        // Get the Contour System if not default
        if (JSONUtils.checkKeyExistsB(param, KEY_CONTOUR_SYSTEM_PTR)) {
            contourSystem = JSONUtils.getStringParam(param, KEY_CONTOUR_SYSTEM_PTR, "");
        }

        // Get the Strip Barrier System
        if (JSONUtils.checkKeyExistsB(param, KEY_STRIP_BARRIER_SYSTEM_PTR)) {
            stripBarrierSystem = JSONUtils.getStringParam(param, KEY_STRIP_BARRIER_SYSTEM_PTR, "");
        }
        
        // Get the Hydraylic Element System Pointer  
        if (JSONUtils.checkKeyExistsB(param, KEY_HYD_ELEM_SYSTEM_PTR)) {
            hydElemSystem = JSONUtils.getStringParam(param, KEY_HYD_ELEM_SYSTEM_PTR, "");
        }
        
        JSONArray aTopoLength = new JSONArray();
        JSONArray aTopoSteepness = new JSONArray();
        JSONArray aSoilIdx = new JSONArray();
        JSONArray aManIdx = new JSONArray();
        JSONArray aManLength = new JSONArray();
//        JSONArray aDiversionIdx = new JSONArray();
//        JSONArray aContourIdx = new JSONArray();
//        JSONArray aStripBarrierIdx = new JSONArray();
        if (JSONUtils.checkKeyExistsB(param, KEY_TOPO_LENGTH)) {
            aTopoLength = JSONUtils.getJSONArrayParam(param, KEY_TOPO_LENGTH);
            for (int i = 0; i < aTopoLength.length(); i++) {
                LOG.info("Topo Length [" + i + "]=" + aTopoLength.getDouble(i));
//                // this is temporary, since R2 will be using slope segments soon
//                if (i == 0) {
//                    length = aTopoLength.getDouble(i);
//                }
            }
        }

        if (JSONUtils.checkKeyExistsB(param, KEY_TOPO_STEEPNESS)) {
            aTopoSteepness = JSONUtils.getJSONArrayParam(param, KEY_TOPO_STEEPNESS);
            for (int i = 0; i < aTopoSteepness.length(); i++) {
                LOG.info("Topo Steepness [" + i + "]=" + aTopoSteepness.getDouble(i));
//                if (i == 0) {
//                    steepness = aTopoSteepness.getDouble(i);
//                }
            }
        }

        if (JSONUtils.checkKeyExistsB(param, KEY_SOIL_INDEX)) {
            aSoilIdx = JSONUtils.getJSONArrayParam(param, KEY_SOIL_INDEX);
            for (int i = 0; i < aSoilIdx.length(); i++) {
                LOG.info("Soil Index [" + i + "]=" + aSoilIdx.getInt(i));
                //            if (i==0)
                //                steepness = aSoilIdx.getInt(i);
            }
        }

        if (JSONUtils.checkKeyExistsB(param, KEY_MAN_INDEX)) {
            aManIdx = JSONUtils.getJSONArrayParam(param, KEY_MAN_INDEX);
            for (int i = 0; i < aManIdx.length(); i++) {
                LOG.info("Man Index [" + i + "]=" + aManIdx.getInt(i));
                //            if (i==0)
                //                steepness = aTopoSteepness.getDouble(i);
            }
        }
        
        if (JSONUtils.checkKeyExistsB(param, KEY_MAN_LENGTH)) {
            aManLength = JSONUtils.getJSONArrayParam(param, KEY_MAN_LENGTH);
            for (int i = 0; i < aManLength.length(); i++) {
                LOG.info("Man Length [" + i + "]=" + aManLength.getInt(i));
            }
        }

//        if (JSONUtils.checkKeyExistsB(param, KEY_DIVERSION_INDEX)) {
//            aDiversionIdx = JSONUtils.getJSONArrayParam(param, KEY_DIVERSION_INDEX);
//            for (int i = 0; i < aDiversionIdx.length(); i++) {
//                LOG.info("Diversion Index [" + i + "]=" + aDiversionIdx.getInt(i));
//            }
//        }
        
//        if (JSONUtils.checkKeyExistsB(param, KEY_CONTOUR_INDEX)) {
//            aContourIdx = JSONUtils.getJSONArrayParam(param, KEY_CONTOUR_INDEX);
//            for (int i = 0; i < aContourIdx.length(); i++) {
//                LOG.info("Contour Index [" + i + "]=" + aContourIdx.getInt(i));
//            }
//        }
        
//        if (JSONUtils.checkKeyExistsB(param, KEY_STRIP_BARRIER_INDEX)) {
//            aStripBarrierIdx = JSONUtils.getJSONArrayParam(param, KEY_STRIP_BARRIER_INDEX);
//            for (int i = 0; i < aStripBarrierIdx.length(); i++) {
//                LOG.info("Strip Barrier Index [" + i + "]=" + aStripBarrierIdx.getInt(i));
//            }
//        }

        if (JSONUtils.checkKeyExistsB(param, KEY_TOPO_LENGTH)) {
            if (!allEqual(aTopoLength.length(), aTopoSteepness.length())) {
                throw new ServiceException("RUSLE2 SEGMENT RUN ERROR! SEGMENT ARRAYS FOR TOPO LENGTH AND TOPO STEEPNESS MUST BE OF EQUAL SIZE!");
            }
        }
        
        if (JSONUtils.checkKeyExistsB(param, KEY_MAN_INDEX)) {
            if (!allEqual(aManLength.length(), aManIdx.length())) {
                throw new ServiceException("RUSLE2 SEGMENT RUN ERROR! SEGMENT ARRAYS FOR MGMT LENGTH AND MGMT INDEX MUST BE OF EQUAL SIZE!");
            }
        }        
        
        //soilPtr = JSONUtils.getStringParam(param, KEY_SOILS, "");
        String managementFormalName[] = new String[]{};

//        String mgmtPtr = JSONUtils.getStringParam(param, KEY_MANAGEMENTS, "");
//        if (!mgmtPtr.startsWith("managements\\")) {
//            mgmtPtr = "managements\\" + mgmtPtr;
//        }
        // management conversion
        // Make file line separator unix compatible. ???? not sure if needed.
        System.setProperty("line.separator", "\n");
        //
        JSONArray managements = JSONUtils.getJSONArrayParam(param, KEY_MGMTS);

        LOG.info("managements array=" + managements.toString());
        managementFormalName = new String[managements.length()];

        for (int i = 0; i < managements.length(); i++) {
            LOG.info("management #" + i);

            JSONObject lmod = (JSONObject) managements.get(i);
            LOG.info(lmod.toString());

            LOG.info("creating Jim's translator.");
            lmod2rusle2.Rusle2Translator translator = new lmod2rusle2.Rusle2Translator();
            LOG.info("trying to put in the lmod json");
            translator.readJsonString(lmod.toString());
            LOG.info("trying to translate=" + translator.Translate());

//            // extract the element as JSON
//            Document lmod_xml = Lmod2Rusle2.readJSON(lmod, false);
//            // Translate the file into RUSLE2 format
//            Document r2_xml = Lmod2Rusle2.LmodXmlToRusle2Xml(lmod_xml, "F");
            Document r2_xml = translator.getDocument();

            LOG.info("R2 XML FILE from trhe translator:\n\n" + translator.getRusle2Xml());
            LOG.info("R2 XML FILE:\n\n" + translator.getRusle2Xml());
            //LOG.info("LMOD XML FILE:\n\n" + lmod_xml.getTextContent());

//            if ((lmod_xml != null) && (lmod_xml.getElementById("Filename") != null))
//                managementFormalName[i] = lmod_xml.getElementById("Filename").getTextContent();
            if ((r2_xml != null) && (r2_xml.getElementsByTagName("Filename") != null)) {
                NodeList nl = r2_xml.getElementsByTagName("Filename");
                for (int ii = 0; ii < nl.getLength(); ii++) {
                    LOG.info("filename node=" + nl.item(ii).getTextContent());
                    managementFormalName[i] = nl.item(ii).getTextContent();
                }
            }
            translator.writeRusle2Xml(getWorkspaceDir().toString(), "lmod_file" + i + ".xml");
            operations = translator.getOperationFiles();
            vegetations = translator.getVegetationFiles();
            residues = translator.getResidueFiles();

            for (String operation : translator.getOperationFiles()) {
                System.out.println("operation=" + operation);
            }
            for (String vege : translator.getVegetationFiles()) {
                System.out.println("vegetation=" + vege);
            }
            for (String residue : translator.getResidueFiles()) {
                System.out.println("residue=" + residue);
            }
        }

        String altR2db = null;
        if (param.get(KEY_ALT_R2DB) != null) {
            altR2db = param.get(KEY_ALT_R2DB).getString(VALUE);
        }

        GIS_DB db = GIS_DB_Factory.createGISEngine();

        // If this is a Lat/Lng request, then we need to make a DB lookup
        // to obtain the Climate and Soil information and ignore whatever
        // may have been passed in
        LOG.info("Rulse 2 model request resolveLocation=" + resolveLoc);
        //if (resolveLoc) {

        if (db != null) {
            GIS_DB.FileQryResult climate = db.findClimate(latitude, longitude);
            if (climate == null) {
                LOG.warning("no climate for lat=" + latitude + "\nfor long=" + longitude + "\n");
                climatePtr = "";
            } else {
                climatePtr = climate.file_path + "\\" + climate.file_name;
            }

//            // to do
//            // use only the first soil for now - later we need to use all of them
//            sString cokey = soilPtr.replace(",", " ");
//            // strip first and last char
//            String t2 = cokey.substring(1, cokey.length() - 1);
//            String delims = "\"";
//            String tokens[] = t2.split(delims);
//            LinkedList<String> lst = new LinkedList();
//            for (String token : tokens) {
//                if (token.trim().length() > 0) {
//                    lst.add(token);
//                }
//            }
            if(!Config.getBoolean("sdmONLINE",false)){
                for (int i = 0; i < aSoils.length(); i++) {
                    String cokey = aSoils.getString(i);
                    //cokey = lst.get(0);  // first soil only for now
                    GIS_DB.FileQryResult soil = db.findSoilsByCokey(cokey, longitude);
                    if (soil == null) {
                        LOG.warning("No soil for lat=" + latitude + "\nfor long=" + longitude + "\n");
                        appendMetainfoWarning(R2_NO_SOIL_FOR_PROVIDED_COKEY);
                        soilPtr[i] = "";
                    } else {
                        soilPtr[i] = soil.file_path + "\\" + soil.file_name;
                        LOG.info("THE SOIL IS =" + soilPtr + "\n\n\n\n");
                    }
                }
            }

        } else {
            LOG.warning("WARNING: Unable to access database to resolve the climate and soil information for this lat/long driven rusle2 model run.  Using deafults.");
        }      
      
        if(Config.getBoolean("sdmONLINE",false)){
            soilPtr = getSoilFiles(aSoils);
        }
        //}

        FileOutputStream fos = new FileOutputStream(file);

        fos.write("import sys\n".getBytes());
        // could rewrite this line based on the OS, but python is interpretting it ok on windows
        fos.write("sys.path.append('/tmp/csip/bin/win-x86/')\n".getBytes());
        //fos.write("sys.path.append('c:\\\\tmp\\\\csip\\\\bin\\\\win-x86\\\\')\n".getBytes());

        fos.write("from pyrome import *\n".getBytes());
        fos.write("from time import sleep\n".getBytes());

        fos.write("def linearTest(save = False, openFlags = RX_FILESOPEN_TEMP):\n".getBytes());
        fos.write("    romeDLL = RomeInit('')\n".getBytes());
        fos.write("    files = RomeGetFiles(romeDLL)\n".getBytes());
        fos.write("    engine = RomeGetEngine(romeDLL)\n".getBytes());
        fos.write("    RomeEngineSetAutorun(engine,RX_FALSE)\n".getBytes());

        fos.write("    #Inputs\n".getBytes());

        if (aTopoLength.length() > 1) {
            String text = "    slopes=[";
            for (int i = 0; i < aTopoSteepness.length(); i++) {
                text += "'" + aTopoSteepness.getInt(i) + "'";
                text += (i == aTopoSteepness.length() - 1) ? "]\n" : ",";
            }
            fos.write(text.getBytes());
            text = "    lengths=[";
            for (int i = 0; i < aTopoLength.length(); i++) {
                text += "'" + aTopoLength.getInt(i) + "'";
                text += (i == aTopoLength.length() - 1) ? "]\n" : ",";
            }
            fos.write(text.getBytes());
            if ((aSoilIdx != null) && (aSoilIdx.length() > 0))
            {
                text = "    soilIndex=[";
                for (int i = 0; i < aSoilIdx.length(); i++) {
                    text += aSoilIdx.getInt(i) + "";
                    text += (i == aSoilIdx.length() - 1) ? "]\n" : ",";
                }
                fos.write(text.getBytes());
            }
            text = "    manIndex=[";
            for (int i = 0; i < aManIdx.length(); i++) {
                text += aManIdx.getInt(i) + "";
                text += (i == aManIdx.length() - 1) ? "]\n" : ",";
            }
            fos.write(text.getBytes());
//            if ((aDiversionIdx != null) && (aDiversionIdx.length() > 0)) {
//                text = "    diversionIndex=[";
//                for (int i = 0; i < aDiversionIdx.length(); i++) {
//                    text += aDiversionIdx.getInt(i) + "";
//                    text += (i == aDiversionIdx.length() - 1) ? "]\n" : ",";
//                }
//                fos.write(text.getBytes());
//            }

        } else {
            String text = "    slopes=['" + steepness + "']\n";
            fos.write(text.getBytes());
            text = "    lengths=['" + length + "']\n";
            fos.write(text.getBytes());
            fos.write("    soilIndex=[0]\n".getBytes());
            fos.write("    manIndex=[0]\n".getBytes());
        }

        fos.write("    results = list()\n".getBytes());

        fos.write("    #Run a simple profile\n".getBytes());
        fos.write("    profile = RomeFilesOpen(files,'profiles\\\\csippyrome',openFlags)\n".getBytes());

        // Open all of the mgmt files...
        for (int i = 0; i < managements.length(); i++) {
            String text = "    mgmt = RomeFilesOpen(files, '#XML:lmod_file" + i + ".xml',0)\n";
            fos.write(text.getBytes());
        }
        
        fos.write("    cli = RomeFilesOpen(files, '#XML:cli_file0.xml',0)\n".getBytes());

        for (int i = 0; i < aSoils.length(); i++) {
            String text = "    soil" + i + " = RomeFilesOpen(files, '#XML:soils_file" + i + ".xml',0)\n";
            fos.write(text.getBytes());
        }

      
//// need to set these elements based on array settings
//        for (int i = 0; i < aDiversionIdx.length(); i++) {
//            String text = "    hydelem = RomeFilesOpen(files, '#XML:hydelem_file" + i + ".xml',0)\n";
//            fos.write(text.getBytes());
////            text = "    RomeFileSetAttrValue(profile, 'HYD_ELEM_SYSTEM_PTR', 'hydraulic-element-systems\\\\aaa" + i + "', 0)\n";
////            fos.write(text.getBytes());
//        }

//        for (int i = 0; i < aStripBarrierIdx.length(); i++) {
//            String text = "    stripbarr = RomeFilesOpen(files, '#XML:stripbarr_file" + i + ".xml',0)\n";
//            fos.write(text.getBytes());
////            text = "    RomeFileSetAttrValue(profile, 'STRIP_BARRIER_SYSTEM_PTR', 'strip-barrier-systems\\\\aaa" + i + "', 0)\n";
////            fos.write(text.getBytes());
//        }

//        for (int i = 0; i < aContourIdx.length(); i++) {
//            String text = "    contour = RomeFilesOpen(files, '#XML:contour_file" + i + ".xml',0)\n";
//            fos.write(text.getBytes());
////            text = "    RomeFileSetAttrValue(profile, 'CONTOUR_SYSTEM_PTR', 'contour-systems\\\\aaa" + i + "', 0)\n";
////            fos.write(text.getBytes());
//        }

        fos.write("    # SET SLOPE\n".getBytes());
        String text = "    RomeFileSetAttrValue(profile, 'SLOPE_HORIZ', '" + length + "', 0)\n";
        fos.write(text.getBytes());
        text = "    RomeFileSetAttrValue(profile, 'SLOPE_STEEP', '" + steepness + "', 0)\n";
        fos.write(text.getBytes());

        fos.write("    # SET CLIMATE_PTR\n".getBytes());
        fos.write("    RomeFileSetAttrValue(profile, 'CLIMATE_PTR','climates\\\\aaa',0)\n".getBytes());
        fos.write("    print('CLIMATE_PTR=%s' % RomeFileGetAttrValue(profile, 'CLIMATE_PTR', 0))\n".getBytes());

        fos.write("    # SET TOPO LAYER\n".getBytes());
        if (aTopoLength.length() > 0) {
            text = "    RomeFileSetAttrSize(profile, 'TOPO_LAYER', " + aTopoLength.length() + ")\n";
            fos.write(text.getBytes());
            for (int i = 0; i < aTopoLength.length(); i++) 
            {
                text = "    RomeFileSetAttrValue(profile, 'TOPO_HORIZ', '" + aTopoLength.getString(i) + "', " + i + ")\n";
                fos.write(text.getBytes());
                text = "    RomeFileSetAttrValue(profile, 'TOPO_STEEP', '" + aTopoSteepness.getString(i) + "', " + i + ")\n";            
                fos.write(text.getBytes());
            }
        }

        // Presently we do not support multiple soils
        fos.write("    # SET SOIL LAYER\n".getBytes());
        if (aSoils.length() > 0) {
            text = "    RomeFileSetAttrSize(profile, 'SOIL_LAYER', " + aSoils.length() + ")\n";
            fos.write(text.getBytes());
            text = "    RomeFileSetAttrValue(profile, 'SOIL_HORIZ', '" + length + "', 0)\n";
            fos.write(text.getBytes());
            text = "    RomeFileSetAttrValue(profile, 'SOIL_PTR', '" + StringEscapeUtils.escapeJava(soilPtr[0]) + "', " + 0 + ")\n";
            fos.write(text.getBytes());
        }
        
        // Must be after set soils or the soils code resets it...sometimes
        if (JSONUtils.checkKeyExistsB(param, KEY_SIMPLE_ROCK_COVER)) {
            text = "    RomeFileSetAttrValue(profile, 'SIMPLE_ROCK_COVER', '" + simpleRockCoverPercent + "' ,0)\n";
            fos.write(text.getBytes());
        }

        fos.write("    # SET MAN LAYER\n".getBytes());
        if (aManIdx.length() > 0) {
            text = "    RomeFileSetAttrSize(profile, 'MAN_LAYER', " + aManIdx.length() + ")\n";
            fos.write(text.getBytes());
            for (int i = 0; i < aManIdx.length(); i++)
            {
                text = "    RomeFileSetAttrValue(profile, 'MAN_HORIZ', '" + aManLength.getString(i) + "', " + i + ")\n";
                fos.write(text.getBytes());
                LOG.info("escapeJava test=" + StringEscapeUtils.escapeJava("simple / test"));
                LOG.info("escapeJava test=" + StringEscapeUtils.escapeJavaScript("simple / test"));
                LOG.info("\n\n\n********************--- escapeJava man name=" + StringEscapeUtils.escapeJava(managementFormalName[aManIdx.getInt(i)]));
                LOG.info("********************--- escapeJavaScript man name=" + StringEscapeUtils.escapeJavaScript(managementFormalName[aManIdx.getInt(i)]));
                LOG.info("********************--- escapeHtml man name=" + StringEscapeUtils.escapeHtml(managementFormalName[aManIdx.getInt(i)]));
                LOG.info("********************--- escapeSql man name=" + StringEscapeUtils.escapeSql(managementFormalName[aManIdx.getInt(i)]));
                LOG.info("********************--- escapeXml man name=" + StringEscapeUtils.escapeXml(managementFormalName[aManIdx.getInt(i)]));
                LOG.info("********************--- raw Value is=" + managementFormalName[aManIdx.getInt(i)]);
                //text = "    RomeFileSetAttrValue(profile, 'MAN_PTR', '" + managementFormalName[aManIdx.getInt(i)] + "', " + i + ")\n";
                text = "    RomeFileSetAttrValue(profile, 'MAN_PTR', '" + R2Run.escapeJavaNoFwdSlash(managementFormalName[aManIdx.getInt(i)]) + "', " + i + ")\n";
                fos.write(text.getBytes());
            }
        }
        else
        {
            // IF no max_idx array provided, defaulting to single mgmt
            text = "    RomeFileSetAttrSize(profile, 'MAN_LAYER', 1)\n";
            fos.write(text.getBytes());
            text = "    RomeFileSetAttrValue(profile, 'MAN_HORIZ', '" + length + "', 0)\n";
            fos.write(text.getBytes());
            LOG.info("escapeJava test=" + StringEscapeUtils.escapeJava("simple / test"));
            LOG.info("escapeJava test=" + StringEscapeUtils.escapeJavaScript("simple / test"));
            LOG.info("\n\n\n********************--- escapeJava man name=" + StringEscapeUtils.escapeJava(managementFormalName[0]));
            LOG.info("********************--- escapeJavaScript man name=" + StringEscapeUtils.escapeJavaScript(managementFormalName[0]));
            LOG.info("********************--- escapeHtml man name=" + StringEscapeUtils.escapeHtml(managementFormalName[0]));
            LOG.info("********************--- escapeSql man name=" + StringEscapeUtils.escapeSql(managementFormalName[0]));
            LOG.info("********************--- escapeXml man name=" + StringEscapeUtils.escapeXml(managementFormalName[0]));
            LOG.info("********************--- raw Value is=" + managementFormalName[0]);
            text = "    RomeFileSetAttrValue(profile, 'MAN_PTR', '" + R2Run.escapeJavaNoFwdSlash(managementFormalName[0]) + "', 0)\n";
            fos.write(text.getBytes());
        }

        // This segment implementation is currently commented out in favor of populating the
        // individual topo, soil, and man layers above for now...
//        if (aTopoLength.length() > 1) {
//            
//            text = "    RomeFileSetAttrSize(profile, 'SEGMENT', " + aTopoLength.length() + ")\n";
//            fos.write(text.getBytes());
//            text = "    RomeFileSetAttrValue(profile, 'SOIL_LAYER', '#INSERT', 1)\n";
//            fos.write(text.getBytes());
//
//            for (int i = 0; i < aSoilIdx.length(); i++) {
//                text = "    print('LOAD SOIL WITH SOIL IDX=%s' % " + aSoilIdx.getInt(i) + ", " + i + ")\n";
//                fos.write(text.getBytes());
//                text = "    RomeFileSetAttrValue(profile, 'SOIL_PTR', '" + StringEscapeUtils.escapeJava(soilPtr[aSoilIdx.getInt(i)]) + ".xml', " + i + ")\n";
//                fos.write(text.getBytes());
//            }
//            for (int i = 0; i < aManIdx.length(); i++) {
//                text = "    RomeFileSetAttrValue(profile, 'MAN_PTR', '" + StringEscapeUtils.escapeJava(managementFormalName[aManIdx.getInt(i)]) + "', " + i + ")\n";
//                fos.write(text.getBytes());
//            }
//            for (int i = 0; i < aTopoLength.length(); i++) {
//                text = "    RomeFileSetAttrValue(profile, 'SEG_HORIZ', lengths[" + i + "], " + i + ")\n";
//                fos.write(text.getBytes());
//                text = "    RomeFileSetAttrValue(profile, 'SEG_STEEP', slopes[" + i + "], " + i + ")\n";
//                fos.write(text.getBytes());
//                text = "    RomeFileSetAttrValue(profile, 'SEG_MAN_LAYER', str(manIndex[" + i + "]), " + i + ")\n";
//                fos.write(text.getBytes());
//                text = "    print('SEG_MAN_LAYER=%s' % str(manIndex[" + i + "]), " + i + ")\n";
//                fos.write(text.getBytes());
//                text = "    RomeFileSetAttrValue(profile, 'SEG_SOIL_LAYER', str(soilIndex[" + i + "]), " + i + ")\n";
//                fos.write(text.getBytes());
//                text = "    print('SEG_SOIL_LAYER=%s' % str(soilIndex[" + i + "]), " + i + ")\n";
//                fos.write(text.getBytes());
//
////                if ((diversions != null) && (diversions.length() > 0)) {
////                    text = "    RomeFileSetAttrValue(profile, 'HYD_ELEM_SYSTEM_PTR', 'hydraulic-element-systems\\\\aaa" + aDiversionIdx.getInt(i) + "', " + i + ")\n";
////                    fos.write(text.getBytes());
////                }
////                if ((stripBarrrierSystems != null) && (stripBarrrierSystems.length() > 0)) {
////                    text = "    RomeFileSetAttrValue(profile, 'STRIP_BARRIER_SYSTEM_PTR', 'strip-barrier-systems\\\\aaa" + aStripBarrierIdx.getInt(i) + "', " + i + ")\n";
////                    fos.write(text.getBytes());
////                }
////                if ((contoursytems != null) && (contoursytems.length() > 0)) {
////                    text = "    RomeFileSetAttrValue(profile, 'CONTOUR_SYSTEM_PTR', 'contour-systems\\\\aaa" + aContourIdx.getInt(i) + "', " + i + ")\n";
////                    fos.write(text.getBytes());
//                }
//            }
//
//        } else {
//            text = "    RomeFileSetAttrValue(profile, 'SOIL_PTR', '" + StringEscapeUtils.escapeJava(soilPtr[0]) + ".xml', " + 0 + ")\n";
//            fos.write(text.getBytes());
//            text = "    RomeFileSetAttrValue(profile, 'MAN_PTR', '" + StringEscapeUtils.escapeJava(managementFormalName[0]) + "', " + 0 + ")\n";
//            fos.write(text.getBytes());
//        }

        //fos.write("    # Set SOIL_PTR\n".getBytes());
        //text = "    RomeFileSetAttrValue(profile, 'SOIL_PTR', '" + StringEscapeUtils.escapeJava(soilPtr[0]) + ".xml',0)\n";
        //fos.write(text.getBytes());
        fos.write("    print('SOIL_PTR=%s' % RomeFileGetAttrValue(profile, 'SOIL_PTR', 0))\n".getBytes());

//        fos.write("    # Set MAN_PTR\n".getBytes());
//        text = "    RomeFileSetAttrValue(profile, 'MAN_PTR', '" + StringEscapeUtils.escapeJava(managementFormalName[0]) + "',0)\n";
//        fos.write(text.getBytes());
//        fos.write("    print('MAN_PTR=%s' % RomeFileGetAttrValue(profile, 'MAN_PTR', 0))\n".getBytes());

        if ((contourSystem != null) && (contourSystem.length() > 1)) {
            // Contour Systems can simply point to the nginx XML file - no need to prefetch because of no special
            // characters in the file name
            text = "    RomeFileSetAttrValue(profile, 'CONTOUR_SYSTEM_PTR', '" + StringEscapeUtils.escapeJava(contourSystem) + "', 0)\n";
            fos.write(text.getBytes());
        }

        // To prevent issues with pyrome converting special chars in filenames to invalid chars for web server retrieval,
        // we prefetch the file, insert a dummy name, and point to it here
        if ((stripBarrierSystem != null) && (stripBarrierSystem.length() > 1)) {
            // for some reason, must reset SLOPE_HORIZ & SLOPE_STEEP immediately before setting a strip and barrier !!! R2 BUG
            // This is required for the internal Rusle2 wizard to calculate proper slope segment lengths
//            text = "    RomeFileSetAttrValue(profile, 'SLOPE_HORIZ', '" + length + "', 0)\n";
//            fos.write(text.getBytes());
//            text = "    RomeFileSetAttrValue(profile, 'SLOPE_STEEP', '" + steepness + "', 0)\n";
//            fos.write(text.getBytes());

            fos.write("    stripbarr = RomeFilesOpen(files, '#XML:stripbarr_file0.xml',0)\n".getBytes());
            text = "    RomeFileSetAttrValue(profile, 'STRIP_BARRIER_SYSTEM_PTR', 'strip-barrier-systems\\\\aaa', 0)\n";
            fos.write(text.getBytes());
        }        
        
        // Runs with a Hydraulic Element System, use a hydraulic element flow path
        if ((hydElemSystem != null) && (hydElemSystem.length() > 1)) {
            // Load the hyd elem flow path into the workspace
            fos.write("    hydelem = RomeFilesOpen(files, '#XML:hydelemflowpath_file.xml',0)\n".getBytes());
//            String r2db = Config.getString("r2.db", "http://oms-db.engr.colostate.edu/r2");
//            String hydelemHttpPtr = r2db + "/" + hydElemSystem.replace("\\", "/") + ".xml";
            int numFlowPaths =  r2run.DetermineNumberOfFlowPaths(hydElemSystem);
            text = "    RomeFileSetAttrSize(profile, 'NUM_FLOW_PATHS', " + numFlowPaths + ")\n";
            fos.write(text.getBytes());
            double offsets[] = r2run.DetermineFlowPathDistribution(hydElemSystem);
            for (int i=0 ; i< numFlowPaths; i++)
            {
                text = "    RomeFileSetAttrValue(profile, 'FLOW_PATH_HORIZ', '" + length * offsets[i] + "', " + i + ")\n";                
                fos.write(text.getBytes());
                if ( i < (numFlowPaths-1))
                {
                    text = "    RomeFileSetAttrValue(profile, 'HYD_ELEM_FLOW_PATH_PTR', 'hydraulic-element-flow-paths\\hydelemflowpath1', " + i + ")\n";
                    fos.write(text.getBytes());
                }
                else
                {
                    // last flow path is always the default
                    text = "    RomeFileSetAttrValue(profile, 'HYD_ELEM_FLOW_PATH_PTR', 'hydraulic-element-flow-paths\\default', " + i + ")\n";
                    fos.write(text.getBytes());
                }
            }
        }        
        
        


//        if ((contourSystem != null) && (contourSystem.length() > 1)) {
//            text = "    RomeFileSetAttrValue(profile, 'CONTOUR_SYSTEM_PTR', '" + contourSystem + "',0)\n";
//            fos.write(text.getBytes());
//        }
        fos.write("    RomeFileSave(profile)\n".getBytes());
        fos.write("    RomeEngineRun(engine)\n".getBytes());
//        fos.write("    results.append(RomeFileGetAttrValue(profile, 'SLOPE_SOIL_LOSS', 0))\n".getBytes());
//        fos.write("    results.append(RomeFileGetAttrValue(profile, 'SLOPE_DELIVERY', 0))\n".getBytes());
//        fos.write("    results.append(RomeFileGetAttrValue(profile, 'SLOPE_DEGRAD', 0))\n".getBytes());

        // Request specific outputs from Rusle2
        for (String r : JSONUtils.getRequestedResults(metainfo)) {
            text = "    paramsize = RomeFileGetAttrSize(profile,'" + r + "')\n";
            fos.write(text.getBytes());
            text = "    if paramsize > 1:\n";
            fos.write(text.getBytes());
            text = "        text = '['\n";
            fos.write(text.getBytes());
            text = "        for x in range (paramsize):\n";
            fos.write(text.getBytes());
            text = "            text += RomeFileGetAttrValue(profile,'" + r + "',x)\n";
            fos.write(text.getBytes());
            text = "            if x < (paramsize-1):\n";
            fos.write(text.getBytes());
            text = "                text += ', '\n";
            fos.write(text.getBytes());
            text = "        text += ']'\n";
            fos.write(text.getBytes());
            text = "    else:\n";
            fos.write(text.getBytes());
            text = "        text = RomeFileGetAttrValue(profile, '" + r + "', 0)\n";
            fos.write(text.getBytes());
            text = "    results.append(RomeFileGetAttrValue(profile, '" + r + "', 0))\n";
            fos.write(text.getBytes());
            text = "    print('" + r + "=%s' % text)\n";
            fos.write(text.getBytes());
        }

        // Request output for segments (seg 0 for non segmented runs)
        fos.write("    numflowpaths = RomeFileGetAttrSize(profile, 'NUM_FLOW_PATHS')\n".getBytes());
        fos.write("    print('------------------------------------------------------------------------------')\n".getBytes());
        fos.write("    print('NUMBER OF FLOWPATHS=%d' % numflowpaths)\n".getBytes());
        fos.write("    for xx in range (numflowpaths):\n".getBytes());
        fos.write("        print('FLOW_PATH_HORIZ:%d=%s' % (xx, RomeFileGetAttrValue(profile, 'FLOW_PATH_HORIZ', xx)))\n".getBytes());
        fos.write("        print('HYD_ELEM_FLOW_PATH_PTR:%d=%s' % (xx, RomeFileGetAttrValue(profile, 'HYD_ELEM_FLOW_PATH_PTR', xx)))\n".getBytes());
        fos.write("    numsegs = RomeFileGetAttrSize(profile, 'SEGMENT')\n".getBytes());
        fos.write("    print('NUMBER OF SEGMENTS=%d' % numsegs)\n".getBytes());
        fos.write("    for x in range (numsegs):\n".getBytes());
        fos.write("        print('------------------------------------------------------------------------------')\n".getBytes());
        fos.write("        print('SEGMENT:%d=%s' % (x, RomeFileGetAttrValue(profile, 'SEGMENT', x)))\n".getBytes());
        fos.write("        print('SEG_HORIZ:%d=%s' % (x, RomeFileGetAttrValue(profile, 'SEG_HORIZ', x)))\n".getBytes());
        fos.write("        print('SEG_STEEP:%d=%s' % (x,RomeFileGetAttrValue(profile, 'SEG_STEEP', x)))\n".getBytes());
        fos.write("        print('SEG_MAN:%d=%s' % (x, RomeFileGetAttrValue(profile, 'MAN_PTR', x)))\n".getBytes());
        fos.write("        print('SEG_SOIL:%d=%s' % (x, RomeFileGetAttrValue(profile, 'SOIL_PTR', x)))\n".getBytes());
        fos.write("        results.append(RomeFileGetAttrValue(profile, 'SEG_SOIL_LOSS', x))\n".getBytes());
        fos.write("        print('SEG_SOIL_LOSS:%d=%s' % (x, RomeFileGetAttrValue(profile, 'SEG_SOIL_LOSS', x)))\n".getBytes());
        fos.write("        print('SEG_SOIL_LAYER %d=%s' % (x, RomeFileGetAttrValue(profile, 'SEG_SOIL_LAYER', x)))\n".getBytes());
        fos.write("        print('SEG_MAN_LAYER %d=%s' % (x, RomeFileGetAttrValue(profile, 'SEG_MAN_LAYER', x)))\n".getBytes());
        fos.write("        print('HYD_ELEM_SYS:%d=%s' % (x, RomeFileGetAttrValue(profile, 'HYD_ELEM_SYSTEM_PTR', x)))\n".getBytes());
        fos.write("        print('STRIP_BARRIER_SYS:%d=%s' % (x, RomeFileGetAttrValue(profile, 'STRIP_BARRIER_SYSTEM_PTR', x)))\n".getBytes());
        fos.write("        print('CONTOUR_SYS:%d=%s' % (x, RomeFileGetAttrValue(profile, 'CONTOUR_SYSTEM_PTR', x)))\n".getBytes());
        fos.write("    print('------------------------------------------------------------------------------')\n".getBytes());

        fos.write("    numsegs = RomeFileGetAttrSize(profile, 'SOIL_LAYER')\n".getBytes());
        fos.write("    print('NUMBER OF SOIL SEGMENTS=%d' % numsegs)\n".getBytes());
        fos.write("    for x in range (numsegs):\n".getBytes());
        fos.write("        print('------------------------------------------------------------------------------')\n".getBytes());
        fos.write("        print('SOIL_SEGMENT:%d=%s' % (x, RomeFileGetAttrValue(profile, 'SOIL_LAYER', x)))\n".getBytes());
        fos.write("        print('SOIL_HORIZ:%d=%s' % (x, RomeFileGetAttrValue(profile, 'SOIL_HORIZ', x)))\n".getBytes());
        fos.write("        print('SOIL_PTR:%d=%s' % (x, RomeFileGetAttrValue(profile, 'SOIL_PTR', x)))\n".getBytes());
        fos.write("    print('------------------------------------------------------------------------------')\n".getBytes());

        fos.write("    numsegs = RomeFileGetAttrSize(profile, 'MAN_LAYER')\n".getBytes());
        fos.write("    print('NUMBER OF MAN SEGMENTS=%d' % numsegs)\n".getBytes());
        fos.write("    for x in range (numsegs):\n".getBytes());
        fos.write("        print('------------------------------------------------------------------------------')\n".getBytes());
        fos.write("        print('MAN_SEGMENT:%d=%s' % (x, RomeFileGetAttrValue(profile, 'MAN_LAYER', x)))\n".getBytes());
        fos.write("        print('MAN_HORIZ:%d=%s' % (x, RomeFileGetAttrValue(profile, 'MAN_HORIZ', x)))\n".getBytes());
        fos.write("        print('MAN_PTR:%d=%s' % (x, RomeFileGetAttrValue(profile, 'MAN_PTR', x)))\n".getBytes());
        fos.write("    print('------------------------------------------------------------------------------')\n".getBytes());

        fos.write("    numsegs = RomeFileGetAttrSize(profile, 'TOPO_LAYER')\n".getBytes());
        fos.write("    print('NUMBER OF TOPO SEGMENTS=%d' % numsegs)\n".getBytes());
        fos.write("    for x in range (numsegs):\n".getBytes());
        fos.write("        print('------------------------------------------------------------------------------')\n".getBytes());
        fos.write("        print('TOPO_SEGMENT:%d=%s' % (x, RomeFileGetAttrValue(profile, 'TOPO_LAYER', x)))\n".getBytes());
        fos.write("        print('TOPO_HORIZ:%d=%s' % (x, RomeFileGetAttrValue(profile, 'TOPO_HORIZ', x)))\n".getBytes());
        fos.write("        print('TOPO_HORIZ_COMPOSITE:%d=%s' % (x, RomeFileGetAttrValue(profile, 'TOPO_HORIZ_COMPOSITE', x)))\n".getBytes());
        fos.write("        print('TOPO_STEEP:%d=%s' % (x, RomeFileGetAttrValue(profile, 'TOPO_STEEP', x)))\n".getBytes());
        fos.write("        print('TOPO_STEEP_COMPOSITE:%d=%s' % (x, RomeFileGetAttrValue(profile, 'TOPO_STEEP_COMPOSITE', x)))\n".getBytes());
        fos.write("    print('------------------------------------------------------------------------------')\n".getBytes());
        

//        // request erosion by segment, if a segmented run
//        if (aTopoLength.length() > 1) {
//            for (int i = 0; i < aTopoLength.length(); i++) {
//                text = "    results.append(RomeFileGetAttrValue(profile, 'SEG_SOIL_LOSS', " + i + "))\n";
//                fos.write(text.getBytes());
//                text = "    print('SEG_SOIL_LOSS:" + i + "=%s' % (RomeFileGetAttrValue(profile, 'SEG_SOIL_LOSS', " + i + ")))\n";
//                fos.write(text.getBytes());
////                text = "    results.append(float(RomeFileGetAttrValue(profile, 'SEG_SOIL_LOSS', " + i + ")))\n";
////                fos.write(text.getBytes());
////                text = "    print('seg man layer %i =%s' % (" +i + " , RomeFileGetAttrValue(profile, 'SEG_MAN_LAYER', " + i + ")))\n";
////                fos.write(text.getBytes());
////                text = "    print('seg soil layer %i =%s' % (" + i + " , RomeFileGetAttrValue(profile, 'SEG_SOIL_LAYER', " + i + ")))\n";
////                fos.write(text.getBytes());
////                text = "    print('seg soil loss %i =%s' % (" + i + " , RomeFileGetAttrValue(profile, 'SEG_SOIL_LOSS', " + i + ")))\n";
////                fos.write(text.getBytes());
////                text = "    print('slope soil loss %i =%s' % (" + i + " , RomeFileGetAttrValue(profile, 'SLOPE_SOIL_LOSS', " + i + ")))\n";
////                fos.write(text.getBytes());
////                text = "    results.append(RomeFileGetAttrValue(profile, 'SLOPE_SOIL_LOSS', " + i + "))\n";
////                fos.write(text.getBytes());
//                text = "    print('SEG_SOIL:" + i + "=%s' % RomeFileGetAttrValue(profile, 'SOIL_PTR', " + i + "))\n";
//                fos.write(text.getBytes());
//                text = "    print('SEG_MAN:" + i + "=%s' % RomeFileGetAttrValue(profile, 'MAN_PTR', " + i + "))\n";
//                fos.write(text.getBytes());
//                text = "    print('SEG_SOIL_LAYER " + i + "=%s' % (RomeFileGetAttrValue(profile, 'SEG_SOIL_LAYER', " + i + ")))\n";
//                fos.write(text.getBytes());
//                text = "    print('SEG_MAN_LAYER " + i + "=%s' % (RomeFileGetAttrValue(profile, 'SEG_MAN_LAYER', " + i + ")))\n";
//                fos.write(text.getBytes());
//                text = "    print('HYD_ELEM_SYS:" + i + "=%s' % (RomeFileGetAttrValue(profile, 'HYD_ELEM_SYSTEM_PTR', " + i + ")))\n";
//                fos.write(text.getBytes());
//                text = "    print('STRIP_BARRIER_SYS:" + i + "=%s' % (RomeFileGetAttrValue(profile, 'STRIP_BARRIER_SYSTEM_PTR', " + i + ")))\n";
//                fos.write(text.getBytes());
//                text = "    print('CONTOUR_SYS:" + i + "=%s' % (RomeFileGetAttrValue(profile, 'CONTOUR_SYSTEM_PTR', " + i + ")))\n";
//                fos.write(text.getBytes());
//            }
//        } else {
//            // always return soil and man ptrs at index 0 - requested by Lucas for IET
//            text = "    print('SEG_SOIL:0" + "=%s' % RomeFileGetAttrValue(profile, 'SOIL_PTR', " + 0 + "))\n";
//            fos.write(text.getBytes());
//            text = "    print('SEG_MAN:0" + "=%s' % RomeFileGetAttrValue(profile, 'MAN_PTR', " + 0 + "))\n";
//            fos.write(text.getBytes());
//            // 
//        }


//        fos.write("    print('SLOPE_DELIVERY=%s' % RomeFileGetAttrValue(profile, 'SLOPE_DELIVERY', 0))\n".getBytes());
//        fos.write("    print('SLOPE_T_VALUE=%s' % RomeFileGetAttrValue(profile, 'SLOPE_T_VALUE', 0))\n".getBytes());
//        fos.write("    print('SLOPE_DEGRAD=%s' % RomeFileGetAttrValue(profile, 'SLOPE_DEGRAD', 0))\n".getBytes());
        text = "    exec(open(\"" + REPORT_PY_FILENAME + "\").read())\n";
        fos.write(text.getBytes());
        fos.write("    RomeFileClose(profile)\n".getBytes());
        fos.write("    return results\n".getBytes());

        fos.write("if __name__ == \"__main__\":\n".getBytes());
        fos.write("    #inputs\n".getBytes());
        fos.write("    save = False\n".getBytes());
        fos.write("    #Run simulation\n".getBytes());
        fos.write("    romeDLL = RomeInit('pyrome /DirRoot=/tmp/csip/bin/bin/win-x86')\n".getBytes());
        fos.write("    database = RomeGetDatabase(romeDLL)\n".getBytes());
        // prints all outputs in single array
        //fos.write("    print(results[:])\n".getBytes());

        // Specify the nginx server
        String r2db = Config.getString("r2.db", "http://oms-db.engr.colostate.edu/r2");
        if (altR2db == null) {
            text = "    RomeDatabaseOpen(database,'" + r2db + "')\n";
            fos.write(text.getBytes());
        } else {
            String altr2db = r2db.substring(0, r2db.lastIndexOf("/")) + "/model-data/" + altR2db;
            text = "    RomeDatabaseOpen(database,'" + altr2db + "')\n";
            fos.write(text.getBytes());
        }
        fos.write("    results = linearTest(save)\n".getBytes());
        fos.write("    RomeDatabaseClose(database)\n".getBytes());
        fos.write("    RomeExit(romeDLL)\n".getBytes());

        // Prepare multiple soils, strips barriers, and hydraulic element files
        if(!Config.getBoolean("sdmONLINE",false)){
            for (int i = 0; i < aSoils.length(); i++) {
                String soilHttpPtr = r2db + "/" + soilPtr[i].replace("\\", "/") + ".xml";
                //r2run.prepareSoilsFile(soilHttpPtr, new File(getWorkspaceDir(), "soils_file" + i + ".xml"), true, String.valueOf(i));
                r2run.prepareFileJ(soilHttpPtr, new File(getWorkspaceDir(), "soils_file" + i + ".xml"), "SOIL", "", "", true);
            }
        }
//        for (int i = 0; i < contoursytems.length(); i++) {
//            String contourSys = contoursytems.getString(i);
//            String contourHttpPtr = r2db + "/" + contourSys.replace("\\", "/") + ".xml";
//            r2run.prepareFile(contourHttpPtr, new File(getWorkspaceDir(), "contour_file" + i + ".xml"), "contour", "contour-systems", Integer.toString(i));
//        }
//        for (int i = 0; i < stripBarrrierSystems.length(); i++) {
//            String stripBarrierSys = stripBarrrierSystems.getString(i);
//            String stripbarrHttpPtr = r2db + "/" + stripBarrierSys.replace("\\", "/") + ".xml";
//            r2run.prepareFile(stripbarrHttpPtr, new File(getWorkspaceDir(), "stripbarr_file" + i + ".xml"), "strip-barrier", "strip-barrier-systems", Integer.toString(i));
//        }
//        for (int i = 0; i < diversions.length(); i++) {
//            String hydElemSys = diversions.getString(i);
//            String hydelemHttpPtr = r2db + "/" + hydElemSys.replace("\\", "/") + ".xml";
//            r2run.prepareFile(hydelemHttpPtr, new File(getWorkspaceDir(), "hydelem_file" + i + ".xml"), "hydraulic-element", "hydraulic-element-systems", Integer.toString(i));
//        }

        // prepare individual contour system, strip barrier system, hyd elem sys, if not provided in an array
        if (JSONUtils.checkKeyExistsB(param, KEY_CONTOUR_SYSTEM_PTR)) {
            String contourHttpPtr = r2db + "/" + contourSystem.replace("\\", "/") + ".xml";
            r2run.prepareFileJ(contourHttpPtr, new File(getWorkspaceDir(), "contour_file0.xml"), "", "contour-systems", "",true);
        }
        if (JSONUtils.checkKeyExistsB(param, KEY_STRIP_BARRIER_SYSTEM_PTR)) {
            String stripbarrHttpPtr = r2db + "/" + stripBarrierSystem.replace("\\", "/") + ".xml";
            r2run.prepareFileJ(stripbarrHttpPtr, new File(getWorkspaceDir(), "stripbarr_file0.xml"), "", "strip-barrier-systems", "", true);
        }
        if (JSONUtils.checkKeyExistsB(param, KEY_HYD_ELEM_SYSTEM_PTR)) {
            String hydelemHttpPtr = r2db + "/" + hydElemSystem.replace("\\", "/") + ".xml";
            r2run.prepareHydraulicElementFlowPathJ(hydelemHttpPtr, r2db, new File(getWorkspaceDir(), "hydelemflowpath_file.xml"));
            //r2run.prepareFileJ(hydelemHttpPtr, new File(getWorkspaceDir(), "hydelemflowpath_file.xml"), climate, text, r2db);
        }

        // prepare climate file
        String cliHttpPtr = r2db + "/" + climatePtr.replace("\\", "/") + ".xml";
        //r2run.prepareClimateFileJ(cliHttpPtr, new File(getWorkspaceDir(), "cli_file0.xml"));
        r2run.prepareFileJ(cliHttpPtr, new File(getWorkspaceDir(), "cli_file0.xml"), "CLIMATE", "climates", "", true);
        //r2run.prepareClimateFile(cliHttpPtr, new File(getWorkspaceDir(), "cli_file0.xml"));

        // to do
        // implement rusle 2 report in pyrome
        // Rusle2 report
        //fos.write("READ \"rusle2_report.rsh\"\n".getBytes());
        fos.close();

        // Unpack the report rsh file in the work space dir 
        Binaries.unpackResourceAbsolute("/bin/win-x86/" + REPORT_PY_FILENAME, getWorkspaceDir().toString() + "/" + REPORT_PY_FILENAME);

        climate = climatePtr;
        soil = soilPtr[0];
        mgmt = managementFormalName[0];

        LOG.info("R2 script: " + file.toString());
    }

    private String[] getSoilFiles(JSONArray cokeys) throws JSONException, Exception{
        String soilPtr[] = new String[(cokeys.length())];
        JSONObject soilsRequest = new JSONObject();
        JSONObject meta = new JSONObject();
        JSONArray paramObj = new JSONArray();
        JSONObject cokeyObj = new JSONObject();
        String cokey;
        JSONObject responseMeta;
        JSONArray resultArr;
        JSONObject soilObj;
        String soilFilePath;
        
        soilsRequest.put(KEY_METAINFO, meta);
        soilsRequest.put(KEY_PARAMETER, paramObj);
        paramObj.put(cokeyObj);
        
        for(int i=0;i< cokeys.length();i++){
            cokey = cokeys.getString(i);
            paramObj.put(0,cokeyObj);
            cokeyObj.put(KEY_NAME, KEY_COKEY);
            cokeyObj.put(KEY_VALUE,cokey);
            LOG.info("SOILS Request: "+soilsRequest.toString());
            JSONObject soilsResponse = new Client().doPOST(Config.getString("r2.soils","http://csip.engr.colostate.edu:8092/csip-soils/d/soilsXML/1.0"), soilsRequest);
            LOG.info("SOILS Response: "+soilsResponse.toString());
            responseMeta = soilsResponse.getJSONObject(KEY_METAINFO);
            if(!responseMeta.getString(KEY_STATUS).equalsIgnoreCase("Failed")){
                resultArr = soilsResponse.getJSONArray(KEY_RESULT);
                soilObj = resultArr.getJSONObject(0);
                soilFilePath = soilObj.getString(KEY_VALUE);

                new Client().doGET(soilFilePath,getWorkspaceFile( "soils_file" + i + ".xml"));

                soilPtr[i] = getSoilFilePath(getWorkspaceFile( "soils_file" + i + ".xml")).replace("/", "\\");
                LOG.info("THE SOIL IS =" + soilPtr[i] + "\n\n\n\n");

            }else{
                LOG.warning("No soil found for cokey "+ cokey);
                setMetainfoWarning("Incomplete soil data for cokey "+cokey+". Default used");
            }
        }
        return soilPtr;
    }
    private String getSoilFilePath(File soilFile) throws ParserConfigurationException, SAXException, IOException{
        String path = "";
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
        
        Document document = documentBuilder.parse(soilFile);
        
        path = document.getElementsByTagName("Filename").item(0).getTextContent();

        return path;
    }

    private String getFilenumber(String filename) {
        return filename.substring(R2_TMP_FILENAME.length(), filename.length() - R2_TMP_FILEEXT.length());
    }


    @Override
    protected JSONArray createReport() throws Exception {
        String sessionWorkDir = getWorkspaceDir().toString();
        String reportJSON = Binaries.unpackResourceAbsolute("/bin/win-x86/" + REPORT_JSON_TEMPLATE_FILENAME, sessionWorkDir + "/" + REPORT_JSON_TEMPLATE_FILENAME).toString();
        File reportTemplate = new File(sessionWorkDir + "/" + REPORT_JSON_TEMPLATE_FILENAME);
        String sReportJSON = FileUtils.readFileToString(reportTemplate);
        JSONArray reportItemsFromTemplate = new JSONArray(sReportJSON);
        JSONArray reportItemsOutput = new JSONArray();

        for (int i = 0; i < reportItemsFromTemplate.length(); i++) {
            JSONObject obj = (JSONObject) reportItemsFromTemplate.get(i);
            String itemName = obj.getString(REPORT_NAME);
            String dimension = JSONUtils.getJSONString(obj, REPORT_DIM, null);
            String type = JSONUtils.getJSONString(obj, REPORT_TYPE, "");
            //LOG.info("Attempting to fetch results for:" + itemName);
        System.out.println("------------------------------------------------------------------------PROCESSING ELEMENT:");
        System.out.println("VAR NAME:" + itemName);
        System.out.println("-------------------------------------------------------------------------------------------");
            
            //String value = r2run.getResultPyrome(itemName);
            String value = r2run.getResult("\"" + itemName + "\"");
            LOG.info("the value='" + value + "'");
            if ((value != null) && (value.equals("null"))) {
                obj.put(REPORT_VALUE, (String) null);
                // if there is no value, then item should be removed from the array
            } else {
                if ((dimension != null) && (dimension.length() > 0) && (value != null) && (!value.equals("null"))) {
                    try {
                        obj.put(REPORT_VALUE, new JSONArray(value));
                    } catch (JSONException je) {
                        obj = processReportElement(obj, type, value);
                    }
                } else {
                    obj = processReportElement(obj, type, value);
                }
                obj.remove(REPORT_TYPE);
                //LOG.info("units output is='" + JSONUtils.getString(obj,REPORT_UNITS,null) + "'");
                //LOG.info("obj to add=" + obj.toString());
                reportItemsOutput.put(obj);
            }
        }

        return reportItemsOutput;
        //LOG.info("report jsonarray=" + reportItemsOutput.toString());        
        //LOG.info("Rusle2 report output obj=" + reportObj.toString());        
    }

    private void prepareHydraulicFlowElementFile()
    {
        // Given a Hydraulic Element Pointer, parse the XML and return a Hydraulic Flow Element
    }
    
    private JSONObject processReportElement(JSONObject obj, String type, String value) throws Exception {
        System.out.println("------------------------------------------------------------------------PROCESSING ELEMENT:\n\n");
        System.out.println("TYPE:" + type);
        System.out.println("VALUE:" + value);
        System.out.println("-------------------------------------------------------------------------------------------\n\n");

        if ((type.equals("TEXT")) || (type.equals("FILENAME")) || (type.equals("DATE"))) {
            // because the RomeShell returns escaped strings, and the JSONObject in Java re-escapes them
            // we have to remove one level of "escaping" !!! 
            
            String newString = StringEscapeUtils.unescapeJava(value);
            //String newString=value;
            obj.put(REPORT_VALUE, Services.removeFirstLastChar(newString));
        }
        if (type.equals("INTEGER") && (value != null) && (!value.equals("null")) && (!value.equals("\"\""))) {
            // trim off quotes
            value = Services.removeFirstLastChar(value);
            System.out.println("VALUE:" + value);
            obj.put("value", new Double(value).intValue());
        }
        if (type.equals("REAL") && (value != null)) {
            if ((!value.equals("null")) && (!value.equals("\"\""))) {
                // trim off quotes
                value = Services.removeFirstLastChar(value);
                System.out.println("VALUE:" + value);
                obj.put(REPORT_VALUE, new Double(value).doubleValue());
            }
            if (value.equals("\"\"")) {
                obj.put(REPORT_VALUE, new Double(0).doubleValue());
            }
        }
        if (type.equals("")) {
            obj.put(REPORT_VALUE, value);
        }
        return obj;
    }


    private boolean allEqual(int... vals) {
        if (vals.length < 2) {
            return true;
        }
        int a = vals[0];
        for (int i = 0; i < vals.length; i++) {
            if (vals[i] != a) {
                return false;
            }
        }
        return true;
    }
}