Merge branch 'develop' into update_212_Dec_merge_with_21125_chamges
[jalview.git] / src / jalview / datamodel / AlignmentAnnotation.java
index 0f7883e..4ebb27f 100755 (executable)
  */
 package jalview.datamodel;
 
-import jalview.analysis.Rna;
-import jalview.analysis.SecStrConsensus.SimpleBP;
-import jalview.analysis.WUSSParseException;
-
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
 
+import jalview.analysis.Rna;
+import jalview.analysis.SecStrConsensus.SimpleBP;
+import jalview.analysis.WUSSParseException;
+
 /**
  * DOCUMENT ME!
  * 
@@ -93,6 +95,146 @@ public class AlignmentAnnotation
    */
   private long invalidrnastruc = -2;
 
+  private double bitScore;
+
+  private double eValue;
+
+  /**
+   * Updates the _rnasecstr field Determines the positions that base pair and
+   * the positions of helices based on secondary structure from a Stockholm file
+   * 
+   * @param rnaAnnotation
+   */
+  private void _updateRnaSecStr(CharSequence rnaAnnotation)
+  {
+    try
+    {
+      _rnasecstr = Rna.getHelixMap(rnaAnnotation);
+      invalidrnastruc = -1;
+    } catch (WUSSParseException px)
+    {
+      // DEBUG System.out.println(px);
+      invalidrnastruc = px.getProblemPos();
+    }
+    if (invalidrnastruc > -1)
+    {
+      return;
+    }
+
+    if (_rnasecstr != null && _rnasecstr.length > 0)
+    {
+      // show all the RNA secondary structure annotation symbols.
+      isrna = true;
+      showAllColLabels = true;
+      scaleColLabel = true;
+      _markRnaHelices();
+    }
+    // System.out.println("featuregroup " + _rnasecstr[0].getFeatureGroup());
+
+  }
+
+  private void _markRnaHelices()
+  {
+    int mxval = 0;
+    // Figure out number of helices
+    // Length of rnasecstr is the number of pairs of positions that base pair
+    // with each other in the secondary structure
+    for (int x = 0; x < _rnasecstr.length; x++)
+    {
+
+      /*
+       * System.out.println(this.annotation._rnasecstr[x] + " Begin" +
+       * this.annotation._rnasecstr[x].getBegin());
+       */
+      // System.out.println(this.annotation._rnasecstr[x].getFeatureGroup());
+      int val = 0;
+      try
+      {
+        val = Integer.valueOf(_rnasecstr[x].getFeatureGroup());
+        if (mxval < val)
+        {
+          mxval = val;
+        }
+      } catch (NumberFormatException q)
+      {
+      }
+      ;
+
+      annotations[_rnasecstr[x].getBegin()].value = val;
+      annotations[_rnasecstr[x].getEnd()].value = val;
+
+      // annotations[_rnasecstr[x].getBegin()].displayCharacter = "" + val;
+      // annotations[_rnasecstr[x].getEnd()].displayCharacter = "" + val;
+    }
+    setScore(mxval);
+  }
+
+  /**
+   * Get the RNA Secondary Structure SequenceFeature Array if present
+   */
+  public SequenceFeature[] getRnaSecondaryStructure()
+  {
+    return this._rnasecstr;
+  }
+
+  /**
+   * Check the RNA Secondary Structure is equivalent to one in given
+   * AlignmentAnnotation param
+   */
+  public boolean rnaSecondaryStructureEquivalent(AlignmentAnnotation that)
+  {
+    return rnaSecondaryStructureEquivalent(that, true);
+  }
+
+  public boolean rnaSecondaryStructureEquivalent(AlignmentAnnotation that,
+          boolean compareType)
+  {
+    SequenceFeature[] thisSfArray = this.getRnaSecondaryStructure();
+    SequenceFeature[] thatSfArray = that.getRnaSecondaryStructure();
+    if (thisSfArray == null || thatSfArray == null)
+    {
+      return thisSfArray == null && thatSfArray == null;
+    }
+    if (thisSfArray.length != thatSfArray.length)
+    {
+      return false;
+    }
+    Arrays.sort(thisSfArray, new SFSortByEnd()); // probably already sorted
+                                                 // like this
+    Arrays.sort(thatSfArray, new SFSortByEnd()); // probably already sorted
+                                                 // like this
+    for (int i = 0; i < thisSfArray.length; i++)
+    {
+      SequenceFeature thisSf = thisSfArray[i];
+      SequenceFeature thatSf = thatSfArray[i];
+      if (compareType)
+      {
+        if (thisSf.getType() == null || thatSf.getType() == null)
+        {
+          if (thisSf.getType() == null && thatSf.getType() == null)
+          {
+            continue;
+          }
+          else
+          {
+            return false;
+          }
+        }
+        if (!thisSf.getType().equals(thatSf.getType()))
+        {
+          return false;
+        }
+      }
+      if (!(thisSf.getBegin() == thatSf.getBegin()
+              && thisSf.getEnd() == thatSf.getEnd()))
+      {
+        return false;
+      }
+    }
+    return true;
+
+  }
+
   /**
    * map of positions in the associated annotation
    */
@@ -180,274 +322,35 @@ public class AlignmentAnnotation
     }
     else if (string.equalsIgnoreCase("LINE_GRAPH"))
     {
-      return LINE_GRAPH;
-    }
-    else
-    {
-      return NO_GRAPH;
-    }
-  }
-
-  /**
-   * Creates a new AlignmentAnnotation object.
-   * 
-   * @param label
-   *          short label shown under sequence labels
-   * @param description
-   *          text displayed on mouseover
-   * @param annotations
-   *          set of positional annotation elements
-   */
-  public AlignmentAnnotation(String label, String description,
-          Annotation[] annotations)
-  {
-    setAnnotationId();
-    // always editable?
-    editable = true;
-    this.label = label;
-    this.description = description;
-    this.annotations = annotations;
-
-    validateRangeAndDisplay();
-  }
-
-  /**
-   * Copy constructor creates a new independent annotation row with the same
-   * associated sequenceRef
-   * 
-   * @param annotation
-   */
-  public AlignmentAnnotation(AlignmentAnnotation annotation)
-  {
-    setAnnotationId();
-    this.label = new String(annotation.label);
-    if (annotation.description != null)
-    {
-      this.description = new String(annotation.description);
-    }
-    this.graphMin = annotation.graphMin;
-    this.graphMax = annotation.graphMax;
-    this.graph = annotation.graph;
-    this.graphHeight = annotation.graphHeight;
-    this.graphGroup = annotation.graphGroup;
-    this.groupRef = annotation.groupRef;
-    this.editable = annotation.editable;
-    this.autoCalculated = annotation.autoCalculated;
-    this.hasIcons = annotation.hasIcons;
-    this.hasText = annotation.hasText;
-    this.height = annotation.height;
-    this.label = annotation.label;
-    this.padGaps = annotation.padGaps;
-    this.visible = annotation.visible;
-    this.centreColLabels = annotation.centreColLabels;
-    this.scaleColLabel = annotation.scaleColLabel;
-    this.showAllColLabels = annotation.showAllColLabels;
-    this.calcId = annotation.calcId;
-    if (annotation.properties != null)
-    {
-      properties = new HashMap<>();
-      for (Map.Entry<String, String> val : annotation.properties.entrySet())
-      {
-        properties.put(val.getKey(), val.getValue());
-      }
-    }
-    if (this.hasScore = annotation.hasScore)
-    {
-      this.score = annotation.score;
-    }
-    if (annotation.threshold != null)
-    {
-      threshold = new GraphLine(annotation.threshold);
-    }
-    Annotation[] ann = annotation.annotations;
-    if (annotation.annotations != null)
-    {
-      this.annotations = new Annotation[ann.length];
-      for (int i = 0; i < ann.length; i++)
-      {
-        if (ann[i] != null)
-        {
-          annotations[i] = new Annotation(ann[i]);
-          if (_linecolour != null)
-          {
-            _linecolour = annotations[i].colour;
-          }
-        }
-      }
-    }
-    if (annotation.sequenceRef != null)
-    {
-      this.sequenceRef = annotation.sequenceRef;
-      if (annotation.sequenceMapping != null)
-      {
-        Integer p = null;
-        sequenceMapping = new HashMap<>();
-        Iterator<Integer> pos = annotation.sequenceMapping.keySet()
-                .iterator();
-        while (pos.hasNext())
-        {
-          // could optimise this!
-          p = pos.next();
-          Annotation a = annotation.sequenceMapping.get(p);
-          if (a == null)
-          {
-            continue;
-          }
-          if (ann != null)
-          {
-            for (int i = 0; i < ann.length; i++)
-            {
-              if (ann[i] == a)
-              {
-                sequenceMapping.put(p, annotations[i]);
-              }
-            }
-          }
-        }
-      }
-      else
-      {
-        this.sequenceMapping = null;
-      }
-    }
-    // TODO: check if we need to do this: JAL-952
-    // if (this.isrna=annotation.isrna)
-    {
-      // _rnasecstr=new SequenceFeature[annotation._rnasecstr];
-    }
-    validateRangeAndDisplay(); // construct hashcodes, etc.
-  }
-
-  /**
-   * copy constructor with edit based on the hidden columns marked in colSel
-   * 
-   * @param alignmentAnnotation
-   * @param colSel
-   */
-  public AlignmentAnnotation(AlignmentAnnotation alignmentAnnotation,
-          HiddenColumns hidden)
-  {
-    this(alignmentAnnotation);
-    if (annotations == null)
-    {
-      return;
-    }
-    makeVisibleAnnotation(hidden);
-  }
-
-  /**
-   * Creates a new AlignmentAnnotation object.
-   * 
-   * @param label
-   *          DOCUMENT ME!
-   * @param description
-   *          DOCUMENT ME!
-   * @param annotations
-   *          DOCUMENT ME!
-   * @param min
-   *          DOCUMENT ME!
-   * @param max
-   *          DOCUMENT ME!
-   * @param winLength
-   *          DOCUMENT ME!
-   */
-  public AlignmentAnnotation(String label, String description,
-          Annotation[] annotations, float min, float max, int graphType)
-  {
-    setAnnotationId();
-    // graphs are not editable
-    editable = graphType == 0;
-
-    this.label = label;
-    this.description = description;
-    this.annotations = annotations;
-    graph = graphType;
-    graphMin = min;
-    graphMax = max;
-    validateRangeAndDisplay();
-  }
-
-  /**
-   * Score only annotation
-   * 
-   * @param label
-   * @param description
-   * @param score
-   */
-  public AlignmentAnnotation(String label, String description, double score)
-  {
-    this(label, description, null);
-    setScore(score);
-  }
-
-  /**
-   * Updates the _rnasecstr field Determines the positions that base pair and
-   * the positions of helices based on secondary structure from a Stockholm file
-   * 
-   * @param rnaAnnotation
-   */
-  private void _updateRnaSecStr(CharSequence rnaAnnotation)
-  {
-    try
-    {
-      _rnasecstr = Rna.getHelixMap(rnaAnnotation);
-      invalidrnastruc = -1;
-    } catch (WUSSParseException px)
-    {
-      // DEBUG System.out.println(px);
-      invalidrnastruc = px.getProblemPos();
-    }
-    if (invalidrnastruc > -1)
-    {
-      return;
-    }
-
-    if (_rnasecstr != null && _rnasecstr.length > 0)
-    {
-      // show all the RNA secondary structure annotation symbols.
-      isrna = true;
-      showAllColLabels = true;
-      scaleColLabel = true;
-      _markRnaHelices();
+      return LINE_GRAPH;
+    }
+    else
+    {
+      return NO_GRAPH;
     }
-    // System.out.println("featuregroup " + _rnasecstr[0].getFeatureGroup());
-
   }
 
-  private void _markRnaHelices()
+  /**
+   * Creates a new AlignmentAnnotation object.
+   * 
+   * @param label
+   *          short label shown under sequence labels
+   * @param description
+   *          text displayed on mouseover
+   * @param annotations
+   *          set of positional annotation elements
+   */
+  public AlignmentAnnotation(String label, String description,
+          Annotation[] annotations)
   {
-    int mxval = 0;
-    // Figure out number of helices
-    // Length of rnasecstr is the number of pairs of positions that base pair
-    // with each other in the secondary structure
-    for (int x = 0; x < _rnasecstr.length; x++)
-    {
-
-      /*
-       * System.out.println(this.annotation._rnasecstr[x] + " Begin" +
-       * this.annotation._rnasecstr[x].getBegin());
-       */
-      // System.out.println(this.annotation._rnasecstr[x].getFeatureGroup());
-      int val = 0;
-      try
-      {
-        val = Integer.valueOf(_rnasecstr[x].getFeatureGroup());
-        if (mxval < val)
-        {
-          mxval = val;
-        }
-      } catch (NumberFormatException q)
-      {
-      }
-      ;
-
-      annotations[_rnasecstr[x].getBegin()].value = val;
-      annotations[_rnasecstr[x].getEnd()].value = val;
+    setAnnotationId();
+    // always editable?
+    editable = true;
+    this.label = label;
+    this.description = description;
+    this.annotations = annotations;
 
-      // annotations[_rnasecstr[x].getBegin()].displayCharacter = "" + val;
-      // annotations[_rnasecstr[x].getEnd()].displayCharacter = "" + val;
-    }
-    setScore(mxval);
+    validateRangeAndDisplay();
   }
 
   /**
@@ -463,6 +366,7 @@ public class AlignmentAnnotation
     char firstChar = 0;
     for (int i = 0; i < annotations.length; i++)
     {
+      // DEBUG System.out.println(i + ": " + annotations[i]);
       if (annotations[i] == null)
       {
         continue;
@@ -470,27 +374,35 @@ public class AlignmentAnnotation
       if (annotations[i].secondaryStructure == 'H'
               || annotations[i].secondaryStructure == 'E')
       {
+        // DEBUG System.out.println( "/H|E/ '" +
+        // annotations[i].secondaryStructure + "'");
         hasIcons |= true;
       }
       else
       // Check for RNA secondary structure
       {
-        // System.out.println(annotations[i].secondaryStructure);
+        // DEBUG System.out.println( "/else/ '" +
+        // annotations[i].secondaryStructure + "'");
         // TODO: 2.8.2 should this ss symbol validation check be a function in
         // RNA/ResidueProperties ?
+        // allow for DSSP extended code:
+        // https://www.wikidoc.org/index.php/Secondary_structure#The_DSSP_code
+        // GHITEBS as well as C and X (for missing?)
         if (annotations[i].secondaryStructure == '('
                 || annotations[i].secondaryStructure == '['
                 || annotations[i].secondaryStructure == '<'
                 || annotations[i].secondaryStructure == '{'
                 || annotations[i].secondaryStructure == 'A'
-                || annotations[i].secondaryStructure == 'B'
-                || annotations[i].secondaryStructure == 'C'
+                // || annotations[i].secondaryStructure == 'B'
+                // || annotations[i].secondaryStructure == 'C'
                 || annotations[i].secondaryStructure == 'D'
-                || annotations[i].secondaryStructure == 'E'
+                // || annotations[i].secondaryStructure == 'E' // ambiguous on
+                // its own -- already checked above
                 || annotations[i].secondaryStructure == 'F'
-                || annotations[i].secondaryStructure == 'G'
-                || annotations[i].secondaryStructure == 'H'
-                || annotations[i].secondaryStructure == 'I'
+                // || annotations[i].secondaryStructure == 'G'
+                // || annotations[i].secondaryStructure == 'H' // ambiguous on
+                // its own -- already checked above
+                // || annotations[i].secondaryStructure == 'I'
                 || annotations[i].secondaryStructure == 'J'
                 || annotations[i].secondaryStructure == 'K'
                 || annotations[i].secondaryStructure == 'L'
@@ -500,12 +412,12 @@ public class AlignmentAnnotation
                 || annotations[i].secondaryStructure == 'P'
                 || annotations[i].secondaryStructure == 'Q'
                 || annotations[i].secondaryStructure == 'R'
-                || annotations[i].secondaryStructure == 'S'
-                || annotations[i].secondaryStructure == 'T'
+                // || annotations[i].secondaryStructure == 'S'
+                // || annotations[i].secondaryStructure == 'T'
                 || annotations[i].secondaryStructure == 'U'
                 || annotations[i].secondaryStructure == 'V'
                 || annotations[i].secondaryStructure == 'W'
-                || annotations[i].secondaryStructure == 'X'
+                // || annotations[i].secondaryStructure == 'X'
                 || annotations[i].secondaryStructure == 'Y'
                 || annotations[i].secondaryStructure == 'Z')
         {
@@ -536,7 +448,7 @@ public class AlignmentAnnotation
         // &&
         // annotations[i].displayCharacter.charAt(0)==annotations[i].secondaryStructure
                 firstChar != ' ' && firstChar != '$' && firstChar != 0xCE
-                && firstChar != '(' && firstChar != '[' && firstChar != '>'
+                && firstChar != '(' && firstChar != '[' && firstChar != '<'
                 && firstChar != '{' && firstChar != 'A' && firstChar != 'B'
                 && firstChar != 'C' && firstChar != 'D' && firstChar != 'E'
                 && firstChar != 'F' && firstChar != 'G' && firstChar != 'H'
@@ -641,12 +553,12 @@ public class AlignmentAnnotation
                       : annotations[index + offset].displayCharacter == null
                               || annotations[index
                                       + offset].displayCharacter
-                                              .length() == 0
-                                                      ? annotations[index
-                                                              + offset].secondaryStructure
-                                                      : annotations[index
-                                                              + offset].displayCharacter
-                                                                      .charAt(0));
+                                      .length() == 0
+                                              ? annotations[index
+                                                      + offset].secondaryStructure
+                                              : annotations[index
+                                                      + offset].displayCharacter
+                                                      .charAt(0));
     }
 
     @Override
@@ -688,6 +600,38 @@ public class AlignmentAnnotation
     }
     return null;
   }
+  
+  /**
+   * Creates a new AlignmentAnnotation object.
+   * 
+   * @param label
+   *          DOCUMENT ME!
+   * @param description
+   *          DOCUMENT ME!
+   * @param annotations
+   *          DOCUMENT ME!
+   * @param min
+   *          DOCUMENT ME!
+   * @param max
+   *          DOCUMENT ME!
+   * @param winLength
+   *          DOCUMENT ME!
+   */
+  public AlignmentAnnotation(String label, String description,
+          Annotation[] annotations, float min, float max, int graphType)
+  {
+    setAnnotationId();
+    // graphs are not editable
+    editable = graphType == 0;
+
+    this.label = label;
+    this.description = description;
+    this.annotations = annotations;
+    graph = graphType;
+    graphMin = min;
+    graphMax = max;
+    validateRangeAndDisplay();
+  }
 
   /**
    * checks graphMin and graphMax, secondary structure symbols, sets graphType
@@ -768,6 +712,127 @@ public class AlignmentAnnotation
       }
     }
   }
+  
+  /**
+   * Copy constructor creates a new independent annotation row with the same
+   * associated sequenceRef
+   * 
+   * @param annotation
+   */
+  public AlignmentAnnotation(AlignmentAnnotation annotation)
+  {
+    setAnnotationId();
+    updateAlignmentAnnotationFrom(annotation);
+  }
+
+  /**
+   * copy attributes and annotation from an existing annotation (used by copy
+   * constructor). This method does not update the unique annotationId
+   * 
+   * @param annotation
+   */
+  public void updateAlignmentAnnotationFrom(AlignmentAnnotation annotation)
+  {
+    this.label = new String(annotation.label);
+    if (annotation.description != null)
+    {
+      this.description = new String(annotation.description);
+    }
+    this.graphMin = annotation.graphMin;
+    this.graphMax = annotation.graphMax;
+    this.graph = annotation.graph;
+    this.graphHeight = annotation.graphHeight;
+    this.graphGroup = annotation.graphGroup;
+    this.groupRef = annotation.groupRef;
+    this.editable = annotation.editable;
+    this.autoCalculated = annotation.autoCalculated;
+    this.hasIcons = annotation.hasIcons;
+    this.hasText = annotation.hasText;
+    this.height = annotation.height;
+    this.label = annotation.label;
+    this.padGaps = annotation.padGaps;
+    this.visible = annotation.visible;
+    this.centreColLabels = annotation.centreColLabels;
+    this.scaleColLabel = annotation.scaleColLabel;
+    this.showAllColLabels = annotation.showAllColLabels;
+    this.calcId = annotation.calcId;
+    this.bitScore = annotation.bitScore;
+    this.eValue = annotation.eValue;
+
+    if (annotation.properties != null)
+    {
+      properties = new HashMap<>();
+      for (Map.Entry<String, String> val : annotation.properties.entrySet())
+      {
+        properties.put(val.getKey(), val.getValue());
+      }
+    }
+    if (this.hasScore = annotation.hasScore)
+    {
+      this.score = annotation.score;
+    }
+    if (annotation.threshold != null)
+    {
+      threshold = new GraphLine(annotation.threshold);
+    }
+    Annotation[] ann = annotation.annotations;
+    if (annotation.annotations != null)
+    {
+      this.annotations = new Annotation[ann.length];
+      for (int i = 0; i < ann.length; i++)
+      {
+        if (ann[i] != null)
+        {
+          annotations[i] = new Annotation(ann[i]);
+          if (_linecolour != null)
+          {
+            _linecolour = annotations[i].colour;
+          }
+        }
+      }
+    }
+    if (annotation.sequenceRef != null)
+    {
+      this.sequenceRef = annotation.sequenceRef;
+      if (annotation.sequenceMapping != null)
+      {
+        Integer p = null;
+        sequenceMapping = new HashMap<>();
+        Iterator<Integer> pos = annotation.sequenceMapping.keySet()
+                .iterator();
+        while (pos.hasNext())
+        {
+          // could optimise this!
+          p = pos.next();
+          Annotation a = annotation.sequenceMapping.get(p);
+          if (a == null)
+          {
+            continue;
+          }
+          if (ann != null)
+          {
+            for (int i = 0; i < ann.length; i++)
+            {
+              if (ann[i] == a)
+              {
+                sequenceMapping.put(p, annotations[i]);
+              }
+            }
+          }
+        }
+      }
+      else
+      {
+        this.sequenceMapping = null;
+      }
+    }
+    // TODO: check if we need to do this: JAL-952
+    // if (this.isrna=annotation.isrna)
+    {
+      // _rnasecstr=new SequenceFeature[annotation._rnasecstr];
+    }
+    validateRangeAndDisplay(); // construct hashcodes, etc.
+  }
 
   /**
    * clip the annotation to the columns given by startRes and endRes (inclusive)
@@ -925,6 +990,7 @@ public class AlignmentAnnotation
    * @param seqRef
    * @param startRes
    * @param alreadyMapped
+   *          - annotation are at aligned columns
    */
   public void createSequenceMapping(SequenceI seqRef, int startRes,
           boolean alreadyMapped)
@@ -956,7 +1022,7 @@ public class AlignmentAnnotation
           seqPos = i + startRes;
         }
 
-        sequenceMapping.put(new Integer(seqPos), annotations[i]);
+        sequenceMapping.put(Integer.valueOf(seqPos), annotations[i]);
       }
     }
 
@@ -995,7 +1061,7 @@ public class AlignmentAnnotation
     {
       for (a = sequenceRef.getStart(); a <= sequenceRef.getEnd(); a++)
       {
-        index = new Integer(a);
+        index = Integer.valueOf(a);
         Annotation annot = sequenceMapping.get(index);
         if (annot != null)
         {
@@ -1126,6 +1192,37 @@ public class AlignmentAnnotation
   {
     return hasScore || !Double.isNaN(score);
   }
+  
+  /**
+   * Score only annotation
+   * 
+   * @param label
+   * @param description
+   * @param score
+   */
+  public AlignmentAnnotation(String label, String description, double score)
+  {
+    this(label, description, null);
+    setScore(score);
+  }
+
+  /**
+   * copy constructor with edit based on the hidden columns marked in colSel
+   * 
+   * @param alignmentAnnotation
+   * @param colSel
+   */
+  public AlignmentAnnotation(AlignmentAnnotation alignmentAnnotation,
+          HiddenColumns hidden)
+  {
+    this(alignmentAnnotation);
+    if (annotations == null)
+    {
+      return;
+    }
+    makeVisibleAnnotation(hidden);
+  }
+
 
   public void setPadGaps(boolean padgaps, char gapchar)
   {
@@ -1160,7 +1257,7 @@ public class AlignmentAnnotation
   {
     if (seqname && this.sequenceRef != null)
     {
-      int i = description.toLowerCase().indexOf("<html>");
+      int i = description.toLowerCase(Locale.ROOT).indexOf("<html>");
       if (i > -1)
       {
         // move the html tag to before the sequence reference.
@@ -1185,7 +1282,7 @@ public class AlignmentAnnotation
   /**
    * machine readable ID string indicating what generated this annotation
    */
-  private String calcId = "";
+  protected String calcId = "";
 
   /**
    * properties associated with the calcId
@@ -1586,7 +1683,7 @@ public class AlignmentAnnotation
           Iterable<AlignmentAnnotation> list, SequenceI seq, String calcId,
           String label)
   {
-    List<AlignmentAnnotation> aa = new ArrayList<>();
+    ArrayList<AlignmentAnnotation> aa = new ArrayList<>();
     for (AlignmentAnnotation ann : list)
     {
       if ((calcId == null || (ann.getCalcId() != null
@@ -1646,4 +1743,43 @@ public class AlignmentAnnotation
     }
     return aa;
   }
+
+  public double getBitScore()
+  {
+    return bitScore;
+  }
+
+  public void setBitScore(double bitScore)
+  {
+    this.bitScore = bitScore;
+  }
+
+  public double getEValue()
+  {
+    return eValue;
+  }
+
+  public void setEValue(double eValue)
+  {
+    this.eValue = eValue;
+  }
+
+  public static AlignmentAnnotation findFirstAnnotation(
+          Iterable<AlignmentAnnotation> alignmentAnnotation, String name,
+          String calcId, boolean autoCalc, SequenceI seqRef,
+          SequenceGroup groupRef)
+  {
+
+    for (AlignmentAnnotation annot : alignmentAnnotation)
+    {
+      if (annot.autoCalculated == autoCalc && (name.equals(annot.label))
+              && (calcId == null || annot.getCalcId().equals(calcId))
+              && annot.sequenceRef == seqRef && annot.groupRef == groupRef)
+      {
+        return annot;
+      }
+    }
+    return null;
+  }
+
 }