/*
* Copyright 2000-2013 Enonic AS
* http://www.enonic.com/license
*/
package com.enonic.cms.core.content.index.queryexpression;
import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.joda.time.Period;
import org.joda.time.ReadableDateTime;
public class DateCompareEvaluator
extends QueryEvaluatorAdapter
{
public Object evaluate( CompareExpr expr )
{
Expression left = (Expression) expr.getLeft().evaluate( this );
Expression right = (Expression) expr.getRight().evaluate( this );
if ( ( right instanceof ValueExpr ) && ( (ValueExpr) right ).isDate() )
{
return createFixedDateCompare( expr.getOperator(), left, (ValueExpr) right );
}
else
{
boolean expressionsOfTypeDate = ( isDateField( left ) && isValidDateString( right ) ) || isDateValue( right );
if ( expressionsOfTypeDate && isExpressionOperatorValidForDates( expr ) )
{
CompareExpr cexpr = new CompareExpr( expr.getOperator(), left,
new FunctionExpr( "date", new ArrayExpr( new ValueExpr[]{(ValueExpr) right} ) ) );
QueryExpr expression = new QueryExpr( cexpr, null );
expression = (QueryExpr)expression.evaluate( new FunctionEvaluator() );
expression = (QueryExpr)expression.evaluate( new DateCompareEvaluator() );
return expression.getExpr();
}
return new CompareExpr( expr.getOperator(), left, right );
}
}
private boolean isDateField( Expression expr )
{
return ( expr instanceof FieldExpr ) && ( (FieldExpr) expr ).isDateField();
}
private boolean isValidDateString( Expression expr )
{
return ( expr instanceof ValueExpr ) && ( (ValueExpr) expr ).isValidDateString();
}
private boolean isDateValue( Expression expr )
{
return ( expr instanceof ValueExpr ) && ( (ValueExpr) expr ).isDate();
}
private boolean isExpressionOperatorValidForDates( CompareExpr expr )
{
int operator = expr.getOperator();
return ( operator != CompareExpr.LIKE ) && ( operator != CompareExpr.NOT_LIKE ) &&
( operator != CompareExpr.IN ) && ( operator != CompareExpr.NOT_IN );
}
private Expression createFixedDateCompare( int op, Expression left, ValueExpr right )
{
if ( op == CompareExpr.EQ )
{
return createFixedDateEq( left, right );
}
else if ( op == CompareExpr.LTE )
{
return createFixedDateLte( left, right );
}
else
{
return new CompareExpr( op, left, right );
}
}
private Expression createFixedDateEq( Expression left, ValueExpr right )
{
ReadableDateTime date = (ReadableDateTime) right.getValue();
if ( date instanceof DateMidnight )
{
CompareExpr lowerBound = new CompareExpr( CompareExpr.GTE, left, new ValueExpr( createLowerBoundDate( (DateMidnight) date ) ) );
CompareExpr upperBound = new CompareExpr( CompareExpr.LTE, left, new ValueExpr( createUpperBoundDate( (DateMidnight) date ) ) );
return new LogicalExpr( LogicalExpr.AND, lowerBound, upperBound );
}
return new CompareExpr( CompareExpr.EQ, left, right );
}
private Expression createFixedDateLte( Expression left, ValueExpr right )
{
ReadableDateTime date = (ReadableDateTime) right.getValue();
if ( date instanceof DateMidnight )
{
right = new ValueExpr( createUpperBoundDate( (DateMidnight) date ) );
}
return new CompareExpr( CompareExpr.LTE, left, right );
}
private ReadableDateTime createLowerBoundDate( DateMidnight date )
{
return date.toDateTime();
}
private ReadableDateTime createUpperBoundDate( DateMidnight date )
{
DateTime dateMidnight = date.toDateTime();
return dateMidnight.plus( new Period( 23, 59, 59, 999 ) );
}
}