ascii type
[jalview.git] / src / jalview / datamodel / AlignmentAnnotation.java
index c675a75..8d8a118 100755 (executable)
  */
 package jalview.datamodel;
 
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
 /**
  * DOCUMENT ME!
  *
@@ -170,7 +174,6 @@ public class AlignmentAnnotation
 
     annotationId = this.hashCode() + "";
   }
-
   /**
    * Creates a new AlignmentAnnotation object.
    *
@@ -190,9 +193,23 @@ public class AlignmentAnnotation
     this.description = description;
     this.annotations = annotations;
     graph = graphType;
-
+    graphMin = min;
+    graphMax = max;
+    validateRangeAndDisplay();
+  }
+  /**
+   * checks graphMin and graphMax,
+   * secondary structure symbols,
+   * sets graphType appropriately,
+   * sets null labels to the empty string
+   * if appropriate.
+   */
+  private void validateRangeAndDisplay() {
+    int graphType = graph;
+    float min = graphMin;
+    float max = graphMax;
     boolean drawValues = true;
-
+    
     if (min == max)
     {
       min = 999999999;
@@ -236,6 +253,57 @@ public class AlignmentAnnotation
       }
     }
   }
+  
+  /**
+   * Copy constructor
+   * creates a new independent annotation row with the same associated sequenceRef 
+   * @param annotation
+   */
+  public AlignmentAnnotation(AlignmentAnnotation annotation)
+  {
+    this.label = new String(annotation.label);
+    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.editable = annotation.editable;
+    this.autoCalculated = annotation.autoCalculated;
+    this.hasIcons = annotation.hasIcons;
+    this.hasText = annotation.hasText;
+    this.height = annotation.height;
+    this.label = annotation.label;
+    if (threshold!=null) {
+      threshold = new GraphLine(annotation.threshold);
+    }
+    if (annotation.annotations!=null) {
+      Vector anvec = new Vector();
+      Annotation[] ann = annotation.annotations;
+      this.annotations = new Annotation[ann.length];
+      for (int i=0; i<ann.length; i++) {
+        annotations[i] = new Annotation(ann[i]);
+        anvec.add(ann[i]); // for lookup if sequenceMapping exists.
+      };
+      if (annotation.sequenceRef!=null) {
+        this.sequenceRef = annotation.sequenceRef;
+        if (annotation.sequenceMapping!=null)
+        {
+          sequenceMapping = new Hashtable();
+          Enumeration pos=annotation.sequenceMapping.keys();
+          while (pos.hasMoreElements()) {
+            Integer p = (Integer) pos.nextElement();
+            Annotation a = (Annotation) sequenceMapping.get(p);
+            sequenceMapping.put(p, annotations[anvec.indexOf(a)]); 
+          }
+          anvec.clear();
+        } else {
+          this.sequenceMapping = null;
+        }
+      }
+    }
+    validateRangeAndDisplay(); // construct hashcodes, etc.
+  }
 
   /**
    * DOCUMENT ME!
@@ -337,6 +405,9 @@ public class AlignmentAnnotation
 
   public void adjustForAlignment()
   {
+    if (sequenceRef==null)
+      return;
+    
     int a = 0, aSize = sequenceRef.getLength();
 
     if (aSize == 0)
@@ -362,4 +433,60 @@ public class AlignmentAnnotation
 
     annotations = temp;
   }
+  /**
+   * remove any null entries in annotation row and return the
+   * number of non-null annotation elements.
+   * @return
+   */
+  private int compactAnnotationArray() {
+    int j=0;
+    for (int i=0;i<annotations.length; i++) {
+      if (annotations[i]!=null && j!=i) {
+        annotations[j++] = annotations[i];
+      }
+    }
+    Annotation[] ann = annotations;
+    annotations = new Annotation[j];
+    System.arraycopy(ann, 0, annotations, 0, j);
+    ann = null;
+    return j;
+  }
+  
+  /**
+   * Associate this annotion with the aligned residues of a particular sequence.
+   * sequenceMapping will be updated in the following way:
+   *   null sequenceI - existing mapping will be discarded but annotations left in mapped positions.
+   *   valid sequenceI not equal to current sequenceRef: mapping is discarded and rebuilt assuming 1:1 correspondence
+   *   TODO: overload with parameter to specify correspondence between current and new sequenceRef
+   * @param sequenceI
+   */
+  public void setSequenceRef(SequenceI sequenceI)
+  {
+    if (sequenceI!=null) {
+      if (sequenceRef!=null) {
+        if (sequenceRef!=sequenceI && !sequenceRef.equals(sequenceI)) {
+          // throw away old mapping and reconstruct.
+          sequenceRef=null;
+          if (sequenceMapping!=null) 
+          {
+            sequenceMapping=null;
+            // compactAnnotationArray();
+          }
+          createSequenceMapping(sequenceI, 1,true);
+          adjustForAlignment();
+        } else {
+          // Mapping carried over
+          sequenceRef = sequenceI;
+        }
+      } else {
+        // No mapping exists
+        createSequenceMapping(sequenceI, 1, true);
+        adjustForAlignment();
+      }
+    } else {
+      // throw away the mapping without compacting.
+      sequenceMapping=null;
+      sequenceRef = null;
+    }
+  }
 }