V1_0.java [src/java/m/rse/cfactor] Revision:   Date:
package m.rse.cfactor;

import csip.ModelDataService;
import csip.ServiceException;
import csip.annotations.*;
import csip.utils.JSONUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collection;
import javax.ws.rs.Path;
import m.rse.cfactor.utils.Const;
import m.rse.cfactor.utils.PGTools;
import oms3.annotations.*;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;
//import org.geotools.coverage.grid.GridCoverage2D;
//import org.geotools.coverage.grid.io.AbstractGridFormat;
//import org.geotools.coverage.grid.io.GridCoverage2DReader;
//import org.geotools.coverage.grid.io.GridFormatFinder;
//import org.geotools.factory.Hints;
//import org.geotools.gce.geotiff.GeoTiffReader;
//import org.geotools.geometry.DirectPosition2D;
//import org.opengis.geometry.DirectPosition;
//import org.opengis.parameter.GeneralParameterValue;
//import org.opengis.referencing.crs.CoordinateReferenceSystem;

/**
 * CFactor Model service.
 *
 * @author od, wl, sc
 */
@Name("cfactor")
@Description("Returns CFactor value for a given lat/long point")
//@Path("m/cfactor/1.0")
@Polling(first = 5000, next = 2000)
public class V1_0 extends ModelDataService {

    // gets called when the context shuts down.
    public static void onContextDestroy() {
	//PGTools.shutdownDataSource();  //The use of try-with resources auto-closes them at the end of the statement scope.
    }

    String lat = null;
    String lon = null;
    double cfactor = -1;
    double cfactorraster = -1;

    @Override
    protected void preProcess() throws Exception {
	if (JSONUtils.checkKeyExistsB(getParamMap(), Const.RSE_LAT)
		&& JSONUtils.checkKeyExistsB(getParamMap(), Const.RSE_LON)) {
	    lat = getStringParam(Const.RSE_LAT);
	    lon = getStringParam(Const.RSE_LON);
	}
    }

    @Override
    protected String process() throws Exception {
	try {
	    if (lat != null && lon != null) {
		cfactor = getCFactor(lat, lon);
		//cfactorraster = getCFactorRaster(lat, lon);
	    } else {
		boolean bFoundAoi = false;
		// Iterate through polygons, retrieving c factor for each
		Collection<JSONObject> coll = getParamMap().values();
		for (JSONObject jsonobj : coll) {
		    LOG.info("json obj name='" + jsonobj.getString("name") + "'");
		    if (jsonobj.getString("name").equals(Const.RSE_AOI)) {
			bFoundAoi = true;
			LOG.info("json obj=" + jsonobj.toString());
			JSONObject aoiobj = jsonobj.optJSONObject("value");
			JSONArray features = aoiobj.optJSONArray("features");
			LOG.info("features obj=" + features.toString());
			for (int i = 0; i < features.length(); i++) {
			    JSONObject poly = features.getJSONObject(i);
			    LOG.info("poly obj #" + i + poly.toString());
			    JSONObject geometry = poly.optJSONObject("geometry");
			    LOG.info("geometry obj=" + geometry.toString());
			    JSONArray coords = geometry.optJSONArray("coordinates");
			    LOG.info("coords obj=" + coords.toString());
			    for (int j = 0; j < coords.length(); j++) {
				JSONArray shape = coords.getJSONArray(j);
				LOG.info("shape obj=" + shape.toString());
				String newPolygon = "geometry::STPolyFromText('POLYGON((";
				double firstLong = 0.0;
				for (int k = 0; k < shape.length(); k++) {
				    JSONArray point = shape.getJSONArray(k);
				    if (firstLong == 0) {
					firstLong = point.getDouble(0);
				    }
				    if (k > 0) {
					newPolygon += ",";
				    }
				    newPolygon += point.getDouble(0) + " " + point.getDouble(1);
				}
				newPolygon += "))',4326)";
				LOG.info("Polygon of interest=" + newPolygon);
				PGTools.Centroid centroid = PGTools.getCentroid(newPolygon, LOG);
				cfactor = getCFactor(centroid.lat, centroid.lon);
				LOG.info("Skipping other polygons if present...");
				break; // only do the first polygon
			    }
			}
		    }
		}
		if (!bFoundAoi) {
		    return "No AoI found in GeoJSON parameter";
		}
	    }
	    if (cfactor == -1) {
		return "error: cfactor is -1,  check log file...";
	    }
	    return EXEC_OK;
	} catch (SQLException E) {
	    return "Error retrieving C-Factor value from database:" + E.toString();
	}
    }

    @Override
    protected void postProcess() throws Exception {
	putResult("cfactor", cfactor, Const.SERVICE_DESC, null);
	//putResult("cfactorRaster", cfactorraster, SERVICE_DESC, null);
    }
    private double getCFactor(String slat, String slon) throws SQLException, ServiceException {
	double lat = Double.parseDouble(slat);
	double lon = Double.parseDouble(slon);
	double c_fact = Const.UNKNOWN_CFACTOR;

	// Alaska
	if (lat >= Const.ALASKA_MIN_LATITUDE) {
	    appendMetainfoWarning(Const.ALASKA_REGION_WARNING_MSG);
	    return c_fact;
	}

	// continental US only
	if (lat > 24.396308 && lon > -124.848974 && lat < 49.384358 && lon < -66.885444) {
	    String intersect_polygons = "SELECT [C_FACTOR_]"
		    + "  FROM [dbo].[c_factor]"
		    + "  where (geometry::STGeomFromText('POINT(" + lon + " " + lat + ")', 4326).STIntersects([geometry])!= 0);";

            try (Connection c = PGTools.getConnection("legacy.cfactor", LOG)) {
		try (Statement s = c.createStatement()) {
		    try (ResultSet r = s.executeQuery(intersect_polygons)) {;
		    LOG.info("query sql=" + intersect_polygons);
		    int cols = r.getMetaData().getColumnCount();
		    if (cols != 1) {
			LOG.severe("invalid columns in getCFactor 'intersect polygons' query");
			throw new ServiceException("invalid Columns");
		    }
		    // If no intersect find C-Factor using step 2 of algorithm
		    if (!r.next()) {
                            try (Connection c2 = PGTools.getConnection("legacy.cfactor", LOG)) {
			    try (Statement s2 = c2.createStatement()) {
				String dist_from_polylines = "SELECT [C_VALUE]"
					+ " ,(geometry::STGeomFromText('POINT(" + lon + " " + lat + ")', 4326).STDistance([geometry])) as distance"
					+ " FROM [dbo].[us_cvals_aea]"
					+ " order by distance ";
				try (ResultSet r2 = s2.executeQuery(dist_from_polylines)) {
				    LOG.info("query sql=" + dist_from_polylines);
				    int cols2 = r2.getMetaData().getColumnCount();
				    if (cols2 != 2) {
					LOG.severe("invalid columns in getCFactor 'dist from polylines' query");
					throw new ServiceException("invalid Columns");
				    }
				    if (r2.next()) {
					LOG.info("getting CFactor from 'distance from polylines' query");
					LOG.info("nearest c factor=" + r2.getNString(1));
					LOG.info("distance from polyline=" + r2.getString(2));
					c_fact = Double.parseDouble(r2.getNString(1));
				    }
				}
			    }
			}
		    } else {
			LOG.info("getting CFactor from 'intersect polygons' query");
			c_fact = Double.parseDouble(r.getString(1));
		    }
		    }
		}
	    }
	    return c_fact;
	}
	throw new ServiceException("Illegal lat/lon as parameter or cenroid: " + lat + "/" + lon);
    }
//    // geotools attempt
//    private double getCFactorRaster(String slat, String slon) throws SQLException, ServiceException, IOException {
//        double lat = Double.parseDouble(slat);
//        double lon = Double.parseDouble(slon);
//        double c_fact = UNKNOWN_CFACTOR;
//    
//        File tiffFile = new File("/tmp/us_cvalues_topo2ras_masked.tif");
//        AbstractGridFormat format = GridFormatFinder.findFormat(tiffFile);
//        LOG.info("format name=" + format.getName());
//        LOG.info("vendor=" + format.getVendor());
//        LOG.info("version=" + format.getVersion());
//        LOG.info("desc=" + format.getDescription());
//        LOG.info("doc-url=" + format.getDocURL());
////        try
////        {
//            GeoTiffReader reader = new GeoTiffReader(tiffFile, new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE));
//            GeneralParameterValue[] gpv = {null};
//            GridCoverage2D coverage = reader.read(gpv);
//            CoordinateReferenceSystem crs = coverage.getCoordinateReferenceSystem2D();
//            DirectPosition position = new DirectPosition2D(crs, lon, lat);
//            double[] sample = (double[]) coverage.evaluate(position);
//
//            for (int i=0; i < sample.length; i ++)
//            {
//                LOG.info("sample value #" + i + "=" + sample[i]);
//            }
////        }
////        catch (Exception e)
////        {
////            StackTraceElement[] ste = e.getStackTrace();
////            for (int i=0 ; i < ste.length; i++)
////                LOG.severe("STACK TRACE=" + ste[i].toString());
////            LOG.severe("ERROR=" + e.toString());
////            return c_fact;
////        }
//        
//        //GridCoverage2DReader reader = format.getReader(tiffFile);
//        // grid =reader.read(null);
//        // gridData = grid.getRenderedImage().getData();
//
//        
//        return c_fact;
//    }
    
}