WWESoilParams.java [src/java/crp/utils] 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-2019, 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 crp.utils;

import static csip.ModelDataService.KEY_METAINFO;
import static csip.ModelDataService.KEY_PARAMETER;
import csip.ServiceException;
import csip.utils.JSONUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import soils.AoA;

/**
 *
 * @author <a href="mailto:shaun.case@colostate.edu">Shaun Case</a>
 */
public class WWESoilParams extends ServiceCall {

  protected AoA aoa = null;
  protected String _callingMetaInfo;
  protected JSONObject _location = null;
  protected String mupolygonkey = "";
  private SortedMap<Double, SoilResult> componentOrderList = new TreeMap<>(Collections.reverseOrder());

  public WWESoilParams(String metaInfo, JSONObject shape, String URI) throws JSONException {
    super(URI);
    _callingMetaInfo = metaInfo;
    errorPrefix = "WWESoilParams_ServiceCall";
    _location = new JSONObject(shape.toString());
  }

  public WWESoilParams(String metaInfo, JSONObject shape, String URI, Object data, CheckedServiceResult<ServiceCallData> serviceCallback) throws JSONException {
    super(URI, data, serviceCallback);
    _callingMetaInfo = metaInfo;
    errorPrefix = "WWESoilParams_ServiceCall";
    _location = new JSONObject(shape.toString());
  }

  public WWESoilParams(String metaInfo, JSONObject shape, String URI, CheckedServiceResult<ServiceCallData> serviceCallback) throws JSONException {
    super(URI, serviceCallback);
    _callingMetaInfo = metaInfo;
    errorPrefix = "WWESoilParams_ServiceCall";
    _location = new JSONObject(shape.toString());
  }

  public WWESoilParams(String metaInfo, String mupolygonkey, String URI, CheckedServiceResult<ServiceCallData> serviceCallback) throws JSONException {
    super(URI, serviceCallback);
    _callingMetaInfo = metaInfo;
    errorPrefix = "WWESoilParams_ServiceCall";
    this.mupolygonkey = mupolygonkey;
  }

  @Override
  protected void createRequest() throws ServiceException {
    JSONArray dataArray;

    requestMetainfoObject = new JSONObject();
    request = new JSONObject();

    dataArray = new JSONArray();
    try {
      requestMetainfoObject.put("MultipartRequest", "Bundled Service Request From csip-crp MetaModeling Assessment Service");
      requestMetainfoObject.put("CRPAssessment_Metainfo", new JSONObject(_callingMetaInfo));
      if (asyncCall) {
        requestMetainfoObject.put("mode", "async");
      }
      request.put(KEY_METAINFO, requestMetainfoObject);

      if (null != _location) {
        _location.put("name", "aoa_geometry");
        dataArray.put(_location);

        request.put(KEY_PARAMETER, dataArray);
      } else {
        if (!mupolygonkey.isEmpty()) {
          dataArray.put(JSONUtils.data("mupolygonkey", mupolygonkey));
          request.put(KEY_PARAMETER, dataArray);
        } else {
          throwServiceCallException("Cannot convert centroid buffer to JSON.");
        }
      }
    } catch (JSONException ex) {
      throwServiceCallException("Cannot create the JSON request for WWESoilParams call.", ex);
    }
  }

  @Override
  protected void parseResults() throws ServiceException {
    //   Error checking has already been done on these results.
    // If we get to this function, no further error
    // checking is necessary, except to look at the "results" array in the output, if desired.
    if (null == callResultSection) {
      throwServiceCallException("Cannot find results in the call to " + this.URI + " .");
    }

    try {
      //  Get the region results and store them.
      Map<String, JSONObject> resultMap = JSONUtils.getResults(results);

      if (resultMap.containsKey("Map Units")) {
        JSONArray mapUnitList = JSONUtils.getJSONArrayParam(resultMap, "Map Units");
        //aoa = new AoA(mapUnitList);

        for (int i = 0; i < mapUnitList.length(); i++) {
          JSONArray mapUnitData = mapUnitList.getJSONArray(i);
          ArrayList<JSONObject> polygonList = new ArrayList<>();

          Map<String, JSONObject> mapUnitObject = JSONUtils.preprocess(mapUnitData);

          String mukey = JSONUtils.getStringParam(mapUnitObject, "mukey", "");
          if (mukey.isEmpty()) {
            throwServiceCallException("Returned mapunit list does not contain the required result value for 'mukey' for a mapunit.");
          }

          String areaSymbol = JSONUtils.getStringParam(mapUnitObject, "areasymbol", "");
          if (areaSymbol.isEmpty()) {
            throwServiceCallException("Returned mapunit list does not contain the required result value for 'areasymbol' for a mapunit.");
          }

          double mapArea = JSONUtils.getDoubleParam(mapUnitObject, "area", 0.0);
          if (areaSymbol.isEmpty()) {
            throwServiceCallException("Returned mapunit list does not contain the required result value for 'area' for a mapunit.");
          }

          if (mapArea > 0) {
            //Parse intersected polygons
            if (mapUnitObject.containsKey("intersected_polygons")) {
              JSONArray polys = JSONUtils.getJSONArrayParam(mapUnitObject, "intersected_polygons");

              for (int polyIndex = 0; polyIndex < polys.length(); polyIndex++) {
                polygonList.add(polys.getJSONObject(polyIndex));
              }

            } else {
              throwServiceCallException("Returned mapunit list does not contain intersected_polygon object.  This is required to compute DEM slope values.");
            }

            if (mapUnitObject.containsKey("Components")) {
              JSONArray componentList = JSONUtils.getJSONArrayParam(mapUnitObject, "Components");

              for (int j = 0; j < componentList.length(); j++) {
                JSONArray componentData = componentList.getJSONArray(j);
                Map<String, JSONObject> componentObject = JSONUtils.preprocess(componentData);

                if (componentObject.containsKey("area")) {

                  double area = JSONUtils.getDoubleParam(componentObject, "area", Double.NaN);
                  if (Double.isNaN(area)) {
                    throwServiceCallException("Returned component list does not contain the required result value for 'area' for a component.");
                  }

                  if (area > 0.1) {
                    if (componentObject.containsKey("cokey")) {
                      String cokey = JSONUtils.getStringParam(componentObject, "cokey", "");
                      if (cokey.isEmpty()) {
                        throwServiceCallException("Returned component list does not contain the required result value for 'cokey' for a component.");
                      }

                      if (componentObject.containsKey("length_r")) {
                        double length = JSONUtils.getDoubleParam(componentObject, "length_r", Double.NaN);
                        if (Double.isNaN(length)) {
                          throwServiceCallException("Returned component list does not contain the required result value for 'length_r' for a component.");
                        }

                        if (componentObject.containsKey("slope_r")) {
                          double slope_r = JSONUtils.getDoubleParam(componentObject, "slope_r", Double.NaN);
                          if (Double.isNaN(slope_r)) {
                            throwServiceCallException("Returned component list does not contain the required result value for 'slope_r' for a component.");
                          }
                          SoilResult soilResult = new SoilResult();
                          soilResult.mukey = mukey;
                          soilResult.musym = JSONUtils.getStringParam(mapUnitObject, "musym", "NONE");
                          soilResult.muname = JSONUtils.getStringParam(mapUnitObject, "muname", "NONE");
                          soilResult.areaSymbol = areaSymbol;
                          soilResult.cokey = cokey;
                          soilResult.length = length;
                          soilResult.tfact = JSONUtils.getDoubleParam(componentObject, "tfact", Double.NaN);;
                          soilResult.area = area;
                          soilResult.slope_r = slope_r;
                          if (mupolygonkey.isEmpty()) {
                            soilResult.area_pct = JSONUtils.getDoubleParam(componentObject, "area_pct", Double.NaN);
                          } else {
                            soilResult.area_pct = JSONUtils.getDoubleParam(componentObject, "comppct_r", Double.NaN);
                          }
                          soilResult.soilName = JSONUtils.getStringParam(componentObject, "compname", "NONE");
                          soilResult.soilLongName = JSONUtils.getStringParam(componentObject, "comp_long_name", "NONE");
                          soilResult.setPolygons(polygonList);

                          componentOrderList.put(area, soilResult);
                        }
                      } else {
                        throwServiceCallException("Returned component list does not contain the required result 'length_r' for a component.");
                      }
                    } else {
                      throwServiceCallException("Returned component list does not contain the required result 'cokey' for a component.");
                    }
                  }
                } else {
                  throwServiceCallException("Returned component list does not contain the required result 'area' for a component.");
                }
              }
            }
          }
        }
      } else {
        throwServiceCallException("No list of map units was returned by the WWESoilParams service.");
      }

    } catch (JSONException ex) {
      throwServiceCallException("Could not build the results map: " + ex.getMessage(), ex);
    }
  }

  public AoA getAoAData() {
    return aoa;
  }

  public ArrayList<SoilResult> getTopThree() throws ServiceException, JSONException {
    ArrayList<SoilResult> ret_val = new ArrayList<>();

    if (!componentOrderList.isEmpty()) {
      int count = 0;

      Set s = componentOrderList.entrySet();
      Iterator i = s.iterator();

      while (i.hasNext() && (count < 3)) {
        Map.Entry entry = (Map.Entry) i.next();
        SoilResult soilResult = new SoilResult((SoilResult) entry.getValue());

        ret_val.add(soilResult);
        count++;
      }
    } else {
      throw new ServiceException("There were no returned components for the AoA provided to the WWESoilParam Service.");
    }

    return ret_val;
  }
}