V1_0.java [src/java/m/util] 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.util;

import csip.ModelDataService;
import csip.annotations.*;
import static csip.annotations.ResourceType.*;

import java.util.ArrayList;
import javax.ws.rs.Path;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import java.io.IOException;
import java.text.ParseException;
import java.util.List;

/**
 * This service returns data from a converted
 *
 * @author jf
 */
@Name("managementTranslate")
@Description("WEPP management translation")
@Path("m/util/translate/1.0")
@Polling(first = 2000, next = 2000)

// Output to capture
@Resource(file = "*stdout.txt *stderr.txt", type = OUTPUT)

/**
 * This is translation service from an IET CRLMOD file to a management file that
 * can be loaded into the WEPP web interface.
 */
public class V1_0 extends ModelDataService {

  String result;
  static final String IET_ROTATION = "ietrotation";
  static final String IET_MANAGEMENTS = "managements";
  static final Boolean crlmod3_format = true;


  /**
   * Calls functions to build the WEPP input files and then run WEPP
   *
   * @throws Exception any problems completing the request.
   */
  @Override
  protected void doProcess() throws Exception {
    if (parameter().has(IET_ROTATION)) {
      JSONObject rot = parameter().getJSON(IET_ROTATION);
      String namedesc = rot.getString("name");
      JSONArray rots = rot.getJSONArray("managements");
      JSONArray newchunks = new JSONArray();
      for (int j = 0; j < rots.length(); j++) {
        JSONObject mparts = rots.getJSONObject(j);
        JSONArray evts = mparts.getJSONArray("events");
        for (int k = 0; k < evts.length(); k++) {
          newchunks.put(evts.get(k));
        }
      }
      JSONObject obn = new JSONObject().append("events", newchunks);
      result = parseDataCSIPCRLMOD(obn, namedesc, crlmod3_format);
      JSONObject obj = new JSONObject(result);
      results().put("WEPPMAN", obj, "WEPP Management Data");
    }
  }


  /**
   * Converts IET CRLMOD JSON blob into an internal structure.
   *
   * @param baseCRLMODObject starting CRLMOD object
   * @return new representation as a string
   * @throws IOException if any
   * @throws ParseException if any
   * @throws JSONException if any
   */
  protected String parseDataCSIPCRLMOD(JSONObject baseCRLMODObject, String namedesc, boolean crlmod3_format)
      throws IOException, ParseException, JSONException {

    String newdata = "";
    try {
      JSONArray ev0 = baseCRLMODObject.getJSONArray("events");
      JSONArray events = ev0.getJSONArray(0);
      List<String> dates = new ArrayList<>();
      List<String> ids = new ArrayList<>();
      List<String> ops = new ArrayList<>();
      List<String> vegs = new ArrayList<>();
      List<Integer> veg_ids = new ArrayList<>();
      List<Integer> yields = new ArrayList<>();
      List<String> yieldUnits = new ArrayList<>();
      List<String> residues = new ArrayList<>();
      List<Integer> res_ids = new ArrayList<>();
      List<Integer> res_amts = new ArrayList<>();
      //LOG.info("Looking at events:\n");
      int yearBase = 1;

      for (int i = 0; i < events.length(); i++) {
        JSONObject ev = events.optJSONObject(i);
        //LOG.info("Event Object: " + ev.toString());
        String datestr = ev.getString("date");
        String parts[] = datestr.split("-");
        int yr = Integer.parseInt(parts[0]);
        // WEPP expects years 1..N If we see a very large number it probably means that 
        // actual years are being sent, like 1986 2017. In this case adjust the years
        // so they start at year 1. Note: that in a regular WEPP year numbers (1..N) the beginning
        // years can be fallow, when real year values are sent no beginning fallow can be specified.
        if (yr > 1000) {
          if (i == 0) {
            yearBase = yr;
          }
          yr = (yr - yearBase) + 1;
          datestr = String.format("%04d", yr) + "-" + parts[1] + "-" + parts[2];
        }
        dates.add(datestr);

        JSONObject op = ev.getJSONObject("operation");
        String idstr = op.getString("id");
        ids.add(idstr);
        String namestr = op.getString("name");
        ops.add(namestr);

        double yld = 0;
        double resa = 0;
        if (!crlmod3_format) {
          yld = ev.optDouble("yield");
          resa = ev.optDouble("res_added");
        }
        JSONObject crop = ev.optJSONObject("crop");
        if (crop != null) {
          String id = crop.getString("id");
          if (id.equals("")) {
            vegs.add(null);
            veg_ids.add(null);
            yields.add(null);
            yieldUnits.add(null);
          } else {
            if (crlmod3_format) {
              yld = crop.optDouble("yield");
            }
            vegs.add(crop.getString("name"));
            veg_ids.add(Integer.parseInt(crop.getString("id")));
            String yunit = crop.getString("yieldUnit");
            if (yunit == null) {
              yieldUnits.add("???");
            } else {
              yieldUnits.add(yunit);
            }
            if (Double.isNaN(yld)) {
              try {
                int cyld = crop.getInt("defaultYield");
                yields.add(cyld);
              } catch (Exception e) {
                // there is no yield or default value specified - 
                LOG.severe("Yield missing on: " + datestr);
              }
            } else {
              yields.add((int) yld);
            }
          }
        } else {
          vegs.add(null);
          veg_ids.add(null);
          yields.add(null);
          yieldUnits.add(null);
        }

        JSONObject res = ev.optJSONObject("residue");
        JSONArray resaddarr = new JSONArray();
        if (res != null) {
          String id = res.getString("id");
          if (id.equals("")) {
            res_ids.add(null);
            residues.add(null);
            res_amts.add(null);
          } else {
            if (crlmod3_format) {
              // Fix 2/2020 - get residue amount from residue block
              // resa = crop.optDouble("res_added");
              resa = res.optDouble("res_added");
            }
            residues.add(res.getString("name"));
            res_ids.add(Integer.parseInt(res.getString("id")));
            res_amts.add((int) resa);
          }
        } else {
          res_ids.add(null);
          residues.add(null);
          res_amts.add(null);
        }
      }

      // build the new object
      JSONObject newobj = new JSONObject();
      JSONObject lmod_file = new JSONObject();
      JSONObject lmod_data = new JSONObject();
      JSONObject params = new JSONObject();
      JSONArray param = new JSONArray();

      lmod_file.put("path", "");
      lmod_file.put("name", namedesc);
      lmod_file.put("crlmod", true);
      lmod_file.put("version", 201803);

      // dates
      JSONObject op_date = new JSONObject();
      op_date.put("name", "OP_DATE");
      JSONArray op_dates = new JSONArray();
      for (int i = 0; i < dates.size(); i++) {
        op_dates.put(dates.get(i));
      }
      op_date.put("data", op_dates);
      param.put(op_date);

      // yields
      JSONObject harv_yields = new JSONObject();
      harv_yields.put("name", "MAN_OP_VEG_NUM_HARV_UNITS");
      JSONArray unitarr = new JSONArray();
      for (int i = 0; i < yields.size(); i++) {
        unitarr.put(yields.get(i));
      }
      harv_yields.put("data", unitarr);
      param.put(harv_yields);

      // operations
      JSONObject my_ops = new JSONObject();
      my_ops.put("name", "OP_PTR");
      JSONArray oparr = new JSONArray();
      for (int i = 0; i < ops.size(); i++) {
        JSONObject oneop = new JSONObject();
        if (ids.get(i) == null) {
          oneop.put("file_key", ops.get(i));
        } else {
          oneop.put("file_key", ids.get(i).toString());
          oneop.put("value", "operations\\" + ops.get(i));
        }
        oparr.put(oneop);
      }
      my_ops.put("data", oparr);
      param.put(my_ops);

      // crops
      JSONObject my_vegs = new JSONObject();
      my_vegs.put("name", "VEG_PTR");
      JSONArray vegarr = new JSONArray();
      for (int i = 0; i < vegs.size(); i++) {
        JSONObject oneveg = new JSONObject();
        if (vegs.get(i) == null) {
          oneveg.put("file_key", JSONObject.NULL);
        } else {
          oneveg.put("file_key", veg_ids.get(i).toString());
          oneveg.put("value", "vegetations\\" + vegs.get(i));
        }
        vegarr.put(oneveg);
      }
      my_vegs.put("data", vegarr);
      param.put(my_vegs);

      // residue amounts
      JSONObject resobj = new JSONObject();
      resobj.put("name", "RES_ADDED");
      JSONArray reso = new JSONArray();
      for (int i = 0; i < res_amts.size(); i++) {
        reso.put(res_amts.get(i));
      }
      resobj.put("data", reso);
      param.put(resobj);

      // residue names
      JSONObject my_ress = new JSONObject();
      my_ress.put("name", "EXT_RES_PTR");
      JSONArray resarr = new JSONArray();
      JSONArray resaddarr = new JSONArray();
      for (int i = 0; i < residues.size(); i++) {
        JSONObject oneres = new JSONObject();
        if (residues.get(i) == null) {
          oneres.put("file_key", JSONObject.NULL);
        } else {
          oneres.put("file_key", res_ids.get(i).toString());
          oneres.put("value", "residues\\" + residues.get(i));
        }
        resarr.put(oneres);
      }
      my_ress.put("data", resarr);
      param.put(my_ress);

      JSONObject weppn = new JSONObject()
          .put("name", "WEPP_NAMES")
          .put("type", "Bool")
          .put("value", "true")
          .put("data", true);
      param.put(weppn);

      params.put("param", param);
      lmod_file.put("params", params);
      lmod_data.put("lmod_file", lmod_file);
      //newobj.put("lmodData", lmod_data);
      newdata = lmod_data.toString();
    } catch (Exception e) {
      LOG.info("translate2WEPP_CRLMOD error: could not convert management" + baseCRLMODObject.toString());
      newdata = "";
    }
    LOG.info("converted from CRLMOD: " + newdata);
    return newdata;
  }

}