V1_0.java [src/java/m/svap/svap09_svapgradient] Revision: default  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.svap.svap09_svapgradient;

import com.vividsolutions.jts.geom.Coordinate;
import csip.Config;
import csip.annotations.Polling;
import csip.annotations.Resource;
import csip.ModelDataService;
import csip.ServiceException;
import gisobjects.GISObject;
import gisobjects.GISObjectException;
import gisobjects.GISObjectFactory;
import gisobjects.db.GISEngine;
import static gisobjects.db.GISEngineFactory.createGISEngine;
import gisobjects.vector.GIS_FeatureCollection;
import java.io.IOException;
import java.net.URISyntaxException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.ws.rs.Path;
import csip.annotations.Description;
import csip.annotations.Name;
import org.codehaus.jettison.json.JSONObject;
import org.codehaus.jettison.json.JSONException;
import svap.utils.DBResources;
import static svap.utils.DBResources.CRDB;
import svap.utils.ExternalService;
import svap.utils.SVAPUtils;

/**
 * SVAP-09: Calculate Stream Gradient for Field Assessment
 *
 * @author Rumpal Sidhu
 * @version 1.0
 */
@Name("SVAP-09: Calculate Stream Gradient for Field Assessment")
@Description("This service computes the gradient of the USGS NHD stream flowline"
    + " nearest the point representing the stream reach to be evaluated by SVAP.")
@Path("m/svap/svapgradient/1.0")
@Polling(first = 10000, next = 2000)
@Resource(from = DBResources.class)

public class V1_0 extends ModelDataService {

  private JSONObject assessmentLocation;
  private int assessmentId;
  private GISObject streamGISGeometry;
  private double streamLength;
  private double startElevation;
  private double endElevation;
  private double gradient;


  @Override
  protected void preProcess() throws ServiceException {
    assessmentLocation = parameter().getJSON("assessment_location");
    assessmentId = parameter().getInt("assessment_id");
  }


  @Override
  protected void doProcess() throws ServiceException, JSONException, URISyntaxException, IOException, SQLException, GISObjectException, Exception {
    JSONObject huc12Response = SVAPUtils.getHUC12Data(assessmentLocation, "json");
    String hucGeometry = huc12Response.getJSONArray("features").getJSONObject(0).getJSONObject("geometry").toString();
    JSONObject nhdFlowlineResponse = SVAPUtils.getNHDFlowlineData(hucGeometry, "geojson", "FCODE = 46000 OR FCODE = 46003 OR FCODE = 46006 OR FCODE = 46007");
    findNearestStreamSegment(nhdFlowlineResponse);
    if (streamGISGeometry == null) {
      throw new ServiceException("Problem in finding the nearest stream segment.");
    } else {
      Coordinate[] coordArray = streamGISGeometry.getGeometry().getCoordinates();
      startElevation = getElevation(coordArray[0].y, coordArray[0].x);
      endElevation = getElevation(coordArray[coordArray.length - 1].y, coordArray[coordArray.length - 1].x);
      gradient = Math.abs(startElevation - endElevation) / (streamLength);
    }
  }


  private void findNearestStreamSegment(JSONObject streamGeometry) throws SQLException, GISObjectException, JSONException, IOException, ServiceException {
    try (Connection connection = resources().getJDBC(CRDB);
        GISEngine gisEngine = createGISEngine(connection);) {

      GISObject assessmentPoint = GISObjectFactory.createGISObject(assessmentLocation, gisEngine);
      GISObject gisStreamGeometry = GISObjectFactory.createGISObject(streamGeometry, gisEngine);

      if (GISObject.GISObjectType.featurecollection == gisStreamGeometry.getType()) {
        SortedMap<Double, Integer> distanceMap = new TreeMap();
        GIS_FeatureCollection gfc = (GIS_FeatureCollection) gisStreamGeometry;
        for (int i = 0; i < gfc.getFeatureCount(); i++) {
          GISObject stream = gfc.getGeometry(i);
          double distance = assessmentPoint.distanceTo(stream);
          distanceMap.put(distance, i);
        }
        int index = distanceMap.get(distanceMap.firstKey());
        streamGISGeometry = gfc.getGeometry(index);
        streamLength = Double.parseDouble(gfc.getFeatureAttribute(index, "LENGTHKM")) * 1000.0;
      }
    }
  }


  private double getElevation(double latitude, double longitude) throws Exception {
    String requestUrl = Config.getString("service.csip.epqs.url") + "x=" + longitude + "&y=" + latitude + "&units=Meters&output=json";
    JSONObject responseObj = new JSONObject(new ExternalService().doGET(requestUrl));
    return responseObj.getJSONObject("USGS_Elevation_Point_Query_Service").getJSONObject("Elevation_Query").getDouble("Elevation");
  }


  @Override
  protected void postProcess() throws ServiceException {
    results().put("assessment_id", assessmentId, "Assessment Identifier");
    results().put("stream_geometry", streamGISGeometry.toWKT(), "Stream Geometry");
    results().put("stream_length", streamLength, "Stream flowline length", "m");
    results().put("elevation_1", startElevation, "Elevation of Stream Flowline Endpoint", "m");
    results().put("elevation_2", endElevation, "Elevation of Stream Flowline Endpoint", "m");
    results().put("gradient", gradient, "Gradient of the Stream");
  }
}