package er.neo4jadaptor.query.neo4j_eval.evaluators;
import java.util.Iterator;
import org.neo4j.graphdb.PropertyContainer;
import er.neo4jadaptor.query.expression.sentence.operators.ComparisonOperator;
import er.neo4jadaptor.query.neo4j_eval.Cost;
import er.neo4jadaptor.query.neo4j_eval.retrievers.Retriever;
/**
* Checks if a some of the candidate's property/relationship value is equal/greater/less than some value.
* To retrieve this property or relationship value it utilizes {@link er.neo4jadaptor.query.neo4j_eval.retrievers.Retriever}.
*
* @author Jedrzej Sobanski
*
* @param <T>
*/
public class Comparison <T extends PropertyContainer> implements Evaluator<T> {
private final Retriever<T, ?> valueRetriever;
private final ComparisonOperator operator;
private final Object rValue;
/**
*
* @param valueRetriever retrieved to get the value from each candidate
* @param operator comparison operator
* @param value value to compare to
*/
public Comparison(Retriever<T, ?> valueRetriever, ComparisonOperator operator, Object value) {
this.valueRetriever = valueRetriever;
this.operator = operator;
this.rValue = value;
}
@SuppressWarnings("unchecked")
private static int compare(Comparable<?> left, Object right) {
if (left == right) {
return 0;
} else if (left == null) {
if (right != null) {
return -1;
} else {
return 1;
}
} else if (right == null) {
if (left != null) {
return -1;
} else {
return 1;
}
}
// both are not-null at this point
if (left instanceof Number) {
// for number comparison convert both either to long or double
if (left instanceof Long || left instanceof Integer || left instanceof Byte || left instanceof Short) {
left = ((Number) left).longValue();
right = ((Number) right).longValue();
}
if (left instanceof Double || left instanceof Float) {
left = ((Number) left).doubleValue();
right = ((Number) right).doubleValue();
}
}
return ((Comparable) left).compareTo(right);
}
@SuppressWarnings("cast")
public boolean evaluate(T candidate) {
Iterator<?> lValues = valueRetriever.retrieve(candidate);
if (rValue == null && ! lValues.hasNext()) {
// if there are no values on the right hand side then it counts as null
return true;
}
while (lValues.hasNext()) {
Object lValue = lValues.next();
final boolean comparisonResult;
switch (operator) {
case EQUAL:
comparisonResult = compare((Comparable<?>) lValue, rValue) == 0;
break;
case GREATER_THAN:
comparisonResult = compare((Comparable<?>) lValue, rValue) > 0;
break;
case GREATER_OR_EQUAL:
comparisonResult = compare((Comparable<?>) lValue, rValue) >= 0;
break;
case LESS_THAN:
comparisonResult = compare((Comparable<?>) lValue, rValue) < 0;
break;
case LESS_OR_EQUAL:
comparisonResult = compare((Comparable<?>) lValue, rValue) <= 0;
break;
default:
throw new UnsupportedOperationException();
}
if (comparisonResult) {
// terminate early
return true;
}
}
return false;
}
public Cost getCost() {
return valueRetriever.getCost();
}
@Override
public String toString() {
return valueRetriever.toString() + operator + rValue;
}
}