WEPSManagement.java [src/nodes] Revision: default  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 nodes;

import csip.utils.Client;
import static csip.ModelDataService.ERROR;
import static csip.ModelDataService.KEY_METAINFO;
import static csip.ModelDataService.KEY_PARAMETER;
import static csip.ModelDataService.KEY_RESULT;
import static csip.ModelDataService.KEY_STATUS;
import static csip.ModelDataService.KEY_VALUE;
import static csip.ModelDataService.VALUE;
import csip.api.server.ServiceException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import parsers.ParseTypes;
import parsers.ParserException;
import parsers.WEPSParser;
import translators.Translator;
import static utils.Constants.ID;
import static utils.Constants.LIMIT;
import static utils.Constants.NAME;
import static utils.Constants.NATIVE_FORMATS;
import static utils.Constants.RESIDUES;
import utils.TranslatorException;
import utils.Urls;
import utils.Util;

/**
 *
 * @author Brad
 */
public class WEPSManagement extends Management {

  public WEPSManagement(Urls urls) {
    super(urls);
  }
  
  @Override
  public void readJSONData(JSONObject data, Translator.FORMAT type) throws JSONException, TranslatorException {
    super.readJSONData(data, type);
    rotateEvents();
  }

  /**
   * Prevents a fallow year in weps if the rotation starts toward the end of the year
   */
//    public void rotateEvents(){
//        LocalDate start = eventData.get(0).getDate();
//        LocalDate end = eventData.get(eventData.size() - 1).getDate();
//        int current_index = 0; // this will keep the shifted year in order
//
//        for(Iterator<Event> iterator = eventData.iterator(); iterator.hasNext();){ // must do it this way so I can remove
//            Event event = iterator.next();
//            if(event.getDate().withYear(start.getYear()).isBefore(start)
//                    && event.getDate().getYear() == end.getYear()){
//                eventData.remove(event);
//                event.setDate(event.getDate().withYear(start.getYear()));
//                eventData.add(current_index, event);
//                current_index++;
//            }
//        }
//
//    }
  public void readManData(File manFile) throws IOException, ServiceException, ParserException {
    WEPSParser parser = new WEPSParser(manFile.getAbsolutePath());
    ParseTypes type;
    Event datum;

    while ((type = parser.readNext()) != ParseTypes.END) {
      if (type == ParseTypes.START) {
        rotationYears = parser.getRotationYears();
      }

      if (type == ParseTypes.DATE) {
        datum = new Event();
        datum.setDate(parser.getDate());
        datum.readManData(parser);
        eventData.add(datum);
      }

    }
  }

  /**
   *
   * @return total fuel usage in gal/ acre
   */
  public Double calculateTotalFuelUsage() {
    List<Double> fuelUsages = calculateFuelUsage();
    Double totalFuel = 0.0;

    // trying this suggestion but it is just totalling the fuel values. Looks like map reduce.
    totalFuel = fuelUsages.stream().map((f) -> f).reduce(totalFuel, (accumulator, _item) -> accumulator + _item);

    return totalFuel;
  }

  /**
   *
   * @return fuel usage by interval in gal/acre
   */
  public List<Double> calculateFuelUsage() {
    List<Double> fuels = new ArrayList();
    Double fuelUse;

    for (List<WEPSOperation> interval : getCropIntervals()) {
      fuelUse = 0.0;
      fuelUse = interval.stream().map((op) -> op.calculateFuel()).reduce(fuelUse, (accumulator, _item) -> accumulator + _item);
      fuels.add(fuelUse * 0.106907); // L/ha -> gal/acre
    }
    return fuels;
  }

  private List<List<WEPSOperation>> getCropIntervals() {
    List<List<WEPSOperation>> intervals = new ArrayList();
    List<WEPSOperation> ops;
    WEPSOperation op;

    ops = new ArrayList();
    for (Event e : eventData) {
      op = ( WEPSOperation ) e.getOperation();
      ops.add(op);

      if (op.containsAction("P", 31)) {
        intervals.add(ops);
        ops = new ArrayList();
      }
    }

    if (intervals.isEmpty())
      intervals.add(ops); // No kill crop was found so put everything into one interval.
    else
      intervals.get(0).addAll(ops); // take the last operations and put them in the first interval due to wrap around.

    return intervals;
  }

  /**
   * This method take all the assumed crops from a WEPS man file and converts them to residues if
   * they are actually residues
   */
  public void convertResidues() throws JSONException, Exception {
    Crop crop;
    JSONObject req;
    JSONObject meta;
    JSONArray params;
    JSONObject jparam;
    JSONArray jvalues;
    JSONObject jnative_formats;
    JSONObject res;
    JSONArray results;
    JSONObject lmod;
    JSONObject value;
    JSONArray residues;
    JSONObject jresidue = null;
    JSONObject responseMeta;
    JSONObject jlimit;
    Map<String, JSONObject> fileData;

    req = new JSONObject();
    meta = new JSONObject();
    params = new JSONArray();

    req.put(KEY_METAINFO, meta);
    req.put(KEY_PARAMETER, params);

    jnative_formats = new JSONObject();
    jnative_formats.put(NAME, NATIVE_FORMATS);
    jnative_formats.put(KEY_VALUE, "FALSE");
    params.put(jnative_formats);

    jlimit = new JSONObject();
    jlimit.put(NAME, LIMIT);
    jlimit.put(VALUE, "all");
    params.put(jlimit);

    jparam = new JSONObject();
    jvalues = new JSONArray();

    jparam.put(NAME, NAME);

    params.put(jparam);
    jparam.put(VALUE, jvalues);

    for (Event datum : eventData) {
      crop = datum.getCrop();
      if (crop != null) {
        jvalues.put(datum.getCrop().getName());

      }
    }
    res = new Client().doPOST(urls.getResidue(), req);

    responseMeta = res.getJSONObject(KEY_METAINFO);
    if (!responseMeta.getString(KEY_STATUS).equalsIgnoreCase("Failed")) {
      results = res.getJSONArray(KEY_RESULT);
      lmod = results.getJSONObject(0);
      value = lmod.getJSONObject(VALUE);
      residues = value.getJSONArray(RESIDUES);
      fileData = Util.mapResidueResultsByName(residues, Translator.FORMAT.KEY);
      for (Event datum : eventData) {
        if (datum.getCrop() != null) {
          jresidue = fileData.get(datum.getCrop().getName());

          // If it is null assume it is a crop and do nothing
          // If it is found then it should be a residue so we need to convert it.
          if (jresidue != null) {
            datum.addResidue(new WEPSResidue(jresidue.getString(ID), datum.getCrop().getName()));
            datum.removeCrop();
          }
        }
      }
    } else {
      String error = responseMeta.getString(ERROR);
      throw new ServiceException("residue service error: " + error);
    }
  }
}