//Dstl (c) Crown Copyright 2017
package uk.gov.dstl.baleen.uima.utils.select;
import java.util.ArrayList;
import java.util.Collection;
import org.apache.commons.lang.StringUtils;
/**
* Base combining (and, or) evaluator.
*/
abstract class CombiningEvaluator<T> extends Evaluator<T> {
final ArrayList<Evaluator<T>> evaluators;
int num = 0;
/**
* Construct an empty combining evaluator
*/
CombiningEvaluator() {
super();
evaluators = new ArrayList<>();
}
/**
* Construct a combining evaluator over the given evaluators.
*
* @param evaluators the evaluators to combine
*/
CombiningEvaluator(Collection<Evaluator<T>> evaluators) {
this();
this.evaluators.addAll(evaluators);
updateNumEvaluators();
}
/**
* Construct a combining evaluator over the given evaluators.
*
* @param left the first evaluator to conbine
* @param right the second evaluator to combine
*/
CombiningEvaluator(Evaluator<T> left, Evaluator<T> right) {
this();
this.evaluators.add(left);
this.evaluators.add(right);
updateNumEvaluators();
}
protected Evaluator<T> rightMostEvaluator() {
return num > 0 ? evaluators.get(num - 1) : null;
}
protected void replaceRightMostEvaluator(Evaluator<T> replacement) {
evaluators.set(num - 1, replacement);
}
protected void updateNumEvaluators() {
// used so we don't need to bash on size() for every match test
num = evaluators.size();
}
/**
* And combining evaluator.
* <p>
* All evaluators must pass
*
*/
static final class And<T> extends CombiningEvaluator<T> {
/**
* Construct an AND evaluator over the given evaluators.
*
* @param evaluators the evaluators to AND
*/
And(Collection<Evaluator<T>> evaluators) {
super(evaluators);
}
/**
* Construct an AND evaluator over the given evaluators.
*
* @param left the first evaluator to AND
* @param right the second evaluator to AND
*/
And(Evaluator<T> left, Evaluator<T> right) {
super(left, right);
}
@Override
public boolean matches(Node<T> root, Node<T> node) {
for (int i = 0; i < num; i++) {
Evaluator<T> s = evaluators.get(i);
if (!s.matches(root, node)) {
return false;
}
}
return true;
}
@Override
public String toString() {
return StringUtils.join(evaluators, " ");
}
}
/**
* And combining evaluator.
* <p>
* Any of the evaluators must pass.
* <p>
* This is a short cutting orperation, so the right evaluator will not be evaluated if the left evaluator is satisfied.
*
*/
static final class Or<T> extends CombiningEvaluator<T> {
/**
* Create a new Or evaluator. The initial evaluators are ANDed together and used as the first
* clause of the OR.
*
* @param evaluators initial OR clause (these are wrapped into an AND evaluator).
*/
Or(Collection<Evaluator<T>> evaluators) {
super();
if (num > 1) {
this.evaluators.add(new And<>(evaluators));
} else {
this.evaluators.addAll(evaluators);
}
updateNumEvaluators();
}
/**
* Create a new empty Or evaluator.
*
*/
Or() {
super();
}
/**
* Create a new Or evaluator with the given leaf and right parts of the clause.
*
* @param left the left clause to evaluate (first)
* @param right the right clause to evaluate
*/
Or(Evaluator<T> left, Evaluator<T> right) {
super(left, right);
}
/**
* Add an evaluator to the or clause
*
* @param e the evaluator to add
*/
public void add(Evaluator<T> e) {
evaluators.add(e);
updateNumEvaluators();
}
@Override
public boolean matches(Node<T> root, Node<T> node) {
for (int i = 0; i < num; i++) {
Evaluator<T> s = evaluators.get(i);
if (s.matches(root, node)) {
return true;
}
}
return false;
}
@Override
public String toString() {
return String.format(":or%s", evaluators);
}
}
}