Merge branch 'develop' into features/mchmmer
[jalview.git] / src / jalview / datamodel / Sequence.java
index 7f200da..7972626 100755 (executable)
@@ -28,12 +28,14 @@ import jalview.util.Comparison;
 import jalview.util.DBRefUtils;
 import jalview.util.MapList;
 import jalview.util.StringUtils;
+import jalview.workers.InformationThread;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Vector;
@@ -55,16 +57,12 @@ public class Sequence extends ASequence implements SequenceI
 
   private char[] sequence;
 
-  int previousPosition;
-
   String description;
 
   int start;
 
   int end;
 
-  boolean hasInfo;
-
   HiddenMarkovModel hmm;
 
   boolean isHMMConsensusSequence = false;
@@ -345,13 +343,9 @@ public class Sequence extends ASequence implements SequenceI
         this.addPDBId(new PDBEntry(pdb));
       }
     }
-    if (seq.isHMMConsensusSequence())
-    {
-      this.isHMMConsensusSequence = true;
-    }
     if (seq.getHMM() != null)
     {
-      this.hmm = new HiddenMarkovModel(seq.getHMM());
+      this.hmm = new HiddenMarkovModel(seq.getHMM(), this);
     }
 
   }
@@ -831,7 +825,7 @@ public class Sequence extends ASequence implements SequenceI
    * @param curs
    * @return
    */
-  protected int findIndex(int pos, SequenceCursor curs)
+  protected int findIndex(final int pos, SequenceCursor curs)
   {
     if (!isValidCursor(curs))
     {
@@ -857,8 +851,13 @@ public class Sequence extends ASequence implements SequenceI
     while (newPos != pos)
     {
       col += delta; // shift one column left or right
-      if (col < 0 || col == sequence.length)
+      if (col < 0)
+      {
+        break;
+      }
+      if (col == sequence.length)
       {
+        col--; // return last column if we failed to reach pos
         break;
       }
       if (!Comparison.isGap(sequence[col]))
@@ -868,7 +867,14 @@ public class Sequence extends ASequence implements SequenceI
     }
 
     col++; // convert back to base 1
-    updateCursor(pos, col, curs.firstColumnPosition);
+
+    /*
+     * only update cursor if we found the target position
+     */
+    if (newPos == pos)
+    {
+      updateCursor(pos, col, curs.firstColumnPosition);
+    }
 
     return col;
   }
@@ -1145,6 +1151,27 @@ public class Sequence extends ASequence implements SequenceI
     return map;
   }
 
+  /**
+   * Build a bitset corresponding to sequence gaps
+   * 
+   * @return a BitSet where set values correspond to gaps in the sequence
+   */
+  @Override
+  public BitSet gapBitset()
+  {
+    BitSet gaps = new BitSet(sequence.length);
+    int j = 0;
+    while (j < sequence.length)
+    {
+      if (jalview.util.Comparison.isGap(sequence[j]))
+      {
+        gaps.set(j);
+      }
+      j++;
+    }
+    return gaps;
+  }
+
   @Override
   public int[] findPositionMap()
   {
@@ -1785,7 +1812,8 @@ public class Sequence extends ASequence implements SequenceI
     {
       for (AlignmentAnnotation ann : annotation)
       {
-        if (ann.calcId != null && ann.calcId.equals(calcId)
+        String id = ann.getCalcId();
+        if (id != null && id.equals(calcId)
                 && ann.label != null && ann.label.equals(label))
         {
           result.add(ann);
@@ -1896,91 +1924,19 @@ public class Sequence extends ASequence implements SequenceI
   }
 
   @Override
-  public void updateHMMMapping()
+  public boolean hasHMMAnnotation()
   {
-    int node = 1;
-    int column = 0;
-    hmm.emptyNodeLookup();
-    for (char residue : sequence)
-    {
-      if (!Comparison.isGap(residue))
-      {
-        hmm.setAlignmentColumn(node, column);
-        node++;
-      }
-      column++;
+    if (this.annotation == null) {
+      return false;
     }
-  }
-
-  /**
-   * Maps the HMM sequence to the reference annotation.
-   * 
-   * @param rf
-   */
-  @Override
-  public void mapToReference(AlignmentAnnotation rf)
-  {
-    if (this.isHMMConsensusSequence)
+    for (AlignmentAnnotation ann : annotation)
     {
-      int node = 1;
-      hmm.emptyNodeLookup();
-      for (int i = 0; i < getLength(); i++)
+      if (InformationThread.HMM_CALC_ID.equals(ann.getCalcId()))
       {
-        if (rf.annotations[i].displayCharacter.equals("x")
-                || rf.annotations[i].displayCharacter.equals("X"))
-        {
-          if (i < hmm.getNodeAlignmentColumn(node))
-          {
-            this.deleteChars(i, hmm.getNodeAlignmentColumn(node));
-            updateHMMMapping();
-          }
-          else if (i > hmm.getNodeAlignmentColumn(node))
-          {
-            int length = i - hmm.getNodeAlignmentColumn(node);
-            this.insertCharAt(hmm.getNodeAlignmentColumn(node), length,
-                    '-');
-            updateHMMMapping();
-          }
-          node++;
-        }
+        return true;
       }
     }
-  }
-
-  @Override
-  public boolean isHMMConsensusSequence()
-  {
-    return isHMMConsensusSequence;
-  }
-
-  @Override
-  public void setIsHMMConsensusSequence(boolean isHMMConsensusSequence)
-  {
-    this.isHMMConsensusSequence = isHMMConsensusSequence;
-  }
-
-  @Override
-  public boolean hasHMMAnnotation()
-  {
-    return hasInfo;
-  }
-
-  @Override
-  public void setHasInfo(boolean status)
-  {
-    hasInfo = true;
-  }
-
-  @Override
-  public int getPreviousPosition()
-  {
-    return previousPosition;
-  }
-
-  @Override
-  public void setPreviousPosition(int previousPosition)
-  {
-    this.previousPosition = previousPosition;
+    return false;
   }
 
   /**
@@ -2078,4 +2034,79 @@ public class Sequence extends ASequence implements SequenceI
 
     return count;
   }
+
+  @Override
+  public String getSequenceStringFromIterator(Iterator<int[]> it)
+  {
+    StringBuilder newSequence = new StringBuilder();
+    while (it.hasNext())
+    {
+      int[] block = it.next();
+      if (it.hasNext())
+      {
+        newSequence.append(getSequence(block[0], block[1] + 1));
+      }
+      else
+      {
+        newSequence.append(getSequence(block[0], block[1]));
+      }
+    }
+
+    return newSequence.toString();
+  }
+
+  @Override
+  public int firstResidueOutsideIterator(Iterator<int[]> regions)
+  {
+    int start = 0;
+
+    if (!regions.hasNext())
+    {
+      return findIndex(getStart()) - 1;
+    }
+
+    // Simply walk along the sequence whilst watching for region
+    // boundaries
+    int hideStart = getLength();
+    int hideEnd = -1;
+    boolean foundStart = false;
+
+    // step through the non-gapped positions of the sequence
+    for (int i = getStart(); i <= getEnd() && (!foundStart); i++)
+    {
+      // get alignment position of this residue in the sequence
+      int p = findIndex(i) - 1;
+
+      // update region start/end
+      while (hideEnd < p && regions.hasNext())
+      {
+        int[] region = regions.next();
+        hideStart = region[0];
+        hideEnd = region[1];
+      }
+      if (hideEnd < p)
+      {
+        hideStart = getLength();
+      }
+      // update boundary for sequence
+      if (p < hideStart)
+      {
+        start = p;
+        foundStart = true;
+      }
+    }
+
+    if (foundStart)
+    {
+      return start;
+    }
+    // otherwise, sequence was completely hidden
+    return 0;
+  }
+
+  @Override
+  public boolean hasHMMProfile()
+  {
+    return hmm != null;
+  }
 }