V1_31.java [src/java/m/rusle2] Revision: 1e3f2b36363f0eeca9f70d1b10adc5e6aaf69e99  Date: Tue Nov 06 16:10:17 MST 2018
/*
 * $Id:$
 * 
 * This file is part of CSIP/OMS applcation suite,
 * 2010-2017, Olaf David and others, Colorado State University.
 *
 * CSIP/OMS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 2.1.
 *
 * CSIP/OMS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with CSIP/OMS.  If not, see <http://www.gnu.org/licenses/lgpl.txt>.
 */
package m.rusle2;

import c.GIS_DB;
import c.SqlGIS;
import csip.Config;
import csip.Executable;
import csip.ServiceException;
import java.io.File;
import java.io.FileOutputStream;
import java.util.*;
import javax.ws.rs.*;
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 util.ErosionConst.*;

import csip.utils.JSONUtils;
import csip.utils.Services;
import csip.annotations.Polling;
import csip.annotations.Resource;
import static csip.annotations.ResourceType.EXECUTABLE;
import static csip.annotations.ResourceType.FILE;
import static csip.annotations.ResourceType.JDBC;
import static csip.annotations.State.RELEASED;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.logging.Level;

import static m.rusle2.V1_31.*;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;

/**
 * REST Web Service. Front end callable.
 *
 * @author wlloyd, od
 */
@Name("Rusle2")
@Description("Cleaner version, FtM")
@VersionInfo("1.3")
@State(RELEASED)
@Path("m/rusle2/1.3")
@Polling(first = 5000, next = 1000)
// R2
@Resource(type = EXECUTABLE, file = "/bin/win-x86/RomeShell.exe", wine = true, id = ROME_EXE)
@Resource(type = FILE, file = "/bin/win-x86/RomeDLL.dll")

@Resource(type = EXECUTABLE, file = "/bin/win-x86/preparesoils.sh", id = PREP_SOILS)

@Resource(type = FILE, file = "/bin/win-x86/rusle2_report.rsh", id = REPORT_RSH)
@Resource(type = FILE, file = "/bin/win-x86/Rusle2_Report.json", id = REPORT_JSON)

// database
@Resource(type = JDBC, file = "${conservation_resources.db}", id = DB)

public class V1_31 extends ModelDataService {

    static final String ROME_EXE = "romeshell";
    static final String REPORT_RSH = "report_rsh";
    static final String REPORT_JSON = "report_json";
    static final String PREP_SOILS = "prep_soils";
    static final String DB = "csip.erosion.sqlsvr";

    static final boolean PRODUCTION_MODE = true;
    //
    static final String R2_TMP_FILENAME = "r2";
    static final String R2_TMP_FILEEXT = ".rsh";
    static final String IO_TIMING_FILENAME = "/tmp/io-timing";
    static final String IO_TIMING_FILEEXT = ".txt";

    /*
     * The R2 Run
     */
//    final R2Run r2run = new R2Run();
    // These are the allowable potential results returnable from the R2 service
    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;

    File stdout;

    File r2script = new File(getWorkspaceDir(), R2_TMP_FILENAME + R2_TMP_FILEEXT);


    @Override
    protected void preProcess() throws Exception {
        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);
        }

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

        createInputFile(r2script, getMetainfo(), getParamMap());
    }


    @Override
    protected void doProcess() throws Exception {
        stdout = execute(r2script);
    }


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

//      results.put(JSONUtils.data(KEY_SLOPE_DELIVERY, 3.0));
        String sout = FileUtils.readFileToString(stdout);
        for (String r : JSONUtils.getRequestedResults(getMetainfo())) {
            if ((errors > 0) && (r.equals(RES_SLOPE_DEGRAD))) {
                putResult(r, getResult(sout, r), R2_MISSING_XML_FILES_WARNING_MSG);
            } else {
                putResult(r, getResult(sout, r));
            }
        }
        if (errors > 0) {
            appendMetainfoWarning(R2_MISSING_XML_FILES_WARNING_MSG);
        }

        putResult(KEY_CLIMATES, climate);
        putResult(KEY_SOILS, soil);
        putResult(KEY_MANAGEMENTS, mgmt);
//      results.put(JSONUtils.data(KEY_ALT_R2DB, in_ALT_R2DB));
    }


    /**
     * Execute the r2 script.
     *
     * @param r2_rsh
     * @return
     * @throws IOException
     */
    private File execute(File r2_rsh) throws ServiceException, IOException {
        Executable exe = getResourceExe(ROME_EXE);
        exe.setArguments(r2_rsh.toString());
        int result = exe.exec();
        if (result != 0) {
            throw new ServiceException("ROME exit error :" + result);
        }
        return exe.stdout();
    }


    private boolean isUrlReachable(String targetUrl) throws IOException {
        String r2db = Config.getString("r2.db", "http://oms-db.engr.colostate.edu/r2");
        String testUrl = r2db + "/" + targetUrl;
        testUrl = XMLUtils.escapeXMLFileURL(testUrl);
        LOG.info("Testing URL=" + testUrl);
        URL url = new URL(testUrl);
        HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection();
        httpUrlConnection.setRequestMethod("GET");
        try {
            int responseCode = httpUrlConnection.getResponseCode();
            LOG.info("response code=" + responseCode);
            return responseCode == HttpURLConnection.HTTP_OK;
        } catch (UnknownHostException E) {
            return false;
        }
    }


    int prepareSoilsFile(String soilsHttpPtr, File workingDir, boolean bPyrome, String idx) throws IOException, ServiceException {
        Executable exe = getResourceExe(PREP_SOILS);
        exe.setArguments(soilsHttpPtr);
        int result = exe.exec();
        if (result != 0) {
            throw new ServiceException("Prep soils exit error :" + result);
        }
        return result;
    }


    void prepareFileJ(String httpPtr, File outputFile, String fileType, String fileDir, String basefilename, boolean prepareSoilForPyrome) throws IOException {
        BufferedReader br = null;
        BufferedWriter bw = null;
        String fn = (((basefilename != null) & (basefilename.length() > 0)) ? "\\" + basefilename + "1" : "\\aaa");
        try {
            // Generate shell script to prepare --fileType-- file for pyrome
            LOG.info("***********************************************************************************the " + fileType + " file name=" + outputFile.getName());
            String tmpFilename = outputFile.getName().substring(0, outputFile.getName().length() - 4) + ".tmp";
            LOG.info("***********************************************************************************the " + fileType + " tmp file name=" + tmpFilename);
            getFile(httpPtr, outputFile.getParent(), tmpFilename);
            FileOutputStream fos = new FileOutputStream(outputFile);
            bw = new BufferedWriter(new OutputStreamWriter(fos));
            File origFile = new File(outputFile.getParent() + "/" + tmpFilename);
            FileInputStream fis = new FileInputStream(origFile);
            br = new BufferedReader(new InputStreamReader(fis));
            if ((fileType.contentEquals("CLIMATE")) || (fileType.contentEquals("SOIL")) || (prepareSoilForPyrome)) {
                bw.write("<?xml version=\"1.0\"?>\n");
            }
            if (!fileType.contentEquals("SOIL")) {
                bw.write("<Obj>\n");
                if ((fileType != null) && (fileType.length() > 1)) {
                    bw.write("<Type>" + fileType + "</Type>\n");
                }
                // if an incrementing index is needed, replace "0" with counter variable
                bw.write("<Filename>" + fileDir + fn + "</Filename>\n");
            }
            int i = 0;
            String inputLine;
            while ((inputLine = br.readLine()) != null) {
                // skip the first line of the file, except for soil files which only have 1 line
                if ((i > 0) || (fileType.contentEquals("SOIL") && (i == 0) && (inputLine.startsWith("<Obj>")))) {
                    bw.write(inputLine + "\n");
                }
                i++;
            }
            fis.close();
        } catch (IOException ioe) {
            LOG.info("IO Exception while preparing flie=" + outputFile.getName() + "---" + ioe.toString());
        } finally {
            if (br != null) {
                br.close();
            }
            if (bw != null) {
                bw.close();
            }
        }
    }


    private void getFile(String url, String destDir, String filename) {
        FileOutputStream fos = null;
        String escapedUrl = XMLUtils.escapeURL(url);
        try {
            LOG.info("*************************************\n\n\n\nTRYING TO GET FILE=" + url + "\n");
            LOG.info("Where the URI is =");
            LOG.info(escapedUrl + "\n\n\n\n\n*************************************************************");
            HttpClient client = new DefaultHttpClient();
            HttpGet httpget = new HttpGet(escapedUrl);
            HttpResponse response = client.execute((HttpUriRequest) httpget);

            byte[] soilData = IOUtils.toByteArray(response.getEntity().getContent());
            fos = new FileOutputStream(new File(destDir + "/" + filename));
            fos.write(soilData);
            fos.close();
        } catch (IOException ie) {
            LOG.log(Level.SEVERE, "ERROR GETTING SOILS IFC FILE!:" + ie.toString());
            throw new RuntimeException(ie);
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (Exception fe) {
                }
            }
        }
    }


    String getResult(String stdout, String key) {
        String sPattern = "RomeFileGetAttrValue " + key;

        //LOG.info("seeking='" + sPattern + "'");
        // Check if attr is available via the GetAttrValue cmd and return if so
        if (stdout.contains(sPattern)) {
            int start = stdout.indexOf(sPattern) + sPattern.length() + 2;
            int end = stdout.toString().indexOf('\r', start);
            //LOG.info("returning='" + stdout.substring(start, end).trim() + "'");
            return stdout.substring(start, end).trim();
        }

        // Check if attr is available via the TestAttrValue cmd and return if so
        sPattern = "RomeFileTestAttrValue " + key;
        //LOG.info("seeking='" + sPattern + "'");        
        if (stdout.contains(sPattern)) {
            int start = stdout.indexOf(sPattern) + sPattern.length() + 2;
            int end = stdout.toString().indexOf('\r', start);
            //LOG.info("returning='" + stdout.substring(start, end).trim() + "'");            
            return stdout.substring(start, end).trim();
        }

        //String key2 = "\"#RD:MAN_PTR:#RD:MAN_IRRIG_SUB_OBJ_PTR:" + key.substring(1);
        sPattern = ":" + Services.removeFirstLastChar(key) + "\"";
        //LOG.info("seeking='" +  sPattern + "'");        
        if (stdout.contains(sPattern)) {
            int start = stdout.indexOf(sPattern) + sPattern.length() + 2;
            int end = stdout.toString().indexOf('\r', start);
            String output = stdout.substring(start, end).trim();
            if ((output == null) || (output.length() <= 0)) {
                output = "null";
            }
            //LOG.info("returning='" + output + "'");            
            return output;
        }

        // If attr is not available return null
        LOG.info("returning='null'");
        return "null";
    }


    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, "");
        String soilPtr = JSONUtils.getStringParam(param, KEY_SOILS, "");
        String managementFormalName[] = new String[]{};

        String contourSystem = JSONUtils.getStringParam(param, KEY_CONTOUR_SYSTEM_PTR, "");
        String stripBarrierSystem = JSONUtils.getStringParam(param, KEY_STRIP_BARRIER_SYSTEM_PTR, "");
        String hydElemSystem = JSONUtils.getStringParam(param, KEY_HYD_ELEM_SYSTEM_PTR, "");

//        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 = new SqlGIS(getResourceJDBC(DB));

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

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

        // to do
        // use only the first soil for now - later we need to use all of them
        String 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);
            }
        }
        cokey = lst.get(0);  // first soil only for now
        GIS_DB.FileQryResult so = db.findSoilsByCokey(cokey, longitude);
        if (so == null) {
            LOG.warning("No soil for lat=" + latitude + "\nfor long=" + longitude + "\n");
            appendMetainfoWarning(R2_NO_SOIL_FOR_PROVIDED_COKEY);
            soilPtr = "";
        } else {
            soilPtr = so.file_path + "\\" + so.file_name;
        }

        db.close();

        FileOutputStream fos = new FileOutputStream(file);
        // to enable/disable romeconsole logging
        if (!PRODUCTION_MODE) {
            fos.write("Log ON\n".getBytes());
        }
        fos.write("JSON ON\n".getBytes());
        fos.write("RomeInit\n".getBytes());

        if (!PRODUCTION_MODE) {
            String timingFilename = IO_TIMING_FILENAME + getFilenumber(file.getName()) + IO_TIMING_FILEEXT;
            fos.write(("RomeSetTitle \"App.Files.IoLogging\" \"" + timingFilename + "\"\n").getBytes());
        }

        String r2db = Config.getString("r2.db", "http://oms-db.engr.colostate.edu/r2");
        if (altR2db == null) {
            fos.write(("DatabaseOpen \"" + r2db + "\"\n").getBytes());
        } else {
            String altr2db = r2db.substring(0, r2db.lastIndexOf("/")) + "/model-data/" + altR2db;
            fos.write(("DatabaseOpen \"" + altr2db + "\"\n").getBytes());
        }

        fos.write("FilesOpen profiles\\#ENTRY_MODEL PRIVATE\n".getBytes());
        fos.write("Activate profiles\\model\n".getBytes());

        // OLD VERSION, WHERE WE GOT CLIMATE DIRECTLY FROM NGINX AND DIDN'T MODIFY IT
        // fos.write(("RomeFileSetAttrValue CLIMATE_PTR \"" + climatePtr + "\"\n").getBytes());
        // NEW VERSION, Where the climate file must be modified to work
        fos.write(("FilesOpen \"#XML:" + new File(getWorkspaceDir(), "cli_file" + 0 + ".xml" + "\"\n")).getBytes());
        fos.write(("RomeFileSetAttrValue CLIMATE_PTR \"climates\\aaa\"\n").getBytes());

        // New version, where we have to process the nginx file so R2 reads it
        // climate stub if needed
        //fos.write("RomeFileSetAttrValue CLIMATE_PTR \"climates\\USA\\Idaho\\Power County\\ID_Power_R_11\"\n".getBytes());
        // soil stub if needed
        //fos.write("RomeFileSetAttrValue SOIL_PTR \"soils\\Power County Area, Idaho\\40 Neeley silt loam, 2 to 4 percent slopes\\Neeley  silt loam 90%\"\n".getBytes());
//        fos.write(("RomeFileSetAttrValue MAN_BASE_PTR \"" + mgmtPtr + "\"\n").getBytes());
        // multiple managements
// to do
// Don't worry about multiple mgmts for now
//        for (int i = 0; i < managements.length(); i++) {
//            //reference the lmod file(s)
//            fos.write(("RomeFileSetAttrValue MAN_PTR \"" + new File(getWorkspace(), "lmod_file" + i + ".xml" + "\"\n")).getBytes());
//        }
        if ((managements != null) && (managements.length() >= 1)) {
            fos.write(("FilesOpen \"#XML:" + new File(getWorkspaceDir(), "lmod_file" + 0 + ".xml" + "\"\n")).getBytes());
            // fos.write(("Activate \"" + managementFormalName[0] + "\"\n").getBytes());
            fos.write(("RomeFileSetAttrValue MAN_BASE_PTR \"" + managementFormalName[0] + "\"\n").getBytes());
            mgmt = managementFormalName[0];
        }

        // to do 
        // commented out - using default for now
        fos.write(("FilesOpen \"#XML:" + new File(getWorkspaceDir(), "soils_file0.xml" + "\"\n")).getBytes());
        String soilHttpPtr = r2db + "/" + soilPtr.replace("\\", "/") + ".xml";
        prepareSoilsFile(soilHttpPtr, new File(getWorkspaceDir(), "soils_file0.xml"), false, "0");
        //r2run.prepareFileJ(soilHttpPtr, new File(getWorkspaceDir(), "soils_file0.xml"), "SOILS", "", "", false);

        String cliHttpPtr = r2db + "/" + climatePtr.replace("\\", "/") + ".xml";
        prepareFileJ(cliHttpPtr, new File(getWorkspaceDir(), "cli_file0.xml"), "CLIMATE", "climates", "", false);

        fos.write(("RomeFileSetAttrValue SOIL_PTR \"" + soilPtr + ".xml\"\n").getBytes());
        fos.write(("RomeFileSetAttrValue SLOPE_HORIZ \"" + length + "\"\n").getBytes());
        fos.write(("RomeFileSetAttrValue SLOPE_STEEP \"" + steepness + "\"\n").getBytes());

        if ((contourSystem != null) && (contourSystem.length() > 1)) {
            fos.write(("RomeFileSetAttrValue CONTOUR_SYSTEM_PTR \"" + contourSystem + "\"\n").getBytes());
        }

        if ((stripBarrierSystem != null) && (stripBarrierSystem.length() > 1)) {
            fos.write(("RomeFileSetAttrValue STRIP_BARRIER_SYSTEM_PTR \"" + stripBarrierSystem + "\"\n").getBytes());
        }

        if ((hydElemSystem != null) && (hydElemSystem.length() > 1)) {
            fos.write(("RomeFileSetAttrValue HYD_ELEM_SYSTEM_PTR \"" + hydElemSystem + "\"\n").getBytes());
        }

        if (JSONUtils.checkKeyExistsB(param, KEY_SIMPLE_ROCK_COVER)) {
            fos.write(("RomeFileSetAttrValue SIMPLE_ROCK_COVER \"" + simpleRockCoverPercent + "\"\n").getBytes());
        }

        fos.write("RomeEngineRun\n".getBytes());
        for (String r : JSONUtils.getRequestedResults(metainfo)) {
            fos.write(("RomeFileGetAttrValue " + r + "\n").getBytes());
        }

//        fos.write(("RomeFileGetAttrValue CONTOUR_SYSTEM_PTR\n").getBytes());
//        fos.write(("RomeFileGetAttrValue STRIP_BARRIER_SYSTEM_PTR\n").getBytes());
//        fos.write(("RomeFileGetAttrValue HYD_ELEMENT_SYSTEM_PTR\n").getBytes());
        // optionally only include this line when reporting is requested to save service execution time
        fos.write("READ \"rusle2_report.rsh\"\n".getBytes());
        fos.write("RomeExit\n".getBytes());
        fos.write("Exit\n".getBytes());
        fos.close();

        // Unpack the report rsh file in the work space dir 
        FileUtils.copyFileToDirectory(getResourceFile(REPORT_RSH), getWorkspaceDir());

        climate = climatePtr;
        soil = soilPtr;
//        mgmt = mgmtPtr;

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


    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 sReportJSON = FileUtils.readFileToString(getResourceFile(REPORT_JSON));
        JSONArray reportItemsFromTemplate = new JSONArray(sReportJSON);

        String sout = FileUtils.readFileToString(stdout);

        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);
            String value = getResult(sout, "\"" + itemName + "\"");
            //LOG.info("the value='" + value + "'");
            if ((value != null) && (value.equals("null"))) {
                putReport(itemName, value, 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 {
                    putReport(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)
                putReportMetaInfo(itemName,REPORT_DIM,new JSONArray(dimension));
        }
    }


    // 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 {
        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);
            putReport(itemName, Services.removeFirstLastChar(newString), desc, units);
        }
        if (type.equals("INTEGER") && (value != null) && (!value.equals("null")) && (!value.equals("\"\""))) {
            putReport(itemName, new Double(value).intValue(), desc, units);
        }
        if (type.equals("REAL") && (value != null)) {
            if ((!value.equals("null")) && (!value.equals("\"\""))) {
                putReport(itemName, Double.parseDouble(value), desc, units);
            }
            if (value.equals("\"\"")) {
                putReport(itemName, new Double(0), desc, units);
            }
        }
        if (type.equals("")) {
            putReport(itemName, value, desc, units);
        }
    }
}