blob: 0893e4de0fa8eca98afd30eb5170f4e59396abfb [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.uima.ruta.condition;
import java.util.ArrayList;
import java.util.List;
import org.apache.uima.cas.FSIterator;
import org.apache.uima.cas.Type;
import org.apache.uima.cas.text.AnnotationFS;
import org.apache.uima.ruta.RutaStream;
import org.apache.uima.ruta.expression.bool.IBooleanExpression;
import org.apache.uima.ruta.expression.number.INumberExpression;
import org.apache.uima.ruta.expression.type.ITypeExpression;
import org.apache.uima.ruta.rule.EvaluatedCondition;
import org.apache.uima.ruta.rule.MatchContext;
import org.apache.uima.ruta.rule.RuleElement;
import org.apache.uima.ruta.rule.RutaRuleElement;
import org.apache.uima.ruta.type.RutaBasic;
import org.apache.uima.ruta.visitor.InferenceCrowd;
public class PositionCondition extends TypeSentiveCondition {
private final INumberExpression position;
private final IBooleanExpression relative;
public PositionCondition(ITypeExpression type, INumberExpression position,
IBooleanExpression relative) {
super(type);
this.position = position;
this.relative = relative;
}
@Override
public EvaluatedCondition eval(MatchContext context, RutaStream stream, InferenceCrowd crowd) {
AnnotationFS annotation = context.getAnnotation();
RuleElement element = context.getElement();
Type t = type.getType(context, stream);
RutaBasic beginAnchor = stream.getBeginAnchor(annotation.getBegin());
RutaBasic endAnchor = stream.getEndAnchor(annotation.getEnd());
if (beginAnchor == null || endAnchor == null || !beginAnchor.isPartOf(t)
|| !endAnchor.isPartOf(t)) {
return new EvaluatedCondition(this, false);
}
boolean relatively = relative == null ? true : relative.getBooleanValue(context, stream);
FSIterator<AnnotationFS> iterator = stream.getCas().getAnnotationIndex(t).iterator(beginAnchor);
if (!iterator.isValid()) {
iterator.moveToNext();
}
if (!iterator.isValid()) {
iterator.moveToLast();
}
AnnotationFS window = null;
while (iterator.isValid()) {
AnnotationFS annotationFS = iterator.get();
if (annotationFS.getBegin() <= annotation.getBegin()
&& annotationFS.getEnd() >= annotation.getEnd()) {
window = annotationFS;
break;
}
iterator.moveToPrevious();
}
List<Type> targetTypes = new ArrayList<Type>();
if (element instanceof RutaRuleElement) {
RutaRuleElement re = (RutaRuleElement) element;
targetTypes.addAll(re.getMatcher().getTypes(element.getParent(), stream));
} else {
targetTypes.add(annotation.getType());
}
if (window == null) {
return new EvaluatedCondition(this, false);
}
int integerValue = position.getIntegerValue(context, stream);
if (relatively) {
int counter = 0;
List<RutaBasic> inWindow = stream.getBasicsInWindow(window);
for (RutaBasic each : inWindow) {
if (beginsWith(each, targetTypes)) {
counter++;
if (counter == integerValue) {
if (each.getBegin() == beginAnchor.getBegin()) {
return new EvaluatedCondition(this, true);
} else {
return new EvaluatedCondition(this, false);
}
} else if (counter > integerValue) {
return new EvaluatedCondition(this, false);
}
}
}
return new EvaluatedCondition(this, false);
} else {
int counter = 0;
List<RutaBasic> inWindow = stream.getBasicsInWindow(window);
for (RutaBasic each : inWindow) {
counter++;
boolean beginsWith = beginsWith(each, targetTypes);
if (each.getBegin() == beginAnchor.getBegin() && beginsWith && counter == integerValue) {
return new EvaluatedCondition(this, true);
} else if (counter > integerValue) {
return new EvaluatedCondition(this, false);
}
}
return new EvaluatedCondition(this, false);
}
}
private boolean beginsWith(RutaBasic each, List<Type> targetTypes) {
for (Type type : targetTypes) {
if (each.beginsWith(type)) {
return true;
}
}
return false;
}
public INumberExpression getPosition() {
return position;
}
public IBooleanExpression getRelative() {
return relative;
}
}