V2_1.java [src/java/m/rusle2] Revision:   Date:
/*
 * $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.utils.Client;
import csip.Config;
import csip.ModelDataService;
import csip.api.server.ServiceException;
import static csip.Utils.removeFirstLastChar;
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 csip.utils.JSONUtils;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;
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 lmod2rusle2.Rusle2Translator;
import static m.rusle2.V2_1.*;
import static m.rusle2.V3_0.ROMEDLL;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import static util.Constants.*;

/**
 * REST Web Service. Front end callable.
 *
 * @author wlloyd, od
 */
@Name("Rusle2")
@Description("IET / pyrome version of R2; RomeDLL 2.5.2.11; references NRCS Soil Data Mart")
@VersionInfo("2.1")
@State(RELEASED)
@Path("m/rusle2/2.1")
@Polling(first = 1000, next = 1000)
@Resource(type = FILE, file = "/bin/win-x86/2.5.2.11/RomeDLL.dll", id = ROMEDLL)
@Resource(type = FILE, file = "/bin/win-x86/2.5.2.11/pyrome.py", id = PYROMESRC)
@Resource(type = FILE, file = "/bin/win-x86/2.5.2.11/_pyrome.pyd", id = PYROME)
@Resource(type = ARCHIVE, file = "/bin/win-x86/Python34.zip")
@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)
@Deprecated
public class V2_1 extends ModelDataService {

  static final String R2_TMP_FILENAME = "rusle2csip.py";
  static final String ROMEDLL = "RomeDLL.dll";
  static final String PYROMESRC = "pyrome.py";
  static final String PYROME = "_pyrome.pyd";
  static final String PYTHON = "python.exe";
  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
   */
  R2Run r2run = new R2Run();
  static final List<String> POT_RESULTS = 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;

  String r2db = Config.getString("r2.db", "http://oms-db.engr.colostate.edu/r2");

  @Override
  protected void preProcess() throws Exception {
    // check for requested output.
    r2run.setLogger(LOG);
    try {
      if (LOG.isLoggable(Level.INFO)) {
        LOG.info("\n\nMETAINFO:");
        LOG.info("\n" + metainfo().toString());
        LOG.info("\n\n\n");
      }
      V4_0.checkValidResultRequest(metainfo(), POT_RESULTS);
    } 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<>();
      params.add(RES_SLOPE_DELIVERY);
      params.add(RES_SLOPE_T_VALUE);
      params.add(RES_SLOPE_DEGRAD);

      // check if these are being set
      if (parameter().has(KEY_CONTOUR_SYSTEM_PTR)) {
        params.add("CONTOUR_SYSTEM_PTR");
      }
      if (parameter().has(KEY_STRIP_BARRIER_SYSTEM_PTR)) {
        params.add("STRIP_BARRIER_SYSTEM_PTR");
      }
      if (parameter().has(KEY_HYD_ELEM_SYSTEM_PTR)) {
        params.add("HYD_ELEM_SYSTEM_PTR");
      }
//            getMetainfo().put( KEY_REQUEST_RESULTS, params );
    }

    // check if sufficient input is there.
    parameter().require(KEY_SOILS, KEY_LENGTH, KEY_STEEPNESS, KEY_MGMTS);

    if (!r2run.isUrlReachable("")) {
      throw new ServiceException("R2 file server unreachable at: " + r2db);
    }

    File r2script = workspace().getFile(R2_TMP_FILENAME);

    String[] reqResults = metainfo().getStringArray(KEY_REQUEST_RESULTS);
    createInputFile(r2script, reqResults, getParamMap());
  }

  @Override
  protected void doProcess() throws Exception {
    r2run.executePyrome(workspace().getFile(R2_TMP_FILENAME), resources().getExe(PYTHON), getSUID());
  }

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

    String[] reqResults = metainfo().getStringArray(KEY_REQUEST_RESULTS);
    for (String r : reqResults) {
      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 (parameter().has(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);
        if (LOG.isLoggable(Level.INFO)) {
          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 (parameter().has(KEY_DIVERSIONS)) {
          results().put(KEY_DIVERSIONS, r2run.getResultPyromeArray("HYD_ELEM_SYS", true, true, true));
        }
        if (parameter().has(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)));
    }
  }

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

    double steepness = parameter().getDouble(KEY_STEEPNESS, 0.0);
    double length = parameter().getDouble(KEY_LENGTH, 0.0);
    boolean resolveLoc = parameter().getBoolean(KEY_RESOLVE_LOCATION, false);
    double latitude = parameter().getDouble(KEY_LATITUDE, 0.0);
    double longitude = parameter().getDouble(KEY_LONGITUDE, 0.0);
    double simpleRockCoverPercent = 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);
      }
    }

    JSONArray aSoils = JSONUtils.getJSONArrayParam(param, KEY_SOILS);
    if (LOG.isLoggable(Level.INFO)) {
      for (int i = 0; i < aSoils.length(); i++) {
        LOG.info("soil [" + i + "]=" + aSoils.getInt(i));
      }
    }

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

    // Get the Contour System if not default
    if (parameter().has(KEY_CONTOUR_SYSTEM_PTR)) {
      contourSystem = parameter().getString(KEY_CONTOUR_SYSTEM_PTR, "");
    }

    // Get the Strip Barrier System
    if (parameter().has(KEY_STRIP_BARRIER_SYSTEM_PTR)) {
      stripBarrierSystem = parameter().getString(KEY_STRIP_BARRIER_SYSTEM_PTR, "");
    }

    // Get the Hydraylic Element System Pointer
    if (parameter().has(KEY_HYD_ELEM_SYSTEM_PTR)) {
      hydElemSystem = parameter().getString(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();

    if (parameter().has(KEY_TOPO_LENGTH)) {
      aTopoLength = JSONUtils.getJSONArrayParam(param, KEY_TOPO_LENGTH);
      if (LOG.isLoggable(Level.INFO)) {
        for (int i = 0; i < aTopoLength.length(); i++) {
          LOG.info("Topo Length [" + i + "]=" + aTopoLength.getDouble(i));
        }
      }
    }

    if (parameter().has(KEY_TOPO_STEEPNESS)) {
      aTopoSteepness = JSONUtils.getJSONArrayParam(param, KEY_TOPO_STEEPNESS);
      if (LOG.isLoggable(Level.INFO)) {
        for (int i = 0; i < aTopoSteepness.length(); i++) {
          LOG.info("Topo Steepness [" + i + "]=" + aTopoSteepness.getDouble(i));
        }
      }
    }

    if (parameter().has(KEY_SOIL_INDEX)) {
      aSoilIdx = JSONUtils.getJSONArrayParam(param, KEY_SOIL_INDEX);
      if (LOG.isLoggable(Level.INFO)) {
        for (int i = 0; i < aSoilIdx.length(); i++) {
          LOG.info("Soil Index [" + i + "]=" + aSoilIdx.getInt(i));
        }
      }
    }

    if (parameter().has(KEY_MAN_INDEX)) {
      aManIdx = JSONUtils.getJSONArrayParam(param, KEY_MAN_INDEX);
      if (LOG.isLoggable(Level.INFO)) {
        for (int i = 0; i < aManIdx.length(); i++) {
          LOG.info("Man Index [" + i + "]=" + aManIdx.getInt(i));
        }
      }
    }

    if (parameter().has(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 (parameter().has(KEY_TOPO_LENGTH)) {
      if (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 (parameter().has(KEY_MAN_INDEX)) {
      if (aManLength.length() != aManIdx.length()) {
        throw new ServiceException("RUSLE2 SEGMENT RUN ERROR! SEGMENT ARRAYS FOR MGMT LENGTH AND MGMT INDEX MUST BE OF EQUAL SIZE!");
      }
    }

    // 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());
    String[] managementFormalName = new String[managements.length()];

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

      JSONObject lmod = (JSONObject) managements.get(i);
      if (LOG.isLoggable(Level.INFO)) {
        LOG.info(lmod.toString());
      }

      Rusle2Translator translator = new Rusle2Translator();
      translator.readJsonString(lmod.toString());

      boolean success = translator.Translate();
      LOG.info("translation successful =" + success);

      Document r2_xml = translator.getDocument();

      if (LOG.isLoggable(Level.INFO)) {
        LOG.info("R2 XML FILE from translator:\n\n" + translator.getRusle2Xml());
      }

      if ((r2_xml != null) && (r2_xml.getElementsByTagName("Filename") != null)) {
        NodeList nl = r2_xml.getElementsByTagName("Filename");
        for (int ii = 0; ii < nl.getLength(); ii++) {
          if (LOG.isLoggable(Level.INFO)) {
            LOG.info("filename node=" + nl.item(ii).getTextContent());
          }
          managementFormalName[i] = nl.item(ii).getTextContent();
        }
      }

      translator.writeRusle2Xml(workspace().getDir().toString(), "lmod_file" + i + ".xml");
      operations = translator.getOperationFiles();
      vegetations = translator.getVegetationFiles();
      residues = translator.getResidueFiles();

      if (LOG.isLoggable(Level.INFO)) {
        operations.forEach((operation) -> {
          LOG.info("operation=" + operation);
        });
        vegetations.forEach((vege) -> {
          LOG.info("vegetation=" + vege);
        });
        residues.forEach((residue) -> {
          LOG.info("residue=" + residue);
        });
      }
    }

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

    // Sub-service calls.
    String climatePtr = getClimateFilePath(latitude, longitude);
    String[] soilPtr = getSoilFiles(aSoils);

    PrintWriter pw = new PrintWriter(file);
    pw.append("import sys\n"
        // could rewrite this line based on the OS, but python is interpretting it ok on windows
        + "sys.path.append('" + resources().getFile(PYROMESRC).getParent().replace('\\', '/') + "')\n"
        + "from pyrome import *\n"
        + "\n"
        + "def linearTest(save = False, openFlags = RX_FILESOPEN_TEMP):\n"
        + "    romeDLL = RomeInit('')\n"
        + "    files = RomeGetFiles(romeDLL)\n"
        + "    engine = RomeGetEngine(romeDLL)\n"
        + "    RomeEngineSetAutorun(engine,RX_FALSE)\n"
        + "    #Inputs\n");

    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" : ",";
      }
      pw.append(text);
      text = "    lengths=[";
      for (int i = 0; i < aTopoLength.length(); i++) {
        text += "'" + aTopoLength.getInt(i) + "'";
        text += (i == aTopoLength.length() - 1) ? "]\n" : ",";
      }
      pw.append(text);
      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" : ",";
        }
        pw.append(text);
      }
      text = "    manIndex=[";
      for (int i = 0; i < aManIdx.length(); i++) {
        text += aManIdx.getInt(i) + "";
        text += (i == aManIdx.length() - 1) ? "]\n" : ",";
      }
      pw.append(text);
    } else {
      pw.append("    slopes=['" + steepness + "']\n"
          + "    lengths=['" + length + "']\n"
          + "    soilIndex=[0]\n"
          + "    manIndex=[0]\n");
    }

    pw.append("    results = list()\n"
        + "    #Run a simple profile\n"
        + "    profile = RomeFilesOpen(files,'profiles\\\\csippyrome',openFlags)\n");

    // Open all of the mgmt files...
    for (int i = 0; i < managements.length(); i++) {
      pw.append("    mgmt = RomeFilesOpen(files, '#XML:lmod_file" + i + ".xml',0)\n");
    }
    pw.append("    cli = RomeFilesOpen(files, '#XML:cli_file0.xml',0)\n");
    for (int i = 0; i < aSoils.length(); i++) {
      pw.append("    soil" + i + " = RomeFilesOpen(files, '#XML:soils_file" + i + ".xml',0)\n");
    }
    pw.append("    # SET SLOPE\n"
        + "    RomeFileSetAttrValue(profile, 'SLOPE_HORIZ', '" + length + "', 0)\n"
        + "    RomeFileSetAttrValue(profile, 'SLOPE_STEEP', '" + steepness + "', 0)\n"
        + "    # SET CLIMATE_PTR\n"
        + "    RomeFileSetAttrValue(profile, 'CLIMATE_PTR','climates\\\\aaa',0)\n"
        + "    print('CLIMATE_PTR=%s' % RomeFileGetAttrValue(profile, 'CLIMATE_PTR', 0))\n");

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

    // Presently we do not support multiple soils
    pw.append("    # SET SOIL LAYER\n");
    if (aSoils.length() > 0) {
      pw.append("    RomeFileSetAttrSize(profile, 'SOIL_LAYER', " + aSoils.length() + ")\n"
          + "    RomeFileSetAttrValue(profile, 'SOIL_HORIZ', '" + length + "', 0)\n"
          + "    RomeFileSetAttrValue(profile, 'SOIL_PTR', '" + StringEscapeUtils.escapeJava(soilPtr[0]) + "', " + 0 + ")\n");
    }

    // Must be after set soils or the soils code resets it...sometimes
    if (parameter().has(KEY_SIMPLE_ROCK_COVER)) {
      pw.append("    RomeFileSetAttrValue(profile, 'SIMPLE_ROCK_COVER', '" + simpleRockCoverPercent + "' ,0)\n");
    }
    pw.append("    # SET MAN LAYER\n");
    if (aManIdx.length() > 0) {
      pw.append("    RomeFileSetAttrSize(profile, 'MAN_LAYER', " + aManIdx.length() + ")\n");
      for (int i = 0; i < aManIdx.length(); i++) {
        pw.append("    RomeFileSetAttrValue(profile, 'MAN_HORIZ', '" + aManLength.getString(i) + "', " + i + ")\n");
        if (LOG.isLoggable(Level.INFO)) {
//                    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)]);
        }
        pw.append("    RomeFileSetAttrValue(profile, 'MAN_PTR', '" + R2Run.escapeJavaNoFwdSlash(managementFormalName[aManIdx.getInt(i)]) + "', " + i + ")\n");
      }
    } else {
      // IF no max_idx array provided, defaulting to single mgmt
      pw.append("    RomeFileSetAttrSize(profile, 'MAN_LAYER', 1)\n"
          + "    RomeFileSetAttrValue(profile, 'MAN_HORIZ', '" + length + "', 0)\n");

      if (LOG.isLoggable(Level.INFO)) {
//                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]);
      }
      pw.append("    RomeFileSetAttrValue(profile, 'MAN_PTR', '" + R2Run.escapeJavaNoFwdSlash(managementFormalName[0]) + "', 0)\n");
    }
    pw.append("    print('SOIL_PTR=%s' % RomeFileGetAttrValue(profile, 'SOIL_PTR', 0))\n");

    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
      pw.append("    RomeFileSetAttrValue(profile, 'CONTOUR_SYSTEM_PTR', '" + StringEscapeUtils.escapeJava(contourSystem) + "', 0)\n");
    }

    // 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
      pw.append("    stripbarr = RomeFilesOpen(files, '#XML:stripbarr_file0.xml',0)\n"
          + "    RomeFileSetAttrValue(profile, 'STRIP_BARRIER_SYSTEM_PTR', 'strip-barrier-systems\\\\aaa', 0)\n");
    }

    // 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
      pw.append("    hydelem = RomeFilesOpen(files, '#XML:hydelemflowpath_file.xml',0)\n");
      int numFlowPaths = r2run.determineNumberOfFlowPaths(hydElemSystem);
      pw.append("    RomeFileSetAttrSize(profile, 'NUM_FLOW_PATHS', " + numFlowPaths + ")\n");
      double offsets[] = r2run.determineFlowPathDistribution(hydElemSystem);
      for (int i = 0; i < numFlowPaths; i++) {
        pw.append("    RomeFileSetAttrValue(profile, 'FLOW_PATH_HORIZ', '" + length * offsets[i] + "', " + i + ")\n");
        if (i < (numFlowPaths - 1)) {
          pw.append("    RomeFileSetAttrValue(profile, 'HYD_ELEM_FLOW_PATH_PTR', 'hydraulic-element-flow-paths\\hydelemflowpath1', " + i + ")\n");
        } else {
          // last flow path is always the default
          pw.append("    RomeFileSetAttrValue(profile, 'HYD_ELEM_FLOW_PATH_PTR', 'hydraulic-element-flow-paths\\default', " + i + ")\n");
        }
      }
    }

    pw.append("    RomeFileSave(profile)\n"
        + "    RomeEngineRun(engine)\n");

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

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

    pw.append("    numflowpaths = RomeFileGetAttrSize(profile, 'NUM_FLOW_PATHS')\n"
        + "    print('------------------------------------------------------------------------------')\n"
        + "    print('NUMBER OF FLOWPATHS=%d' % numflowpaths)\n"
        + "    for xx in range (numflowpaths):\n"
        + "        print('FLOW_PATH_HORIZ:%d=%s' % (xx, RomeFileGetAttrValue(profile, 'FLOW_PATH_HORIZ', xx)))\n"
        + "        print('HYD_ELEM_FLOW_PATH_PTR:%d=%s' % (xx, RomeFileGetAttrValue(profile, 'HYD_ELEM_FLOW_PATH_PTR', xx)))\n"
        + "    numsegs = RomeFileGetAttrSize(profile, 'SEGMENT')\n"
        + "    print('NUMBER OF SEGMENTS=%d' % numsegs)\n"
        + "    for x in range (numsegs):\n"
        + "        print('------------------------------------------------------------------------------')\n"
        + "        print('SEGMENT:%d=%s' % (x, RomeFileGetAttrValue(profile, 'SEGMENT', x)))\n"
        + "        print('SEG_HORIZ:%d=%s' % (x, RomeFileGetAttrValue(profile, 'SEG_HORIZ', x)))\n"
        + "        print('SEG_STEEP:%d=%s' % (x,RomeFileGetAttrValue(profile, 'SEG_STEEP', x)))\n"
        + "        print('SEG_MAN:%d=%s' % (x, RomeFileGetAttrValue(profile, 'MAN_PTR', x)))\n"
        + "        print('SEG_SOIL:%d=%s' % (x, RomeFileGetAttrValue(profile, 'SOIL_PTR', x)))\n"
        + "        results.append(RomeFileGetAttrValue(profile, 'SEG_SOIL_LOSS', x))\n"
        + "        print('SEG_SOIL_LOSS:%d=%s' % (x, RomeFileGetAttrValue(profile, 'SEG_SOIL_LOSS', x)))\n"
        + "        print('SEG_SOIL_LAYER %d=%s' % (x, RomeFileGetAttrValue(profile, 'SEG_SOIL_LAYER', x)))\n"
        + "        print('SEG_MAN_LAYER %d=%s' % (x, RomeFileGetAttrValue(profile, 'SEG_MAN_LAYER', x)))\n"
        + "        print('HYD_ELEM_SYS:%d=%s' % (x, RomeFileGetAttrValue(profile, 'HYD_ELEM_SYSTEM_PTR', x)))\n"
        + "        print('STRIP_BARRIER_SYS:%d=%s' % (x, RomeFileGetAttrValue(profile, 'STRIP_BARRIER_SYSTEM_PTR', x)))\n"
        + "        print('CONTOUR_SYS:%d=%s' % (x, RomeFileGetAttrValue(profile, 'CONTOUR_SYSTEM_PTR', x)))\n"
        + "    print('------------------------------------------------------------------------------')\n");

    pw.append("    numflowpaths = RomeFileGetAttrSize(profile, 'NUM_FLOW_PATHS')\n"
        + "    print('------------------------------------------------------------------------------')\n"
        + "    print('NUMBER OF FLOWPATHS=%d' % numflowpaths)\n"
        + "    for xx in range (numflowpaths):\n"
        + "        print('FLOW_PATH_HORIZ:%d=%s' % (xx, RomeFileGetAttrValue(profile, 'FLOW_PATH_HORIZ', xx)))\n"
        + "        print('HYD_ELEM_FLOW_PATH_PTR:%d=%s' % (xx, RomeFileGetAttrValue(profile, 'HYD_ELEM_FLOW_PATH_PTR', xx)))\n"
        + "    numsegs = RomeFileGetAttrSize(profile, 'SEGMENT')\n"
        + "    print('NUMBER OF SEGMENTS=%d' % numsegs)\n"
        + "    for x in range (numsegs):\n"
        + "        print('------------------------------------------------------------------------------')\n"
        + "        print('SEGMENT:%d=%s' % (x, RomeFileGetAttrValue(profile, 'SEGMENT', x)))\n"
        + "        print('SEG_HORIZ:%d=%s' % (x, RomeFileGetAttrValue(profile, 'SEG_HORIZ', x)))\n"
        + "        print('SEG_STEEP:%d=%s' % (x,RomeFileGetAttrValue(profile, 'SEG_STEEP', x)))\n"
        + "        print('SEG_MAN:%d=%s' % (x, RomeFileGetAttrValue(profile, 'MAN_PTR', x)))\n"
        + "        print('SEG_SOIL:%d=%s' % (x, RomeFileGetAttrValue(profile, 'SOIL_PTR', x)))\n"
        + "        results.append(RomeFileGetAttrValue(profile, 'SEG_SOIL_LOSS', x))\n"
        + "        print('SEG_SOIL_LOSS:%d=%s' % (x, RomeFileGetAttrValue(profile, 'SEG_SOIL_LOSS', x)))\n"
        + "        print('SEG_SOIL_LAYER %d=%s' % (x, RomeFileGetAttrValue(profile, 'SEG_SOIL_LAYER', x)))\n"
        + "        print('SEG_MAN_LAYER %d=%s' % (x, RomeFileGetAttrValue(profile, 'SEG_MAN_LAYER', x)))\n"
        + "        print('HYD_ELEM_SYS:%d=%s' % (x, RomeFileGetAttrValue(profile, 'HYD_ELEM_SYSTEM_PTR', x)))\n"
        + "        print('STRIP_BARRIER_SYS:%d=%s' % (x, RomeFileGetAttrValue(profile, 'STRIP_BARRIER_SYSTEM_PTR', x)))\n"
        + "        print('CONTOUR_SYS:%d=%s' % (x, RomeFileGetAttrValue(profile, 'CONTOUR_SYSTEM_PTR', x)))\n"
        + "    print('------------------------------------------------------------------------------')\n"
        + "    numsegs = RomeFileGetAttrSize(profile, 'SOIL_LAYER')\n"
        + "    print('NUMBER OF SOIL SEGMENTS=%d' % numsegs)\n"
        + "    for x in range (numsegs):\n"
        + "        print('------------------------------------------------------------------------------')\n"
        + "        print('SOIL_SEGMENT:%d=%s' % (x, RomeFileGetAttrValue(profile, 'SOIL_LAYER', x)))\n"
        + "        print('SOIL_HORIZ:%d=%s' % (x, RomeFileGetAttrValue(profile, 'SOIL_HORIZ', x)))\n"
        + "        print('SOIL_PTR:%d=%s' % (x, RomeFileGetAttrValue(profile, 'SOIL_PTR', x)))\n"
        + "    print('------------------------------------------------------------------------------')\n"
        + "    numsegs = RomeFileGetAttrSize(profile, 'MAN_LAYER')\n"
        + "    print('NUMBER OF MAN SEGMENTS=%d' % numsegs)\n"
        + "    for x in range (numsegs):\n"
        + "        print('------------------------------------------------------------------------------')\n"
        + "        print('MAN_SEGMENT:%d=%s' % (x, RomeFileGetAttrValue(profile, 'MAN_LAYER', x)))\n"
        + "        print('MAN_HORIZ:%d=%s' % (x, RomeFileGetAttrValue(profile, 'MAN_HORIZ', x)))\n"
        + "        print('MAN_PTR:%d=%s' % (x, RomeFileGetAttrValue(profile, 'MAN_PTR', x)))\n"
        + "    print('------------------------------------------------------------------------------')\n"
        + "    numsegs = RomeFileGetAttrSize(profile, 'TOPO_LAYER')\n"
        + "    print('NUMBER OF TOPO SEGMENTS=%d' % numsegs)\n"
        + "    for x in range (numsegs):\n"
        + "        print('------------------------------------------------------------------------------')\n"
        + "        print('TOPO_SEGMENT:%d=%s' % (x, RomeFileGetAttrValue(profile, 'TOPO_LAYER', x)))\n"
        + "        print('TOPO_HORIZ:%d=%s' % (x, RomeFileGetAttrValue(profile, 'TOPO_HORIZ', x)))\n"
        + "        print('TOPO_HORIZ_COMPOSITE:%d=%s' % (x, RomeFileGetAttrValue(profile, 'TOPO_HORIZ_COMPOSITE', x)))\n"
        + "        print('TOPO_STEEP:%d=%s' % (x, RomeFileGetAttrValue(profile, 'TOPO_STEEP', x)))\n"
        + "        print('TOPO_STEEP_COMPOSITE:%d=%s' % (x, RomeFileGetAttrValue(profile, 'TOPO_STEEP_COMPOSITE', x)))\n"
        + "    print('------------------------------------------------------------------------------')\n"
        + "    exec(open(\"" + REPORT_PY_FILENAME + "\").read())\n"
        + "    RomeFileClose(profile)\n"
        + "    return results\n\n"
        + "if __name__ == \"__main__\":\n"
        + "    #inputs\n"
        + "    save = False\n"
        + "    #Run simulation\n"
        + "    romeDLL = RomeInit('pyrome /DirRoot=" + resources().getFile(ROMEDLL).getParent().replace('\\', '/') + "/')\n"
        + "    database = RomeGetDatabase(romeDLL)\n");

    // prints all outputs in single array
    // Specify the nginx server
    if (!parameter().has(KEY_ALT_R2DB)) {
      pw.append("    RomeDatabaseOpen(database,'" + r2db + "')\n");
    } else {
      String altr2db = r2db.substring(0, r2db.lastIndexOf("/")) + "/model-data/" + parameter().getString(KEY_ALT_R2DB);
      pw.append("    RomeDatabaseOpen(database,'" + altr2db + "')\n");
    }

    pw.append("    results = linearTest(save)\n"
        + "    RomeDatabaseClose(database)\n"
        + "    RomeExit(romeDLL)\n"
        + "    exit()\n"
    );
    pw.close();

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

    // prepare climate file
    r2run.prepareFileJ(climatePtr, workspace().getFile("cli_file0.xml"), "CLIMATE", "climates", "", true);

    // Unpack the report rsh file in the work space dir
    FileUtils.copyFileToDirectory(resources().getFile(REPORT_PY_FILENAME), workspace().getDir());

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

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

    soilsRequest.put(KEY_METAINFO, meta);
    soilsRequest.put(KEY_PARAMETER, paramObj);
    paramObj.put(cokeyObj);

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

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

        soilPtr[i] = getSoilFilePath(workspace().getFile("soils_file" + i + ".xml")).replace("/", "\\");
        if (LOG.isLoggable(Level.INFO)) {
          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 {
    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
    Document document = documentBuilder.parse(soilFile);
    String 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();
    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);

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

  @Override
  protected void doReport() throws Exception {
    String sReportJSON = FileUtils.readFileToString(resources().getFile(REPORT_JSON_TEMPLATE_FILENAME));
    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);
      if (LOG.isLoggable(Level.INFO)) {
        LOG.info("--------------------PROCESSING ELEMENT:");
        LOG.info("VAR NAME:" + itemName);
        LOG.info("---------------------------------------");
      }

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

  // 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 (LOG.isLoggable(Level.INFO)) {
      LOG.info("------------------------------------PROCESSING ELEMENT:\n\n");
      LOG.info("TYPE:" + type);
      LOG.info("VALUE:" + value);
      LOG.info("------------------------------------\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, removeFirstLastChar(newString), desc, units);
    }
    if (type.equals("INTEGER") && (value != null) && (!value.equals("null")) && (!value.equals("\"\""))) {
      // trim off quotes
      value = removeFirstLastChar(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 = removeFirstLastChar(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);
    }
  }

  protected Map<String, Object> getConfigInfo() {
    return new LinkedHashMap<String, Object>() {
      {
        put(ROMEDLL, resources().getResolved(ROMEDLL));
      }
    };
  }
}