V3_0.java [src/java/m/rusle2] Revision: 24eb0cf5c7944d83b6d6b536a7f3ffb571fac260  Date: Tue Nov 12 16:40:04 MST 2019
/*
 * $Id$
 *
 * This file is part of the Cloud Services Integration Platform (CSIP),
 * a Model-as-a-Service framework, API, and application suite.
 *
 * 2012-2017, OMSLab, Colorado State University.
 *
 * OMSLab licenses this file to you under the MIT license.
 * See the LICENSE file in the project root for more information.
 */
package m.rusle2;

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.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.VALUE;
import csip.annotations.*;
import static csip.annotations.ResourceType.ARCHIVE;
import static csip.annotations.ResourceType.FILE;
import static csip.annotations.ResourceType.REFERENCE;
import static csip.annotations.State.RELEASED;
import static util.Constants.*;

import csip.utils.JSONUtils;
import csip.utils.Services;
import java.io.IOException;
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.V3_0.*;
import org.xml.sax.SAXException;

/**
 * REST Web Service. Front end callable.
 *
 * @author wlloyd, od
 */
@Name("Rusle2")
@Description("IET / pyrome version of RomeDLL 2.6.8.4; references NRCS Soil Data Mart")
@VersionInfo("3.0")
@State(RELEASED)
@Path("m/rusle2/3.0")
@Polling(first = 1000, next = 1000)

@Resource(type = FILE, file = "/bin/win-x86/2.6.8.4/RomeDLL.dll", id = ROMEDLL)
@Resource(type = FILE, file = "/bin/win-x86/2.6.8.4/pyrome.py", id = PYROMESRC)
@Resource(type = FILE, file = "/bin/win-x86/2.6.8.4/_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)

@Resource(type = FILE, file = "/bin/win-x86/rusle2_report.py", id = REPORT_PY_FILENAME)
@Resource(type = FILE, file = "/bin/win-x86/Rusle2_Report.json", id = REPORT_JSON_TEMPLATE_FILENAME)

public class V3_0 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;
    // moved these to globals so both R2 and ann can use them.
    protected double steepness;
    protected double length;
    protected String contourSystem;
    protected JSONArray managements;
    protected JSONArray aSoils;
    protected String climatePtr;

    //

    @Override
    protected void preProcess() throws Exception {
        // check for requested output.
        r2run.setLogger(LOG);
        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);
        }

        JSONUtils.checkKeyExists(getParamMap(), KEY_SOILS);
        JSONUtils.checkKeyExists(getParamMap(), KEY_LENGTH);
        JSONUtils.checkKeyExists(getParamMap(), KEY_STEEPNESS);
        JSONUtils.checkKeyExists(getParamMap(), KEY_MGMTS);
        
        if(!r2run.isUrlReachable("climates/default.xml"))
            throw new ServiceException("R2 file server unreachable at: " + Config.getString("r2.db", "http://oms-db.engr.colostate.edu/r2"));

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


    @Override
    protected void doProcess() throws Exception {
        try {
            Executable python = resources().getExe(V3_0.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 void postProcess() throws Exception {
        int errors = 0;
        for (int i = 0; i < operations.size(); i++) {
            String op = operations.get(i);
            if (r2run.isFileUrlReachable(op)) {
                results().put("OPERATION_" + (i + 1), op, "operation is valid");
            } else {
                results().put("OPERATION_INVALID_" + (i + 1), op, "OPERATION IS MISSING!");
                errors++;
            }
        }
        for (int i = 0; i < vegetations.size(); i++) {
            String vege = vegetations.get(i);
            if (r2run.isFileUrlReachable(vege)) {
                results().put("VEGETATION_" + (i + 1),vege,"vegetation is valid");
            } else {
                results().put("VEGETATION_INVALID_" + (i + 1), vege, "VEGETATION IS MISSING");
                errors++;
            }
        }
        for (int i = 0; i < residues.size(); i++) {
            String res = residues.get(i);
            if (r2run.isFileUrlReachable(res)) {
                results().put("RESIDUE_" + (i + 1), res, "residue is valid");
            } else {
                results().put("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(r, r2run.getResultPyrome(r), R2_MISSING_XML_FILES_WARNING_MSG);
            } else {
                results().put(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("SEG_SOIL_LOSS", aSoilLoss);
                results().put(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");
                results().put(KEY_SOILS, new JSONArray(r2run.getResultPyromeArray("SEG_SOIL", true, true, true)));
                results().put(KEY_MANAGEMENTS, new JSONArray(r2run.getResultPyromeArray("SEG_MAN", true, true, true)));
                if (JSONUtils.checkKeyExistsB(getParamMap(), KEY_DIVERSIONS)) 
                    results().put(KEY_DIVERSIONS, r2run.getResultPyromeArray("HYD_ELEM_SYS", true, true, true));
                
                if (JSONUtils.checkKeyExistsB(getParamMap(), KEY_STRIP_BARRIER_SYSTEMS)) {
                    results().put(KEY_STRIP_BARRIER_SYSTEMS, r2run.getResultPyromeArray("STRIP_BARRIER_SYS", true, true, true));
                }
            }
        } else {
            results().put(KEY_CLIMATES, climate);
            results().put(KEY_SOILS, new JSONArray(r2run.getResultPyromeArray("SEG_SOIL", true, true, true)));
            results().put(KEY_MANAGEMENTS, new JSONArray(r2run.getResultPyromeArray("SEG_MAN", true, true, true)));
        }
    }


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

        steepness = JSONUtils.getDoubleParam(param, KEY_STEEPNESS, 0.0);
        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);
            }
        }

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

        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
        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");
        //
        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);
        }

        // 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) {

        climatePtr = getClimateFilePath(latitude, longitude);
//            // 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);
//                }
//            }

        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('"+ resources().getFile(PYROMESRC).getParent().replace('\\','/')+"')\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="+ resources().getFile(ROMEDLL).getParent().replace('\\','/')+"/')\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());

//        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
        //r2run.prepareClimateFileJ(cliHttpPtr, new File(getWorkspaceDir(), "cli_file0.xml"));
        r2run.prepareFileJ(climatePtr, 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);
        FileUtils.copyFileToDirectory(resources().getFile(REPORT_PY_FILENAME), getWorkspaceDir());

        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 {
                String error = responseMeta.getString(ERROR);
                throw new ServiceException("Soil service error: " + error);
            }
        }
        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 getClimateFilePath(double lat, double lon) throws JSONException, Exception {
        JSONObject climateReq = new JSONObject();
        JSONObject meta = new JSONObject();
        JSONArray param = new JSONArray();
        JSONObject jlat = new JSONObject();
        JSONObject jlong = new JSONObject();
        JSONArray resultArr;
        JSONObject responseMeta;
        JSONObject cliObj;
        String climatePath = "";

        climateReq.put(KEY_METAINFO, meta);
        climateReq.put(KEY_PARAMETER, param);

        param.put(jlat);
        param.put(jlong);

        jlat.put(KEY_NAME, KEY_LATITUDE);
        jlat.put(KEY_VALUE, lat);

        jlong.put(KEY_NAME, KEY_LONGITUDE);
        jlong.put(KEY_VALUE, lon);

        LOG.info("CLIMATE Request: " + climateReq.toString());
        JSONObject climateResponse = new Client().doPOST(Config.getString("r2.climate", "http://csip.engr.colostate.edu:8092/csip-misc/d/r2climate/2.0"), climateReq);
        LOG.info("CLIMATE Response: " + climateResponse.toString());
        responseMeta = climateResponse.getJSONObject(KEY_METAINFO);
        if (!responseMeta.getString(KEY_STATUS).equalsIgnoreCase("Failed")) {
            resultArr = climateResponse.getJSONArray(KEY_RESULT);
            cliObj = JSONUtils.preprocess(resultArr).get(KEY_CLIMATE_URL);
            climatePath = cliObj.getString(KEY_VALUE);
        }

        return climatePath;
    }


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


    @Override
    protected void doReport() 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);
        File reportTemplate = resources().getFile(REPORT_JSON_TEMPLATE_FILENAME);
        
        String sReportJSON = FileUtils.readFileToString(reportTemplate);
        JSONArray reportItemsFromTemplate = new JSONArray(sReportJSON);

        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, "");
            String units = JSONUtils.getJSONString(obj, REPORT_UNITS, null);
            String desc = JSONUtils.getJSONString(obj, REPORT_DESC, null);
            //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"))) {
                report().put(itemName, (String) null, desc, units);
                // 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 {
                        report().put(itemName, new JSONArray(value), desc, units);
                    } catch (JSONException je) {
                        processReportElement(itemName,dimension,units,desc, type, value);
                    }
                } else {
                    processReportElement(itemName,dimension,units,desc, type, value);
                }

            }
            if(dimension != null)
                report().putMetaInfo(itemName,REPORT_DIM,new JSONArray(dimension));
        }     
    }


    private void prepareHydraulicFlowElementFile() {
        // Given a Hydraulic Element Pointer, parse the XML and return a Hydraulic Flow Element
    }


    // This is a gross signiture but due to csip report changes this is the easiest way to change it without losing Wes's logic.
    private void processReportElement(String itemName, String dim, String units, String desc, 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;
            report().put(itemName, Services.removeFirstLastChar(newString), desc, units);
        }
        if (type.equals("INTEGER") && (value != null) && (!value.equals("null")) && (!value.equals("\"\""))) {
            // trim off quotes
            value = Services.removeFirstLastChar(value);
            System.out.println("VALUE:" + value);
            report().put(itemName, new Double(value).intValue(), desc, units);
        }
        if (type.equals("REAL") && (value != null)) {
            if ((!value.equals("null")) && (!value.equals("\"\""))) {
                // trim off quotes
                value = Services.removeFirstLastChar(value);
                System.out.println("VALUE:" + value);
                report().put(itemName, Double.parseDouble(value), desc, units);
            }
            if (value.equals("\"\"")) {
                report().put(itemName, new Double(0), desc, units);
            }
        }
        if (type.equals("")) {
            report().put(itemName, value, desc, units);
        }
    }


    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;
    }
}