JAL-2526 Sequence.findPositions to get residue positions for column
[jalview.git] / src / jalview / datamodel / Sequence.java
index 9f3e7b8..dd7c24a 100755 (executable)
@@ -87,9 +87,6 @@ public class Sequence extends ASequence implements SequenceI
    */
   int index = -1;
 
-  /** array of sequence features - may not be null for a valid sequence object */
-  public SequenceFeature[] sequenceFeatures;
-
   private SequenceFeatures sequenceFeatureStore;
 
   /**
@@ -107,11 +104,13 @@ public class Sequence extends ASequence implements SequenceI
    */
   public Sequence(String name, String sequence, int start, int end)
   {
+    this();
     initSeqAndName(name, sequence.toCharArray(), start, end);
   }
 
   public Sequence(String name, char[] sequence, int start, int end)
   {
+    this();
     initSeqAndName(name, sequence, start, end);
   }
 
@@ -131,7 +130,6 @@ public class Sequence extends ASequence implements SequenceI
     this.sequence = sequence2;
     this.start = start2;
     this.end = end2;
-    sequenceFeatureStore = new SequenceFeatures();
     parseId();
     checkValidRange();
   }
@@ -182,6 +180,14 @@ public class Sequence extends ASequence implements SequenceI
   }
 
   /**
+   * default constructor
+   */
+  private Sequence()
+  {
+    sequenceFeatureStore = new SequenceFeatures();
+  }
+
+  /**
    * Creates a new Sequence object.
    * 
    * @param name
@@ -220,8 +226,8 @@ public class Sequence extends ASequence implements SequenceI
    */
   public Sequence(SequenceI seq, AlignmentAnnotation[] alAnnotation)
   {
+    this();
     initSeqFrom(seq, alAnnotation);
-
   }
 
   /**
@@ -260,13 +266,13 @@ public class Sequence extends ASequence implements SequenceI
           addDBRef(new DBRefEntry(dbr[i]));
         }
       }
-      if (seq.getSequenceFeatures() != null)
+
+      /*
+       * make copies of any sequence features
+       */
+      for (SequenceFeature sf : seq.getSequenceFeatures())
       {
-        SequenceFeature[] sf = seq.getSequenceFeatures();
-        for (int i = 0; i < sf.length; i++)
-        {
-          addSequenceFeature(new SequenceFeature(sf[i]));
-        }
+        addSequenceFeature(new SequenceFeature(sf));
       }
     }
 
@@ -306,24 +312,14 @@ public class Sequence extends ASequence implements SequenceI
   }
 
   @Override
-  public void setSequenceFeatures(SequenceFeature[] features)
+  public void setSequenceFeatures(List<SequenceFeature> features)
   {
-    if (datasetSequence == null)
-    {
-      sequenceFeatures = features;
-    }
-    else
+    if (datasetSequence != null)
     {
-      if (datasetSequence.getSequenceFeatures() != features
-              && datasetSequence.getSequenceFeatures() != null
-              && datasetSequence.getSequenceFeatures().length > 0)
-      {
-        new Exception(
-                "Warning: JAL-2046 side effect ? Possible implementation error: overwriting dataset sequence features by setting sequence features on alignment")
-                .printStackTrace();
-      }
       datasetSequence.setSequenceFeatures(features);
+      return;
     }
+    sequenceFeatureStore = new SequenceFeatures(features);
   }
 
   @Override
@@ -336,109 +332,40 @@ public class Sequence extends ASequence implements SequenceI
       return false;
     }
 
-    if (sequenceFeatures == null && datasetSequence != null)
+    if (datasetSequence != null)
     {
       return datasetSequence.addSequenceFeature(sf);
     }
-    if (sequenceFeatures == null)
-    {
-      sequenceFeatures = new SequenceFeature[0];
-    }
-
-    for (int i = 0; i < sequenceFeatures.length; i++)
-    {
-      if (sequenceFeatures[i].equals(sf))
-      {
-        return false;
-      }
-    }
-
-    SequenceFeature[] temp = new SequenceFeature[sequenceFeatures.length + 1];
-    System.arraycopy(sequenceFeatures, 0, temp, 0, sequenceFeatures.length);
-    temp[sequenceFeatures.length] = sf;
 
-    sequenceFeatures = temp;
-
-    sequenceFeatureStore.add(sf);
-    return true;
+    return sequenceFeatureStore.add(sf);
   }
 
   @Override
   public void deleteFeature(SequenceFeature sf)
   {
-    if (sequenceFeatures == null)
-    {
-      if (datasetSequence != null)
-      {
-        datasetSequence.deleteFeature(sf);
-      }
-      return;
-    }
-
-    /*
-     * new way
-     */
-    sequenceFeatureStore.delete(sf);
-
-    /*
-     * old way - to be removed
-     */
-    int index = 0;
-    for (index = 0; index < sequenceFeatures.length; index++)
-    {
-      if (sequenceFeatures[index].equals(sf))
-      {
-        break;
-      }
-    }
-
-    if (index == sequenceFeatures.length)
-    {
-      return;
-    }
-
-    int sfLength = sequenceFeatures.length;
-    if (sfLength < 2)
+    if (datasetSequence != null)
     {
-      sequenceFeatures = null;
+      datasetSequence.deleteFeature(sf);
     }
     else
     {
-      SequenceFeature[] temp = new SequenceFeature[sfLength - 1];
-      System.arraycopy(sequenceFeatures, 0, temp, 0, index);
-
-      if (index < sfLength)
-      {
-        System.arraycopy(sequenceFeatures, index + 1, temp, index,
-                sequenceFeatures.length - index - 1);
-      }
-
-      sequenceFeatures = temp;
+      sequenceFeatureStore.delete(sf);
     }
   }
 
   /**
-   * Returns the sequence features (if any), looking first on the sequence, then
-   * on its dataset sequence, and so on until a non-null value is found (or
-   * none). This supports retrieval of sequence features stored on the sequence
-   * (as in the applet) or on the dataset sequence (as in the Desktop version).
+   * {@inheritDoc}
    * 
    * @return
    */
   @Override
-  public SequenceFeature[] getSequenceFeatures()
+  public List<SequenceFeature> getSequenceFeatures()
   {
-    SequenceFeature[] features = sequenceFeatures;
-
-    SequenceI seq = this;
-    int count = 0; // failsafe against loop in sequence.datasetsequence...
-    while (features == null && seq.getDatasetSequence() != null
-            && count++ < 10)
+    if (datasetSequence != null)
     {
-      seq = seq.getDatasetSequence();
-      features = ((Sequence) seq).sequenceFeatures;
+      return datasetSequence.getSequenceFeatures();
     }
-    return features;
+    return sequenceFeatureStore.getAllFeatures();
   }
 
   @Override
@@ -735,7 +662,7 @@ public class Sequence extends ASequence implements SequenceI
     // Rely on end being at least as long as the length of the sequence.
     while ((i < sequence.length) && (j <= end) && (j <= pos))
     {
-      if (!jalview.util.Comparison.isGap(sequence[i]))
+      if (!Comparison.isGap(sequence[i]))
       {
         j++;
       }
@@ -761,7 +688,7 @@ public class Sequence extends ASequence implements SequenceI
     int seqlen = sequence.length;
     while ((j < i) && (j < seqlen))
     {
-      if (!jalview.util.Comparison.isGap(sequence[j]))
+      if (!Comparison.isGap(sequence[j]))
       {
         pos++;
       }
@@ -773,6 +700,68 @@ public class Sequence extends ASequence implements SequenceI
   }
 
   /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Range findPositions(int fromCol, int toCol)
+  {
+    /*
+     * count residues before fromCol
+     */
+    int j = 0;
+    int count = 0;
+    int seqlen = sequence.length;
+    while (j < fromCol && j < seqlen)
+    {
+      if (!Comparison.isGap(sequence[j]))
+      {
+        count++;
+      }
+      j++;
+    }
+
+    /*
+     * find first and last residues between fromCol and toCol
+     */
+    int firstPos = 0;
+    int lastPos = 0;
+    int firstPosCol = 0;
+    boolean foundFirst = false;
+    
+    while (j <= toCol && j < seqlen)
+    {
+      if (!Comparison.isGap(sequence[j]))
+      {
+        count++;
+        if (!foundFirst)
+        {
+          firstPos = count;
+          firstPosCol = j;
+          foundFirst = true;
+        }
+        lastPos = count;
+      }
+      j++;
+    }
+
+    if (firstPos == 0)
+    {
+      /*
+       * no residues in this range
+       */
+      return null;
+    }
+
+    /*
+     * adjust for sequence start coordinate
+     */
+    firstPos += start - 1;
+    lastPos += start - 1;
+
+    return new Range(firstPos, lastPos);
+  }
+
+  /**
    * Returns an int array where indices correspond to each residue in the
    * sequence and the element value gives its position in the alignment
    * 
@@ -1191,8 +1180,6 @@ public class Sequence extends ASequence implements SequenceI
 
       dsseq.setDescription(description);
       // move features and database references onto dataset sequence
-      dsseq.sequenceFeatures = sequenceFeatures;
-      sequenceFeatures = null;
       dsseq.sequenceFeatureStore = sequenceFeatureStore;
       sequenceFeatureStore = null;
       dsseq.dbrefs = dbrefs;
@@ -1325,12 +1312,12 @@ public class Sequence extends ASequence implements SequenceI
     if (entry.getSequenceFeatures() != null)
     {
 
-      SequenceFeature[] sfs = entry.getSequenceFeatures();
-      for (int si = 0; si < sfs.length; si++)
+      List<SequenceFeature> sfs = entry.getSequenceFeatures();
+      for (SequenceFeature feature : sfs)
       {
-        SequenceFeature sf[] = (mp != null) ? mp.locateFeature(sfs[si])
-                : new SequenceFeature[] { new SequenceFeature(sfs[si]) };
-        if (sf != null && sf.length > 0)
+        SequenceFeature sf[] = (mp != null) ? mp.locateFeature(feature)
+                : new SequenceFeature[] { new SequenceFeature(feature) };
+        if (sf != null)
         {
           for (int sfi = 0; sfi < sf.length; sfi++)
           {