package er.neo4jadaptor.query.neo4j_eval.evaluators; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import org.neo4j.graphdb.PropertyContainer; import er.neo4jadaptor.query.neo4j_eval.Cost; import er.neo4jadaptor.query.neo4j_eval.HasCost; /** * Evaluates candidates to match some or all of some other {@link Evaluator}s building something * equivalent to logical sentences. * * @author Jedrzej Sobanski * * @param <T> */ public final class BoolEvaluator <T extends PropertyContainer> implements Evaluator<T> { private final List<Evaluator<T>> evals = new ArrayList<Evaluator<T>>(); private final boolean interruptOn; public static <T extends PropertyContainer> Evaluator<T> and(Iterable<Evaluator<T>> evaluators) { return new BoolEvaluator<>(evaluators, false); } public static <T extends PropertyContainer> Evaluator<T> or(Iterable<Evaluator<T>> evaluators) { return new BoolEvaluator<>(evaluators, true); } public Comparator<HasCost> COST_COMPARATOR = new Comparator<HasCost>() { public int compare(HasCost h1, HasCost h2) { return h1.getCost().compareTo(h2.getCost()); } }; @SuppressWarnings("unchecked") private boolean canBeFlattened(Evaluator<T> e) { return e instanceof BoolEvaluator && ((BoolEvaluator<T>) e).interruptOn == interruptOn; } private BoolEvaluator(Iterable<Evaluator<T>> evaluators, boolean interruptOn) { for (Evaluator<T> e : evaluators) { if (canBeFlattened(e)) { // if one of components is the same evaluator then add just its subcomponents (flatten) BoolEvaluator<T> be = (BoolEvaluator<T>) e; this.evals.addAll(be.evals); } else { this.evals.add(e); } } // start with the lowest cost operations Collections.sort(this.evals, COST_COMPARATOR); this.interruptOn = interruptOn; } public boolean evaluate(T candidate) { for (Evaluator<T> e : evals) { if (e.evaluate(candidate) == interruptOn) { return interruptOn; } } return ! interruptOn; } public Cost getCost() { return Cost.getHighest(evals); } @Override public String toString() { StringBuilder b = new StringBuilder(); Iterator<Evaluator<T>> it = evals.iterator(); if (it.hasNext()) { b.append(it.next()); } while (it.hasNext()) { if (interruptOn == false) { b.append(" and "); } else { b.append(" or "); } b.append(it.next()); } return b.toString(); } }