package com.esri.hadoop.hive;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hive.pdk.HivePdkUnitTest;
import org.apache.hive.pdk.HivePdkUnitTests;

import com.esri.core.geometry.Geometry;
import com.esri.core.geometry.GeometryEngine;
import com.esri.core.geometry.ogc.OGCGeometry;

@Description(
	name = "ST_Intersection",
	value = "_FUNC_(ST_Geometry1, ST_Geometry2) - intersection of ST_Geometry1 & ST_Geometry2",
	extended = "Example:\n" + 
	"SELECT ST_AsText(_FUNC_(ST_Point(1,1), ST_Point(1,1))) FROM onerow; -- POINT (1 1)\n" +
	"SELECT ST_AsText(_FUNC_(ST_GeomFromText('linestring(0 2, 0 0, 2 0)'), ST_GeomFromText('linestring(0 3, 0 1, 1 0, 3 0)'))) FROM onerow; -- MULTILINESTRING ((1 0, 2 0), (0 2, 0 1))\n" +
	"SELECT ST_AsText(_FUNC_(ST_LineString(0,2, 2,3), ST_Polygon(1,1, 4,1, 4,4, 1,4))) FROM onerow; -- MULTILINESTRING ((1 2.5, 2 3))\n" +
	"SELECT ST_AsText(_FUNC_(ST_Polygon(2,0, 2,3, 3,0), ST_Polygon(1,1, 4,1, 4,4, 1,4))) FROM onerow; -- MULTIPOLYGON (((2.67 1, 2 3, 2 1, 2.67 1)))\n" +
	"OGC Compliance Notes : \n" +
	" In the case where the two geometries intersect in a lower dimension," +
	" ST_Intersection may drop the lower-dimension intersections, or output a closed linestring.\n" +
	"SELECT ST_AsText(_FUNC_(ST_Polygon(2,0, 3,1, 2,1), ST_Polygon(1,1, 4,1, 4,4, 1,4))) FROM onerow; -- MULTIPOLYGON EMPTY or LINESTRING (2 1, 3 1, 2 1)\n"
	)

public class ST_Intersection extends ST_GeometryProcessing {
	static final Log LOG = LogFactory.getLog(ST_Intersection.class.getName());

	public BytesWritable evaluate(BytesWritable geometryref1, BytesWritable geometryref2)
	{
		if (geometryref1 == null || geometryref2 == null ||
		    geometryref1.getLength() == 0 || geometryref2.getLength() == 0) {
			LogUtils.Log_ArgumentsNull(LOG);
			return null;
		}
		if (!GeometryUtils.compareSpatialReferences(geometryref1, geometryref2)) {
			LogUtils.Log_SRIDMismatch(LOG, geometryref1, geometryref2);
			return null;
		}

		OGCGeometry ogcGeom1 = GeometryUtils.geometryFromEsriShape(geometryref1);
		OGCGeometry ogcGeom2 = GeometryUtils.geometryFromEsriShape(geometryref2);
		if (ogcGeom1 == null || ogcGeom2 == null){
			LogUtils.Log_ArgumentsNull(LOG);
			return null;
		}

		OGCGeometry commonGeom;
		try {		
			commonGeom = ogcGeom1.intersection(ogcGeom2);
			if (commonGeom == null) {  // may obviate in geometry-api
				LogUtils.Log_InternalError(LOG, "ST_Intersection: work around null");
				commonGeom = esriIntersection(ogcGeom1, ogcGeom2);
			}
			return GeometryUtils.geometryToEsriShapeBytesWritable(commonGeom);
		} catch (ArrayIndexOutOfBoundsException e) {  // may obviate in geometry-api
		    LogUtils.Log_InternalError(LOG, "ST_Intersection: " + e);
			commonGeom = esriIntersection(ogcGeom1, ogcGeom2);
			return GeometryUtils.geometryToEsriShapeBytesWritable(commonGeom);
		} catch (Exception e) {
		    LogUtils.Log_InternalError(LOG, "ST_Intersection: " + e);
		    return null;
		}
	}

	private OGCGeometry esriIntersection(OGCGeometry ogcGeom1, OGCGeometry ogcGeom2) {
		LogUtils.Log_InternalError(LOG, "ST_Intersection: work around null");
		Geometry esriGeom1 = ogcGeom1.getEsriGeometry(),
			esriGeom2 = ogcGeom2.getEsriGeometry();
		Geometry commonEsri = GeometryEngine.intersect(esriGeom1, esriGeom2,
													   ogcGeom1.getEsriSpatialReference());
		return OGCGeometry.createFromEsriGeometry(commonEsri,
												  ogcGeom1.getEsriSpatialReference());
	}

}

@@ -591,16 +591,18 @@
 n%22 + %0A%09%22
+  
 SELECT S
@@ -675,32 +675,34 @@
 NT (1 1)%5Cn%22 +%0A%09%22
+  
 SELECT ST_AsText
@@ -863,32 +863,34 @@
 2, 0 1))%5Cn%22 +%0A%09%22
+  
 SELECT ST_AsText
@@ -1001,32 +1001,34 @@
 5, 2 3))%5Cn%22 +%0A%09%22
+  
 SELECT ST_AsText
@@ -2440,1134 +2440,187 @@
 %0A%09%09%09
-if (commonGeom == null) %7B  // may obviate in geometry-api%0A%09%09%09%09LogUtils.Log_InternalError(LOG, %22ST_Intersection: work around null%22);%0A%09%09%09%09commonGeom = esriIntersection(ogcGeom1, ogcGeom2);%0A%09%09%09%7D%0A%09%09%09return GeometryUtils.geometryToEsriShapeBytesWritable(commonGeom);%0A%09%09%7D catch (ArrayIndexOutOfBoundsException e) %7B  // may obviate in geometry-api%0A%09%09    LogUtils.Log_InternalError(LOG, %22ST_Intersection: %22 + e);%0A%09%09%09commonGeom = esriIntersection(ogcGeom1, ogcGeom2);%0A%09%09%09return GeometryUtils.geometryToEsriShapeBytesWritable(commonGeom);%0A%09%09%7D catch (Exception e) %7B%0A%09%09    LogUtils.Log_InternalError(LOG, %22ST_Intersection: %22 + e);%0A%09%09    return null;%0A%09%09%7D%0A%09%7D%0A%0A%09private OGCGeometry esriIntersection(OGCGeometry ogcGeom1, OGCGeometry ogcGeom2) %7B%0A%09%09LogUtils.Log_InternalError(LOG, %22ST_Intersection: work around null%22);%0A%09%09Geometry esriGeom1 = ogcGeom1.getEsriGeometry(),%0A%09%09%09esriGeom2 = ogcGeom2.getEsriGeometry();%0A%09%09Geometry commonEsri = GeometryEngine.intersect(esriGeom1, esriGeom2,%0A%09%09%09%09%09%09%09%09%09%09%09%09%09   ogcGeom1.getEsriSpatialReference());%0A%09%09return OGCGeometry.createFromEsriGeometry(commonEsri,%0A%09%09%09%09%09%09%09%09%09%09%09%09  ogcGeom1.getEsriSpatialReference());
+return GeometryUtils.geometryToEsriShapeBytesWritable(commonGeom);%0A%09%09%7D catch (Exception e) %7B%0A%09%09    LogUtils.Log_InternalError(LOG, %22ST_Intersection: %22 + e);%0A%09%09    return null;%0A%09%09%7D
 %0A%09%7D%0A

streamline per updated geometry-api