mearge with develop
[jalview.git] / src / jalview / datamodel / AlignmentAnnotation.java
index c0d911e..0731991 100755 (executable)
@@ -25,8 +25,12 @@ import jalview.analysis.SecStrConsensus.SimpleBP;
 import jalview.analysis.WUSSParseException;
 
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.Hashtable;
+import java.util.Map;
 import java.util.Map.Entry;
 
 /**
@@ -43,17 +47,24 @@ public class AlignmentAnnotation
    */
   public boolean autoCalculated = false;
 
+  /**
+   * unique ID for this annotation, used to match up the same annotation row
+   * shown in multiple views and alignments
+   */
   public String annotationId;
 
+  /**
+   * the sequence this annotation is associated with (or null)
+   */
   public SequenceI sequenceRef;
 
-  /** DOCUMENT ME!! */
+  /** label shown in dropdown menus and in the annotation label area */
   public String label;
 
-  /** DOCUMENT ME!! */
+  /** longer description text shown as a tooltip */
   public String description;
 
-  /** DOCUMENT ME!! */
+  /** Array of annotations placed in the current coordinate system */
   public Annotation[] annotations;
 
   public ArrayList<SimpleBP> bps = null;
@@ -103,6 +114,9 @@ public class AlignmentAnnotation
     // System.out.println("featuregroup " + _rnasecstr[0].getFeatureGroup());
   }
 
+  /**
+   * map of positions in the associated annotation
+   */
   public java.util.Hashtable<Integer, Annotation> sequenceMapping;
 
   /** DOCUMENT ME!! */
@@ -622,6 +636,14 @@ public class AlignmentAnnotation
     this.scaleColLabel = annotation.scaleColLabel;
     this.showAllColLabels = annotation.showAllColLabels;
     this.calcId = annotation.calcId;
+    if (annotation.properties!=null)
+    {
+      properties = new HashMap<String,String>();
+      for (Map.Entry<String, String> val:annotation.properties.entrySet())
+      {
+        properties.put(val.getKey(), val.getValue());
+      }
+    }
     if (this.hasScore = annotation.hasScore)
     {
       this.score = annotation.score;
@@ -630,9 +652,9 @@ public class AlignmentAnnotation
     {
       threshold = new GraphLine(annotation.threshold);
     }
+    Annotation[] ann = annotation.annotations;
     if (annotation.annotations != null)
     {
-      Annotation[] ann = annotation.annotations;
       this.annotations = new Annotation[ann.length];
       for (int i = 0; i < ann.length; i++)
       {
@@ -645,24 +667,26 @@ public class AlignmentAnnotation
           }
         }
       }
-      ;
-      if (annotation.sequenceRef != null)
+    }
+    if (annotation.sequenceRef != null)
+    {
+      this.sequenceRef = annotation.sequenceRef;
+      if (annotation.sequenceMapping != null)
       {
-        this.sequenceRef = annotation.sequenceRef;
-        if (annotation.sequenceMapping != null)
+        Integer p = null;
+        sequenceMapping = new Hashtable();
+        Enumeration pos = annotation.sequenceMapping.keys();
+        while (pos.hasMoreElements())
         {
-          Integer p = null;
-          sequenceMapping = new Hashtable();
-          Enumeration pos = annotation.sequenceMapping.keys();
-          while (pos.hasMoreElements())
+          // could optimise this!
+          p = (Integer) pos.nextElement();
+          Annotation a = annotation.sequenceMapping.get(p);
+          if (a == null)
+          {
+            continue;
+          }
+          if (ann != null)
           {
-            // could optimise this!
-            p = (Integer) pos.nextElement();
-            Annotation a = annotation.sequenceMapping.get(p);
-            if (a == null)
-            {
-              continue;
-            }
             for (int i = 0; i < ann.length; i++)
             {
               if (ann[i] == a)
@@ -672,10 +696,10 @@ public class AlignmentAnnotation
             }
           }
         }
-        else
-        {
-          this.sequenceMapping = null;
-        }
+      }
+      else
+      {
+        this.sequenceMapping = null;
       }
     }
     // TODO: check if we need to do this: JAL-952
@@ -1119,6 +1143,11 @@ public class AlignmentAnnotation
   protected String calcId = "";
 
   /**
+   * properties associated with the calcId
+   */
+  protected Map<String, String> properties = new HashMap<String, String>();
+
+  /**
    * base colour for line graphs. If null, will be set automatically by
    * searching the alignment annotation
    */
@@ -1182,6 +1211,108 @@ public class AlignmentAnnotation
         // trim positions
       }
     }
+  }
+
+  /**
+   * like liftOver but more general.
+   * 
+   * Takes an array of int pairs that will be used to update the internal
+   * sequenceMapping and so shuffle the annotated positions
+   * 
+   * @param newref
+   *          - new sequence reference for the annotation row - if null,
+   *          sequenceRef is left unchanged
+   * @param mapping
+   *          array of ints containing corresponding positions
+   * @param from
+   *          - column for current coordinate system (-1 for index+1)
+   * @param to
+   *          - column for destination coordinate system (-1 for index+1)
+   * @param idxoffset
+   *          - offset added to index when referencing either coordinate system
+   * @note no checks are made as to whether from and/or to are sensible
+   * @note caller should add the remapped annotation to newref if they have not
+   *       already
+   */
+  public void remap(SequenceI newref, int[][] mapping, int from, int to,
+          int idxoffset)
+  {
+    if (mapping != null)
+    {
+      Hashtable<Integer, Annotation> old = sequenceMapping, remap = new Hashtable<Integer, Annotation>();
+      int index = -1;
+      for (int mp[] : mapping)
+      {
+        if (index++ < 0)
+        {
+          continue;
+        }
+        Annotation ann = null;
+        if (from == -1)
+        {
+          ann = sequenceMapping.get(Integer.valueOf(idxoffset + index));
+        }
+        else
+        {
+          if (mp != null && mp.length > from)
+          {
+            ann = sequenceMapping.get(Integer.valueOf(mp[from]));
+          }
+        }
+        if (ann != null)
+        {
+          if (to == -1)
+          {
+            remap.put(Integer.valueOf(idxoffset + index), ann);
+          }
+          else
+          {
+            if (to > -1 && to < mp.length)
+            {
+              remap.put(Integer.valueOf(mp[to]), ann);
+            }
+          }
+        }
+      }
+      sequenceMapping = remap;
+      old.clear();
+      if (newref != null)
+      {
+        sequenceRef = newref;
+      }
+      adjustForAlignment();
+    }
+  }
+
+  public String getProperty(String property)
+  {
+    if (properties == null)
+    {
+      return null;
+    }
+    return properties.get(property);
+  }
 
+  public void setProperty(String property, String value)
+  {
+    if (properties==null)
+    {
+      properties = new HashMap<String,String>();
+    }
+    properties.put(property, value);
+  }
+
+  public boolean hasProperties()
+  {
+    return properties != null && properties.size() > 0;
+  }
+
+  public Collection<String> getProperties()
+  {
+    if (properties == null)
+    {
+      return Collections.EMPTY_LIST;
+    }
+    return properties.keySet();
   }
 }