package net.canadensys.query.interpreter;

import java.util.ArrayList;
import java.util.List;

import net.canadensys.databaseutils.PostgisUtils;
import net.canadensys.query.QueryOperatorEnum;
import net.canadensys.query.SearchQueryPart;
import net.canadensys.query.SearchableField;

import org.apache.commons.lang3.tuple.Pair;
import org.apache.log4j.Logger;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;

/**
 * Interprets a SearchQueryPart representing a geospatial query where we target a polygon. 
 * @author canadensys
 *
 */
public class InsidePolygonFieldInterpreter implements QueryPartInterpreter{
	
	//get log4j handler
	private static final Logger LOGGER = Logger.getLogger(InsidePolygonFieldInterpreter.class);
	
	/**
	 * Needs at least one related field and type should not be specified.
	 */
	@Override
	public boolean canHandleSearchableField(SearchableField searchableField) {
		return (searchableField.getRelatedFields() != null && 
				searchableField.getRelatedFields().size() >= 1 &&
				searchableField.getType() == null);
	}
	
	@Override
	public boolean canHandleSearchQueryPart(SearchQueryPart searchQueryPart) {
		
		if(!canHandleSearchableField(searchQueryPart.getSearchableField()) || 
			!QueryOperatorEnum.IN.equals(searchQueryPart.getOp())){
			return false;
		}
		
		//validate that the parsedValue are in the right type(class)
		List<String> valueList = searchQueryPart.getValueList();
		Object parsedValue = null;
		//get the parsed value of the first SearchableField only (e.g. the_geom)
		String searchableFieldKey = searchQueryPart.getSearchableField().getRelatedFields().get(0);
		for(String currValue : valueList){
			parsedValue = searchQueryPart.getParsedValue(currValue, searchableFieldKey);
			if(parsedValue instanceof Pair){
				Pair<?,?> a = (Pair<?,?>)parsedValue;
				if(!String.class.equals(a.getLeft().getClass()) ||
						!String.class.equals(a.getRight().getClass())){
					return false;
				}
			}
			else{
				return false;
			}
		}
		return true;
	}
	
	@Override
	public Criterion toCriterion(SearchQueryPart searchQueryPart) {
		String sqlCmd = toSQL(searchQueryPart);
		if(sqlCmd == null){
			return null;
		}
		return Restrictions.sqlRestriction(sqlCmd);
	}

	@SuppressWarnings("unchecked")
	@Override
	public String toSQL(SearchQueryPart searchQueryPart) {
		
		if(!canHandleSearchQueryPart(searchQueryPart)){
			LOGGER.error("Can't handle QueryPart : " + searchQueryPart);
			return null;
		}	
		
		List<Pair<String,String>> polygon = new ArrayList<Pair<String,String>>();
		SearchableField searchableField = searchQueryPart.getSearchableField();
		
		List<String> valueList = searchQueryPart.getValueList();
		Object parsedValue = null;
		for(String currValue : valueList){
			parsedValue = searchQueryPart.getParsedValue(currValue);
			polygon.add((Pair<String,String>)parsedValue);
		}
		String geomColumn = searchableField.getRelatedField();
		return PostgisUtils.getInsidePolygonSQLClause(geomColumn, polygon, true);
	}
}

@@ -276,16 +276,62 @@
 Field;%0A%0A
+import org.apache.commons.lang3.BooleanUtils;%0A
 import o
@@ -580,17 +580,158 @@
 polygon.
- 
+%0A * If the polygon is crossing the IDL, make sure to add the hint IS_CROSSING_IDL_HINT so the %0A * interpreter can use the shifted_geom column.
 %0A * @aut
@@ -946,16 +946,184 @@
 ass);%0A%09%0A
+%09public static final String IS_CROSSING_IDL_HINT = %22isCrossingIDL%22;%0A%09public static final int GEOM_FIELD_IDX = 0;%0A%09public static final int SHIFTED_GEOM_FIELD_IDX = 1;%0A%09%0A
 %09/**%0A%09 *
@@ -2000,17 +2000,30 @@
 s().get(
-0
+GEOM_FIELD_IDX
 );%0A%09%09for
@@ -3009,16 +3009,91 @@
 ld();%0A%09%09
+String geomColumn = searchableField.getRelatedFields().get(GEOM_FIELD_IDX);
 %0A%09%09List%3C
@@ -3136,32 +3136,35 @@
 getValueList();%0A
+%09%09%0A
 %09%09Object parsedV
@@ -3266,24 +3266,35 @@
 ue(currValue
+,geomColumn
 );%0A%09%09%09polygo
@@ -3340,24 +3340,191 @@
 ;%0A%09%09%7D%0A%09%09
-String g
+%0A%09%09//If the polygon is crossing the IDL, we use the shiftedGeomColumn.%0A%09%09if(BooleanUtils.toBoolean((Boolean)searchQueryPart.getHint(IS_CROSSING_IDL_HINT)))%7B%0A%09%09%09String shiftedG
 eomColum
@@ -3558,20 +3558,50 @@
 tedField
+s
 ()
+.get(SHIFTED_GEOM_FIELD_IDX)
 ;%0A
+%09
 %09%09return
@@ -3640,17 +3640,24 @@
 LClause(
-g
+shiftedG
 eomColum
@@ -3675,13 +3675,94 @@
  true);%0A
+%09%09%7D%0A%09%09return PostgisUtils.getInsidePolygonSQLClause(geomColumn, polygon, false);%0A
 %09%7D%0A%7D%0A

use new SearchQueryPart hints to check IDL