/** Performs name finding on the given cas object. */
  public final void process(CAS cas) {

    if (isRemoveExistingAnnotations) {
      final AnnotationComboIterator sentenceNameCombo =
          new AnnotationComboIterator(cas, mSentenceType, mNameType);

      List<AnnotationFS> removeAnnotations = new LinkedList<AnnotationFS>();
      for (AnnotationIteratorPair annotationIteratorPair : sentenceNameCombo) {
        for (AnnotationFS nameAnnotation : annotationIteratorPair.getSubIterator()) {
          removeAnnotations.add(nameAnnotation);
        }
      }

      for (AnnotationFS annotation : removeAnnotations) {
        cas.removeFsFromIndexes(annotation);
      }
    }

    final AnnotationComboIterator sentenceTokenCombo =
        new AnnotationComboIterator(cas, mSentenceType, mTokenType);

    for (AnnotationIteratorPair annotationIteratorPair : sentenceTokenCombo) {

      final List<AnnotationFS> sentenceTokenAnnotationList = new LinkedList<AnnotationFS>();

      final List<String> sentenceTokenList = new LinkedList<String>();

      for (AnnotationFS tokenAnnotation : annotationIteratorPair.getSubIterator()) {

        sentenceTokenAnnotationList.add(tokenAnnotation);

        sentenceTokenList.add(tokenAnnotation.getCoveredText());
      }

      Span[] names =
          find(cas, (String[]) sentenceTokenList.toArray(new String[sentenceTokenList.size()]));

      AnnotationFS nameAnnotations[] = new AnnotationFS[names.length];

      for (int i = 0; i < names.length; i++) {

        int startIndex =
            ((AnnotationFS) sentenceTokenAnnotationList.get(names[i].getStart())).getBegin();

        int endIndex =
            ((AnnotationFS) sentenceTokenAnnotationList.get(names[i].getEnd() - 1)).getEnd();

        nameAnnotations[i] = cas.createAnnotation(mNameType, startIndex, endIndex);

        cas.getIndexRepository().addFS(nameAnnotations[i]);
      }

      postProcessAnnotations(names, nameAnnotations);
    }

    documentDone(cas);
  }
  /**
   * Removes all annotations of type removeAnnotationType which are contained by annotations of type
   * containerAnnotationType.
   *
   * @param cas
   * @param containerAnnotationType
   * @param removeAnnotationType
   */
  public static void removeAnnotations(
      CAS cas, AnnotationFS containerAnnotation, Type removeAnnotationType) {

    FSIndex<AnnotationFS> allRemoveAnnotations = cas.getAnnotationIndex(removeAnnotationType);

    ContainingConstraint containingConstraint = new ContainingConstraint(containerAnnotation);

    Iterator<AnnotationFS> containingTokens =
        cas.createFilteredIterator(allRemoveAnnotations.iterator(), containingConstraint);

    Collection<AnnotationFS> removeAnnotations = new LinkedList<AnnotationFS>();

    while (containingTokens.hasNext()) {
      removeAnnotations.add(containingTokens.next());
    }

    for (Iterator<AnnotationFS> it = removeAnnotations.iterator(); it.hasNext(); ) {
      cas.removeFsFromIndexes(it.next());
    }
  }