//Dstl (c) Crown Copyright 2017
package uk.gov.dstl.baleen.uima.utils;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import org.apache.uima.fit.util.JCasUtil;
import org.apache.uima.jcas.tcas.Annotation;
/**
* Helper utilities in the vein of JCasUtils for dealing with JCas annotations.
*/
public final class AnnotationUtils {
private AnnotationUtils() {
// Singleton
}
/**
* Gets the first annotation which is covered (below) by the provided annotation.
*
* @param <T>
* the generic type of annotation
* @param clazz
* the class fo the annotation
* @param annotation
* the annotation instance which covers the desired
* @return the covered annotation (as an optional)
*/
public static <T extends Annotation> Optional<T> getSingleCovered(final Class<T> clazz,
final Annotation annotation) {
final List<T> list = JCasUtil.selectCovered(clazz, annotation);
if (list.isEmpty()) {
return Optional.empty();
} else {
return Optional.of(list.get(0));
}
}
/**
* Filter only the top level annotations (that is remove all the covered annotations).
*
* This is not too efficient, but is should work with any ordering.
*
* @param <T>
* the generic type of the annotation
* @param annotations
* the annotations to filter
* @return a new list of containing just the top level (uncovered) annotations
*/
public static <T extends Annotation> List<T> filterToTopLevelAnnotations(final Collection<T> annotations) {
final List<T> topLevel = new LinkedList<>();
for (final T a : annotations) {
boolean covered = false;
for (final T b : annotations) {
if (!a.equals(b) && b.getBegin() <= a.getBegin() && a.getEnd() <= b.getEnd()) {
covered = true;
break;
}
}
if (!covered) {
topLevel.add(a);
}
}
return topLevel;
}
/**
* Checks if an annotation is in between the source and target entities (in the sentence).
*
* The order of source and target is not important (target could be earlier in the sentence than
* source).
*
* Overlapping annotations are not considered between.
*
* @param between
* the entity to test if in the middle
* @param source
* an entity which will be on the left/right
* @param target
* an entity which will be on the left/right
* @return true, if is in between
*/
public static boolean isInBetween(final Annotation between, final Annotation source, final Annotation target) {
int left;
int right;
if (source.getEnd() <= target.getBegin()) {
left = source.getEnd();
right = target.getBegin();
} else {
left = target.getEnd();
right = source.getBegin();
}
return left <= between.getBegin() && between.getEnd() <= right;
}
}