WEPPModel.java [src/java/m/wepp] Revision:   Date:
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package m.wepp;

import csip.api.client.ModelDataServiceCall;
import csip.api.server.ServiceException;
import csip.SessionLogger;
import java.io.*;
import org.apache.commons.io.FileUtils;
import org.json.XML;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;

/**
 * This class has misc functions. Needs to be reviewed to see if these can be
 * moved or are not needed.
 *
 * @author jrf
 */
public class WEPPModel {

  private static final double BAD_DOUBLE_VALUE = -999;
  private static final int BAD_INT_VALUE = -999;

  private double precip = BAD_DOUBLE_VALUE,
      soilLoss = BAD_DOUBLE_VALUE,
      runoff = BAD_DOUBLE_VALUE,
      sedYield = BAD_DOUBLE_VALUE,
      fuel = BAD_DOUBLE_VALUE,
      stir = BAD_DOUBLE_VALUE,
      sci = BAD_DOUBLE_VALUE;
  private double om = Double.NaN,
      er = Double.NaN,
      fo = Double.NaN;
  private double deposition, irrigation, nrcsLoss;
  private int contoursHeld = BAD_INT_VALUE, contoursFailed = BAD_INT_VALUE;
  private JSONObject segments;
  private boolean useBuiltin;
  private String weppversion;
  private String preprocversion;
  String contourServiceURL;
  String manServiceURL;
  String stripsServiceURL;
  SessionLogger LOG;


  WEPPModel(SessionLogger log) {
    LOG = log;
    useBuiltin = true;
    weppversion = "";
    preprocversion = "";
  }


  public void setServiceURLS(String contourURL, String managementURL, String stripsURL) {
    contourServiceURL = contourURL;
    manServiceURL = managementURL;
    stripsServiceURL = stripsURL;
  }


  public double getPrecip() {
    return precip;
  }


  public double getLoss() {
    return soilLoss;
  }


  public double getRunoff() {
    return runoff;
  }


  public double getSedyield() {
    return sedYield;
  }


  public double getFuel() {
    return fuel;
  }


  public double getSTIR() {
    return stir;
  }


  public double getSCI() {
    return sci;
  }


  public double getOM() {
    return om;
  }


  public double getFO() {
    return fo;
  }


  public double getER() {
    return er;
  }


  public int getContoursHeld() {
    return contoursHeld;
  }


  public int getContoursFailed() {
    return contoursFailed;
  }


  public double getDeposition() {
    return deposition;
  }


  public double getIrrigation() {
    return irrigation;
  }


  public double getNRCSLoss() {
    return nrcsLoss;
  }


  public JSONObject getSegments() {
    return segments;
  }


  public String getWEPPVersion() {
    return weppversion;
  }


  public String getPreprocversion() {
    return preprocversion;
  }


  /*
     * getManagement()
     * This takes a LMOD key are returns the data in LMOD format that will be parsed
     * to use in WEPP. Any sub objects such as vegetations, operations or residues are
     * looked up the local WEPP sqlite database to get the WEPP specfic parameters.
   */
  public String getManagement(String csip_lmod_file_key) throws Exception {

    ModelDataServiceCall r = new ModelDataServiceCall()
        .put("file_key", csip_lmod_file_key)
        .put("format", "lmod")
        .withDefaultLogger()
        .url(manServiceURL)
        .call();

    if (r.serviceFinished()) {
      try {
        JSONObject obj = r.getJSONObject(r.getNames().get(0)).getJSONArray("managements").getJSONObject(0);
        return obj.toString();
      } catch (JSONException E) {
        LOG.warning("Could not get management data from LMOD: " + E.getMessage());
        return null;
      }
    } else {
      LOG.info("Management request failed: " + r.getError());
      return null;
    }
  }


  /**
   * Get the details of a contour given a specific name. Calls the CSIP contout
   * service.
   *
   * @param lmod_contour_name name of the contour
   * @return JSON with contour parameters.
   */
  public JSONObject getContour(String lmod_contour_name) throws Exception {

    if (useBuiltin) {
      double abs;
      if (lmod_contour_name.equals("c. perfect contouring no row grade")) {
        abs = 0;
      } else if (lmod_contour_name.equals("a. rows up-and-down hill")) {
        abs = 0;
      } else {
        String sslp = lmod_contour_name.substring("b. absolute row grade ".length());
        String[] p = sslp.trim().split(" ");
        abs = Double.parseDouble(p[0]);
      }
      try {
        JSONObject obj = new JSONObject()
            .put("name", lmod_contour_name)
            .put("abs", abs);
        return obj;
      } catch (Exception e) {
        return null;
      }
    } else {
      String[] parts = lmod_contour_name.split("\\\\");
      ModelDataServiceCall r = new ModelDataServiceCall()
          .put("name", parts[parts.length - 1])
          .withDefaultLogger()
          .url(contourServiceURL)
          .call();

      if (r.serviceFinished()) {
        try {
          return r.getJSONObject(r.getNames().get(0)).getJSONArray("contours").getJSONObject(0);
        } catch (JSONException E) {
          LOG.warning("Could not get contour data from LMOD");
          return null;
        }
      } else {
        LOG.warning("Contour request failed: " + r.getError());
        return null;
      }
    }
  }


  /**
   * Gets a specific strip/barrier set of parameters give a name.
   *
   * @param lmod_strip_name name of strip/barrier
   * @return JSON returned from CSIP service
   */
  public JSONObject getStripBarrier(String lmod_strip_name) throws Exception {
    String[] parts = lmod_strip_name.split("\\\\");
    ModelDataServiceCall r = new ModelDataServiceCall()
        .put("name", parts[parts.length - 1])
        .put("format", "r2")
        .withDefaultLogger()
        .url(stripsServiceURL)
        .call();

    if (r.serviceFinished()) {
      try {
        return r.getJSONObject(r.getNames().get(0)).getJSONArray("strips").getJSONObject(0);
      } catch (JSONException E) {
        LOG.warning("Error: Could not get strip data." + E.getMessage());
        return null;
      }
    } else {
      LOG.warning("Strips service failed: " + r.getError());
      return null;
    }
  }


  /**
   * After a WEPP run a brief put file lists the main 4 outputs which as read
   * and saved.
   *
   * @param resultsFile WEPP results
   * @throws IOException error reading file
   */
  public void parseOutputs(File resultsFile) throws IOException {
    contoursHeld = 0;
    contoursFailed = 0;

    String restring;
    try {
      String fc = FileUtils.readFileToString(resultsFile, "UTF-8");
//      restring = XML.toJSONObject(fileContents.toString()).toString();
      restring = XML.toJSONObject(fc).toString();
    } catch (org.json.JSONException ex) {
      throw new IOException("Cannot convert WEPP output XML file to JSON: " + ex.getMessage(), ex);
    }

    if ((restring != null) && (!restring.isEmpty())) {
      JSONObject results;
      try {
        results = new JSONObject(restring);
      } catch (JSONException ex) {
        throw new IOException("Cannot convert WEPP output XML file to JSON: " + ex.getMessage(), ex);
      }

      if ((results == null) || (!results.has("RESULTS"))) {
        throw new IOException("The contents of the WEPP output XML file could not be processed. Contents missing or \"RESULTS\" xml tag not found.");
      }

      results = results.optJSONObject("RESULTS");

      precip = results.optDouble("PRECIP", BAD_DOUBLE_VALUE);
      soilLoss = results.optDouble("LOSS", BAD_DOUBLE_VALUE);
      sedYield = results.optDouble("SEDYIELD", BAD_DOUBLE_VALUE);
      runoff = results.optDouble("RUNOFF", BAD_DOUBLE_VALUE);
      fuel = results.optDouble("FUEL", BAD_DOUBLE_VALUE);
      stir = results.optDouble("STIR", BAD_DOUBLE_VALUE);
      sci = results.optDouble("SCI", BAD_DOUBLE_VALUE);
      om = results.optDouble("OM", BAD_DOUBLE_VALUE);
      er = results.optDouble("ER", BAD_DOUBLE_VALUE);
      fo = results.optDouble("FO", BAD_DOUBLE_VALUE);
      deposition = results.optDouble("DEPOSITION", BAD_DOUBLE_VALUE);
      irrigation = results.optDouble("IRRIGATION", BAD_DOUBLE_VALUE);
      nrcsLoss = results.optDouble("NRCSLOSS", BAD_DOUBLE_VALUE);

      try {
        weppversion = results.getString("WEPP_VERSION");
        preprocversion = results.getString("PREPROCESSOR_VERSION");
      } catch (JSONException ex) {
        throw new IOException("WEPP output XML file is missing a mandatory tag value: " + ex.getMessage(), ex);
      }

      JSONObject contours = results.optJSONObject("Contours");

      if (contours != null) {
        contoursHeld = contours.optInt("Held", BAD_INT_VALUE);
        contoursFailed = contours.optInt("Failed", BAD_INT_VALUE);
      }

      segments = results.optJSONObject("Management");

//    }catch (JSONException e) {
//        precip = soilLoss = sedYield = runoff = fuel = stir = sci = BAD_DOUBLE_VALUE;
//        contoursHeld = contoursFailed = BAD_INT_VALUE;
//      }
    } else {
      throw new IOException("The WEPP output XML file is empty");
    }
  }
}