/** Get the link following the current link. */
 private AnnotationFS getNextLink(AnnotationFS aLink) {
   return (AnnotationFS)
       aLink.getFeatureValue(aLink.getType().getFeatureByBaseName(linkNextFeatureName));
 }
  /**
   * Add annotations from the CAS, which is controlled by the window size, to the brat response
   * {@link GetDocumentResponse}
   *
   * @param aJcas The JCAS object containing annotations
   * @param aResponse A brat response containing annotations in brat protocol
   * @param aBratAnnotatorModel Data model for brat annotations
   * @param aColoringStrategy the coloring strategy to render this layer (ignored)
   */
  @Override
  public void render(
      JCas aJcas,
      List<AnnotationFeature> aFeatures,
      GetDocumentResponse aResponse,
      BratAnnotatorModel aBratAnnotatorModel,
      ColoringStrategy aColoringStrategy) {
    // Get begin and end offsets of window content
    int windowBegin =
        BratAjaxCasUtil.selectByAddr(
                aJcas, Sentence.class, aBratAnnotatorModel.getSentenceAddress())
            .getBegin();
    int windowEnd =
        BratAjaxCasUtil.selectByAddr(
                aJcas,
                Sentence.class,
                BratAjaxCasUtil.getLastSentenceAddressInDisplayWindow(
                    aJcas,
                    aBratAnnotatorModel.getSentenceAddress(),
                    aBratAnnotatorModel.getPreferences().getWindowSize()))
            .getEnd();

    // Find the features for the arc and span labels - it is possible that we do not find a
    // feature for arc/span labels because they may have been disabled.
    AnnotationFeature spanLabelFeature = null;
    AnnotationFeature arcLabelFeature = null;
    for (AnnotationFeature f : aFeatures) {
      if (WebAnnoConst.COREFERENCE_TYPE_FEATURE.equals(f.getName())) {
        spanLabelFeature = f;
      }
      if (WebAnnoConst.COREFERENCE_RELATION_FEATURE.equals(f.getName())) {
        arcLabelFeature = f;
      }
    }
    // At this point arc and span feature labels must have been found! If not, the later code
    // will crash.

    Type chainType = getAnnotationType(aJcas.getCas());
    Feature chainFirst = chainType.getFeatureByBaseName(chainFirstFeatureName);

    int colorIndex = 0;
    // Iterate over the chains
    for (FeatureStructure chainFs : selectFS(aJcas.getCas(), chainType)) {
      AnnotationFS linkFs = (AnnotationFS) chainFs.getFeatureValue(chainFirst);
      AnnotationFS prevLinkFs = null;

      // Every chain is supposed to have a different color
      String color =
          ColoringStrategy.PALETTE_NORMAL_FILTERED[
              colorIndex % ColoringStrategy.PALETTE_NORMAL_FILTERED.length];
      // The color index is updated even for chains that have no visible links in the current
      // window because we would like the chain color to be independent of visibility. In
      // particular the color of a chain should not change when switching pages/scrolling.
      colorIndex++;

      // Iterate over the links of the chain
      while (linkFs != null) {
        Feature linkNext = linkFs.getType().getFeatureByBaseName(linkNextFeatureName);
        AnnotationFS nextLinkFs = (AnnotationFS) linkFs.getFeatureValue(linkNext);

        // Is link after window? If yes, we can skip the rest of the chain
        if (linkFs.getBegin() >= windowEnd) {
          break; // Go to next chain
        }

        // Is link before window? We only need links that being within the window and that
        // end within the window
        if (!(linkFs.getBegin() >= windowBegin) && (linkFs.getEnd() <= windowEnd)) {
          // prevLinkFs remains null until we enter the window
          linkFs = nextLinkFs;
          continue; // Go to next link
        }

        String bratTypeName = TypeUtil.getBratTypeName(this);

        // Render span
        {
          String bratLabelText =
              TypeUtil.getBratLabelText(
                  this,
                  linkFs,
                  (spanLabelFeature != null) ? asList(spanLabelFeature) : Collections.EMPTY_LIST);
          Offsets offsets =
              new Offsets(linkFs.getBegin() - windowBegin, linkFs.getEnd() - windowBegin);

          aResponse.addEntity(
              new Entity(
                  BratAjaxCasUtil.getAddr(linkFs), bratTypeName, offsets, bratLabelText, color));
        }

        // Render arc (we do this on prevLinkFs because then we easily know that the current
        // and last link are within the window ;)
        if (prevLinkFs != null) {
          String bratLabelText = null;

          if (linkedListBehavior && arcLabelFeature != null) {
            // Render arc label
            bratLabelText = TypeUtil.getBratLabelText(this, prevLinkFs, asList(arcLabelFeature));
          } else {
            // Render only chain type
            bratLabelText = TypeUtil.getBratLabelText(this, prevLinkFs, Collections.EMPTY_LIST);
          }

          List<Argument> argumentList =
              asList(
                  new Argument("Arg1", BratAjaxCasUtil.getAddr(prevLinkFs)),
                  new Argument("Arg2", BratAjaxCasUtil.getAddr(linkFs)));

          aResponse.addRelation(
              new Relation(
                  BratAjaxCasUtil.getAddr(prevLinkFs),
                  bratTypeName,
                  argumentList,
                  bratLabelText,
                  color));
        }

        //                if (BratAjaxCasUtil.isSame(linkFs, nextLinkFs)) {
        //                    log.error("Loop in CAS detected, aborting rendering of chains");
        //                    break;
        //                }

        prevLinkFs = linkFs;
        linkFs = nextLinkFs;
      }
    }
  }