Merge branch 'develop' into features/JAL-2360colourSchemeApplicability
[jalview.git] / src / jalview / datamodel / Alignment.java
index fd918fc..a6f2bf4 100755 (executable)
@@ -24,6 +24,7 @@ import jalview.analysis.AlignmentUtils;
 import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
 import jalview.io.FastaFile;
 import jalview.util.Comparison;
+import jalview.util.LinkedIdentityHashSet;
 import jalview.util.MessageManager;
 
 import java.util.ArrayList;
@@ -53,11 +54,7 @@ public class Alignment implements AlignmentI
 
   protected char gapCharacter = '-';
 
-  protected int type = NUCLEOTIDE;
-
-  public static final int PROTEIN = 0;
-
-  public static final int NUCLEOTIDE = 1;
+  private boolean nucleotide = true;
 
   public boolean hasRNAStructure = false;
 
@@ -75,14 +72,7 @@ public class Alignment implements AlignmentI
     hiddenSequences = new HiddenSequences(this);
     codonFrameList = new ArrayList<AlignedCodonFrame>();
 
-    if (Comparison.isNucleotide(seqs))
-    {
-      type = NUCLEOTIDE;
-    }
-    else
-    {
-      type = PROTEIN;
-    }
+    nucleotide = Comparison.isNucleotide(seqs);
 
     sequences = Collections.synchronizedList(new ArrayList<SequenceI>());
 
@@ -217,7 +207,9 @@ public class Alignment implements AlignmentI
   }
 
   /**
-   * Adds a sequence to the alignment. Recalculates maxLength and size.
+   * Adds a sequence to the alignment. Recalculates maxLength and size. Note
+   * this currently does not recalculate whether or not the alignment is
+   * nucleotide, so mixed alignments may have undefined behaviour.
    * 
    * @param snew
    */
@@ -226,18 +218,21 @@ public class Alignment implements AlignmentI
   {
     if (dataset != null)
     {
+
       // maintain dataset integrity
-      if (snew.getDatasetSequence() != null)
-      {
-        getDataset().addSequence(snew.getDatasetSequence());
-      }
-      else
+      SequenceI dsseq = snew.getDatasetSequence();
+      if (dsseq == null)
       {
         // derive new sequence
         SequenceI adding = snew.deriveSequence();
-        getDataset().addSequence(adding.getDatasetSequence());
         snew = adding;
+        dsseq = snew.getDatasetSequence();
       }
+      if (getDataset().findIndex(dsseq) == -1)
+      {
+        getDataset().addSequence(dsseq);
+      }
+
     }
     if (sequences == null)
     {
@@ -287,13 +282,23 @@ public class Alignment implements AlignmentI
   }
 
   @Override
-  public void finalize()
+  public void finalize() throws Throwable
   {
     if (getDataset() != null)
     {
       getDataset().removeAlignmentRef();
     }
 
+    nullReferences();
+    super.finalize();
+  }
+
+  /**
+   * Defensively nulls out references in case this object is not garbage
+   * collected
+   */
+  void nullReferences()
+  {
     dataset = null;
     sequences = null;
     groups = null;
@@ -302,14 +307,16 @@ public class Alignment implements AlignmentI
   }
 
   /**
-   * decrement the alignmentRefs counter by one and call finalize if it goes to
-   * zero.
+   * decrement the alignmentRefs counter by one and null references if it goes
+   * to zero.
+   * 
+   * @throws Throwable
    */
-  private void removeAlignmentRef()
+  private void removeAlignmentRef() throws Throwable
   {
     if (--alignmentRefs == 0)
     {
-      finalize();
+      nullReferences();
     }
   }
 
@@ -350,17 +357,18 @@ public class Alignment implements AlignmentI
    * @see jalview.datamodel.AlignmentI#findGroup(jalview.datamodel.SequenceI)
    */
   @Override
-  public SequenceGroup findGroup(SequenceI s)
+  public SequenceGroup findGroup(SequenceI seq, int position)
   {
     synchronized (groups)
     {
-      for (int i = 0; i < this.groups.size(); i++)
+      for (SequenceGroup sg : groups)
       {
-        SequenceGroup sg = groups.get(i);
-
-        if (sg.getSequences(null).contains(s))
+        if (sg.getSequences(null).contains(seq))
         {
-          return sg;
+          if (position >= sg.getStartRes() && position <= sg.getEndRes())
+          {
+            return sg;
+          }
         }
       }
     }
@@ -645,7 +653,7 @@ public class Alignment implements AlignmentI
    * jalview.datamodel.AlignmentI#findIndex(jalview.datamodel.SearchResults)
    */
   @Override
-  public int findIndex(SearchResults results)
+  public int findIndex(SearchResultsI results)
   {
     int i = 0;
 
@@ -961,29 +969,9 @@ public class Alignment implements AlignmentI
   }
 
   @Override
-  public void setNucleotide(boolean b)
-  {
-    if (b)
-    {
-      type = NUCLEOTIDE;
-    }
-    else
-    {
-      type = PROTEIN;
-    }
-  }
-
-  @Override
   public boolean isNucleotide()
   {
-    if (type == NUCLEOTIDE)
-    {
-      return true;
-    }
-    else
-    {
-      return false;
-    }
+    return nucleotide;
   }
 
   @Override
@@ -1039,6 +1027,7 @@ public class Alignment implements AlignmentI
   private void resolveAndAddDatasetSeq(SequenceI currentSeq,
           Set<SequenceI> seqs, boolean createDatasetSequence)
   {
+    SequenceI alignedSeq = currentSeq;
     if (currentSeq.getDatasetSequence() != null)
     {
       currentSeq = currentSeq.getDatasetSequence();
@@ -1073,12 +1062,19 @@ public class Alignment implements AlignmentI
         {
           if (dbr.getMap() != null && dbr.getMap().getTo() != null)
           {
+            if (dbr.getMap().getTo() == alignedSeq)
+            {
+              /*
+               * update mapping to be to the newly created dataset sequence
+               */
+              dbr.getMap().setTo(currentSeq);
+            }
             if (dbr.getMap().getTo().getDatasetSequence() != null)
             {
-              throw new Error("Implementation error: Map.getTo() for dbref"
-                      + dbr + " is not a dataset sequence.");
-              // TODO: if this happens, could also rewrite the reference to
-              // point to new dataset sequence
+              throw new Error(
+                      "Implementation error: Map.getTo() for dbref " + dbr
+                              + " from " + curDs.getName()
+                              + " is not a dataset sequence.");
             }
             // we recurse to add all forward references to dataset sequences via
             // DBRefs/etc
@@ -1100,7 +1096,7 @@ public class Alignment implements AlignmentI
       return;
     }
     // try to avoid using SequenceI.equals at this stage, it will be expensive
-    Set<SequenceI> seqs = new jalview.util.LinkedIdentityHashSet<SequenceI>();
+    Set<SequenceI> seqs = new LinkedIdentityHashSet<SequenceI>();
 
     for (int i = 0; i < getHeight(); i++)
     {
@@ -1566,7 +1562,6 @@ public class Alignment implements AlignmentI
           String calcId, boolean autoCalc, SequenceI seqRef,
           SequenceGroup groupRef)
   {
-    assert (name != null);
     if (annotations != null)
     {
       for (AlignmentAnnotation annot : getAlignmentAnnotation())
@@ -1598,14 +1593,18 @@ public class Alignment implements AlignmentI
   @Override
   public Iterable<AlignmentAnnotation> findAnnotation(String calcId)
   {
-    ArrayList<AlignmentAnnotation> aa = new ArrayList<AlignmentAnnotation>();
-    for (AlignmentAnnotation a : getAlignmentAnnotation())
+    List<AlignmentAnnotation> aa = new ArrayList<AlignmentAnnotation>();
+    AlignmentAnnotation[] alignmentAnnotation = getAlignmentAnnotation();
+    if (alignmentAnnotation != null)
     {
-      if (a.getCalcId() == calcId
-              || (a.getCalcId() != null && calcId != null && a.getCalcId()
-                      .equals(calcId)))
+      for (AlignmentAnnotation a : alignmentAnnotation)
       {
-        aa.add(a);
+        if (a.getCalcId() == calcId
+                || (a.getCalcId() != null && calcId != null && a
+                        .getCalcId().equals(calcId)))
+        {
+          aa.add(a);
+        }
       }
     }
     return aa;
@@ -1813,7 +1812,7 @@ public class Alignment implements AlignmentI
   @Override
   public String toString()
   {
-    return new FastaFile().print(getSequencesArray());
+    return new FastaFile().print(getSequencesArray(), true);
   }
 
   /**