JAL-1645 Version-Rel Version 2.9 Year-Rel 2015 Licensing glob
[jalview.git] / src / jalview / io / VamsasAppDatastore.java
index 3c6e441..d580129 100644 (file)
@@ -1,43 +1,78 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer
- * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.9)
+ * Copyright (C) 2015 The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
  * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
-
 package jalview.io;
 
 import jalview.bin.Cache;
+import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.AlignmentAnnotation;
-import jalview.datamodel.AlignmentI;
-import jalview.datamodel.AlignmentView;
-import jalview.datamodel.DBRefEntry;
-import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.GraphLine;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.AlignViewport;
 import jalview.gui.Desktop;
 import jalview.gui.TreePanel;
-
+import jalview.io.vamsas.Datasetsequence;
+import jalview.io.vamsas.DatastoreItem;
+import jalview.io.vamsas.DatastoreRegistry;
+import jalview.io.vamsas.Rangetype;
+import jalview.util.MessageManager;
+import jalview.viewmodel.AlignmentViewport;
+
+import java.io.IOException;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
 import java.util.Vector;
-
-import uk.ac.vamsas.client.*;
-import uk.ac.vamsas.objects.core.*;
+import java.util.jar.JarInputStream;
+import java.util.jar.JarOutputStream;
+
+import uk.ac.vamsas.client.IClientAppdata;
+import uk.ac.vamsas.client.IClientDocument;
+import uk.ac.vamsas.client.Vobject;
+import uk.ac.vamsas.client.VorbaId;
+import uk.ac.vamsas.objects.core.Alignment;
+import uk.ac.vamsas.objects.core.AlignmentSequence;
+import uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation;
+import uk.ac.vamsas.objects.core.AnnotationElement;
+import uk.ac.vamsas.objects.core.DataSet;
+import uk.ac.vamsas.objects.core.DataSetAnnotations;
+import uk.ac.vamsas.objects.core.DbRef;
+import uk.ac.vamsas.objects.core.Entry;
+import uk.ac.vamsas.objects.core.Glyph;
+import uk.ac.vamsas.objects.core.Local;
+import uk.ac.vamsas.objects.core.MapType;
+import uk.ac.vamsas.objects.core.Mapped;
+import uk.ac.vamsas.objects.core.Property;
+import uk.ac.vamsas.objects.core.Provenance;
+import uk.ac.vamsas.objects.core.RangeAnnotation;
+import uk.ac.vamsas.objects.core.RangeType;
+import uk.ac.vamsas.objects.core.Seg;
+import uk.ac.vamsas.objects.core.Sequence;
+import uk.ac.vamsas.objects.core.SequenceType;
+import uk.ac.vamsas.objects.core.VAMSAS;
+import uk.ac.vamsas.objects.utils.Properties;
 
 /*
  *
@@ -46,47 +81,83 @@ import uk.ac.vamsas.objects.core.*;
  * "org.exolab.castor.serializer", "org.apache.xml.serialize.XMLSerilazizer"); }
  *
  */
-
+/*
+ * TODO: check/verify consistency for vamsas sync with group associated alignment annotation
+ */
 public class VamsasAppDatastore
 {
-  Entry provEntry = null;
+  /**
+   * Type used for general jalview generated annotation added to vamsas document
+   */
+  public static final String JALVIEW_ANNOTATION_ROW = "JalviewAnnotation";
 
-  // AlignViewport av;
+  /**
+   * AlignmentAnnotation property to indicate that values should not be
+   * interpolated
+   */
+  public static final String DISCRETE_ANNOTATION = "discrete";
 
-  org.exolab.castor.types.Date date = new org.exolab.castor.types.Date(
-      new java.util.Date());
+  /**
+   * continuous property - optional to specify that annotation should be
+   * represented as a continous graph line
+   */
+  private static final String CONTINUOUS_ANNOTATION = "continuous";
 
+  private static final String THRESHOLD = "threshold";
+
+  /**
+   * template for provenance entries written to vamsas session document
+   */
+  Entry provEntry = null;
+
+  /**
+   * Instance of the session document being synchronized with
+   */
   IClientDocument cdoc;
 
+  /**
+   * map Vorba (vamsas object xml ref) IDs to live jalview object references
+   */
   Hashtable vobj2jv;
 
+  /**
+   * map live jalview object references to Vorba IDs
+   */
   IdentityHashMap jv2vobj;
 
+  /**
+   * map jalview sequence set ID (which is vorba ID for alignment) to last
+   * recorded hash value for the alignment viewport (the undo/redo hash value)
+   */
+  Hashtable alignRDHash;
+
   public VamsasAppDatastore(IClientDocument cdoc, Hashtable vobj2jv,
-                         IdentityHashMap jv2vobj, Entry provEntry)
+          IdentityHashMap jv2vobj, Entry provEntry, Hashtable alignRDHash)
   {
     this.cdoc = cdoc;
     this.vobj2jv = vobj2jv;
     this.jv2vobj = jv2vobj;
     this.provEntry = provEntry;
+    this.alignRDHash = alignRDHash;
+    buildSkipList();
   }
 
-  /*
-   * public void storeJalview(String file, AlignFrame af) { try { // 1. Load the
-   * mapping information from the file Mapping map = new
-   * Mapping(getClass().getClassLoader()); java.net.URL url =
-   * getClass().getResource("/jalview_mapping.xml"); map.loadMapping(url); // 2.
-   * Unmarshal the data // Unmarshaller unmar = new Unmarshaller();
-   * //unmar.setIgnoreExtraElements(true); //unmar.setMapping(map); // uni =
-   * (UniprotFile) unmar.unmarshal(new FileReader(file)); // 3. marshal the data
-   * with the total price back and print the XML in the console Marshaller
-   * marshaller = new Marshaller( new FileWriter(file) );
-   *
-   * marshaller.setMapping(map); marshaller.marshal(af); } catch (Exception e) {
-   * e.printStackTrace(); } }
-   *
-   *
+  /**
+   * the skipList used to skip over views from Jalview Appdata's that we've
+   * already syncrhonized
    */
+  Hashtable skipList;
+
+  private void buildSkipList()
+  {
+    skipList = new Hashtable();
+    AlignFrame[] al = Desktop.getAlignFrames();
+    for (int f = 0; al != null && f < al.length; f++)
+    {
+      skipList.put(al[f].getViewport().getSequenceSetId(), al[f]);
+    }
+  }
+
   /**
    * @return the Vobject bound to Jalview datamodel object
    */
@@ -94,17 +165,49 @@ public class VamsasAppDatastore
   {
     if (jv2vobj.containsKey(jvobj))
     {
-      return cdoc.getObject( (VorbaId) jv2vobj.get(jvobj));
+      return cdoc.getObject((VorbaId) jv2vobj.get(jvobj));
+    }
+    // check if we're working with a string - then workaround
+    // the use of IdentityHashTable because different strings
+    // have different object IDs.
+    if (jvobj instanceof String)
+    {
+      Object seqsetidobj = null;
+      seqsetidobj = getVamsasObjectBinding().get(jvobj);
+      if (seqsetidobj != null)
+      {
+        if (seqsetidobj instanceof String)
+        {
+          // what is expected. object returned by av.getSequenceSetId() -
+          // reverse lookup to get the 'registered' instance of this string
+          Vobject obj = getjv2vObj(seqsetidobj);
+          if (obj != null && !(obj instanceof Alignment))
+          {
+            Cache.log
+                    .warn("IMPLEMENTATION ERROR?: Unexpected mapping for unmapped jalview string object content:"
+                            + seqsetidobj + " to object " + obj);
+          }
+          return obj;
+        }
+        else
+        {
+          Cache.log.warn("Unexpected mapping for Jalview String Object ID "
+                  + seqsetidobj + " to another jalview dataset object "
+                  + seqsetidobj);
+        }
+      }
     }
+
     if (Cache.log.isDebugEnabled())
     {
-      Cache.log.debug("Returning null VorbaID binding for jalview object "+jvobj);
+      Cache.log.debug("Returning null VorbaID binding for jalview object "
+              + jvobj);
     }
     return null;
   }
 
   /**
-   *
+   * 
    * @param vobj
    * @return Jalview datamodel object bound to the vamsas document object
    */
@@ -115,7 +218,7 @@ public class VamsasAppDatastore
     {
       id = cdoc.registerObject(vobj);
       Cache.log
-          .debug("Registering new object and returning null for getvObj2jv");
+              .debug("Registering new object and returning null for getvObj2jv");
       return null;
     }
     if (vobj2jv.containsKey(vobj.getVorbaId()))
@@ -131,32 +234,41 @@ public class VamsasAppDatastore
     if (id == null)
     {
       id = cdoc.registerObject(vobj);
-      if (id == null || vobj.getVorbaId() == null || cdoc.getObject(id)!=vobj)
+      if (id == null || vobj.getVorbaId() == null
+              || cdoc.getObject(id) != vobj)
       {
-        Cache.log.error("Failed to get id for " +
-                        (vobj.isRegisterable() ? "registerable" :
-                         "unregisterable") + " object " + vobj);
+        Cache.log.error("Failed to get id for "
+                + (vobj.isRegisterable() ? "registerable"
+                        : "unregisterable") + " object " + vobj);
       }
     }
 
-    if (vobj2jv.containsKey(vobj.getVorbaId()) &&
-        ! ( (VorbaId) vobj2jv.get(vobj.getVorbaId())).equals(jvobj))
+    if (vobj2jv.containsKey(vobj.getVorbaId())
+            && !((VorbaId) vobj2jv.get(vobj.getVorbaId())).equals(jvobj))
     {
-      Cache.log.debug("Warning? Overwriting existing vamsas id binding for " +
-                      vobj.getVorbaId(),
-                      new Exception("Overwriting vamsas id binding."));
+      Cache.log
+              .debug("Warning? Overwriting existing vamsas id binding for "
+                      + vobj.getVorbaId(),
+                      new Exception(
+                              MessageManager
+                                      .getString("exception.overwriting_vamsas_id_binding")));
     }
-    else if (jv2vobj.containsKey(jvobj) &&
-             ! ( (VorbaId) jv2vobj.get(jvobj)).equals(vobj.getVorbaId()))
+    else if (jv2vobj.containsKey(jvobj)
+            && !((VorbaId) jv2vobj.get(jvobj)).equals(vobj.getVorbaId()))
     {
       Cache.log.debug(
-          "Warning? Overwriting existing jalview object binding for " + jvobj,
-          new Exception("Overwriting jalview object binding."));
+              "Warning? Overwriting existing jalview object binding for "
+                      + jvobj, new Exception(
+                      "Overwriting jalview object binding."));
     }
-    /* Cache.log.error("Attempt to make conflicting object binding! "+vobj+" id " +vobj.getVorbaId()+" already bound to "+getvObj2jv(vobj)+" and "+jvobj+" already bound to "+getjv2vObj(jvobj),new Exception("Excessive call to bindjvvobj"));
-         }*/
+    /*
+     * Cache.log.error("Attempt to make conflicting object binding! "+vobj+" id "
+     * +vobj.getVorbaId()+" already bound to "+getvObj2jv(vobj)+" and "+jvobj+"
+     * already bound to "+getjv2vObj(jvobj),new Exception("Excessive call to
+     * bindjvvobj")); }
+     */
     // we just update the hash's regardless!
-    Cache.log.debug("Binding "+vobj.getVorbaId()+" to "+jvobj);
+    Cache.log.debug("Binding " + vobj.getVorbaId() + " to " + jvobj);
     vobj2jv.put(vobj.getVorbaId(), jvobj);
     // JBPNote - better implementing a hybrid invertible hash.
     jv2vobj.put(jvobj, vobj.getVorbaId());
@@ -164,33 +276,91 @@ public class VamsasAppDatastore
 
   /**
    * put the alignment viewed by AlignViewport into cdoc.
-   *
-   * @param av alignViewport to be stored
-   * @param aFtitle title for alignment
+   * 
+   * @param av
+   *          alignViewport to be stored
+   * @param aFtitle
+   *          title for alignment
+   * @return true if alignment associated with viewport was stored/synchronized
+   *         to document
    */
-  public void storeVAMSAS(AlignViewport av, String aFtitle)
+  public boolean storeVAMSAS(AlignViewport av, String aFtitle)
   {
     try
     {
       jalview.datamodel.AlignmentI jal = av.getAlignment();
+      jalview.datamodel.AlignmentI jds = jal.getDataset();
       boolean nw = false;
       VAMSAS root = null; // will be resolved based on Dataset Parent.
       // /////////////////////////////////////////
       // SAVE THE DATASET
-      if (jal.getDataset() == null)
+      DataSet dataset = null;
+      if (jds == null)
       {
         Cache.log.warn("Creating new dataset for an alignment.");
         jal.setDataset(null);
+        jds = jal.getDataset();
+      }
+
+      // try and get alignment and association for sequence set id
+
+      Alignment alignment = (Alignment) getjv2vObj(av.getSequenceSetId());
+      if (alignment != null)
+      {
+        dataset = (DataSet) alignment.getV_parent();
+      }
+      else
+      {
+        // is the dataset already registered
+        dataset = (DataSet) getjv2vObj(jds);
       }
-      DataSet dataset = (DataSet) getjv2vObj(jal.getDataset());
+
+      if (dataset == null)
+      {
+        // it might be that one of the dataset sequences does actually have a
+        // binding, so search for it indirectly. If it does, then the local
+        // jalview dataset
+        // must be merged with the existing vamsas dataset.
+        jalview.datamodel.SequenceI[] jdatset = jds.getSequencesArray();
+        for (int i = 0; i < jdatset.length; i++)
+        {
+          Vobject vbound = getjv2vObj(jdatset[i]);
+          if (vbound != null)
+          {
+            if (vbound instanceof uk.ac.vamsas.objects.core.Sequence)
+            {
+              if (dataset == null)
+              {
+                dataset = (DataSet) vbound.getV_parent();
+              }
+              else
+              {
+                if (vbound.getV_parent() != null
+                        && dataset != vbound.getV_parent())
+                {
+                  throw new Error(
+                          MessageManager
+                                  .getString("error.implementation_error_cannot_map_alignment_sequences"));
+                  // This occurs because the dataset for the alignment we are
+                  // trying to
+                }
+              }
+            }
+          }
+        }
+      }
+
       if (dataset == null)
       {
+        Cache.log.warn("Creating new vamsas dataset for alignment view "
+                + av.getSequenceSetId());
+        // we create a new dataset on the default vamsas root.
         root = cdoc.getVamsasRoots()[0]; // default vamsas root for modifying.
         dataset = new DataSet();
         root.addDataSet(dataset);
-        bindjvvobj(jal.getDataset(), dataset);
+        bindjvvobj(jds, dataset);
         dataset.setProvenance(dummyProvenance());
-        dataset.getProvenance().addEntry(provEntry);
+        // dataset.getProvenance().addEntry(provEntry);
         nw = true;
       }
       else
@@ -199,117 +369,53 @@ public class VamsasAppDatastore
       }
       // update dataset
       Sequence sequence;
-      DbRef dbref;
       // set new dataset and alignment sequences based on alignment Nucleotide
       // flag.
       // this *will* break when alignment contains both nucleotide and amino
       // acid sequences.
-      String dict = jal.isNucleotide() ?
-          uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA
-          : uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_AA;
+      String dict = jal.isNucleotide() ? uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA
+              : uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_AA;
+      Vector dssmods = new Vector();
       for (int i = 0; i < jal.getHeight(); i++)
       {
         SequenceI sq = jal.getSequenceAt(i).getDatasetSequence(); // only insert
         // referenced
         // sequences
         // to dataset.
-        sequence = (Sequence) getjv2vObj(sq);
-        if (sequence == null)
-        {
-          sequence = new Sequence();
-          bindjvvobj(sq, sequence);
-          sq.setVamsasId(sequence.getVorbaId().getId());
-          sequence.setSequence(sq.getSequenceAsString());
-          sequence.setDictionary(dict);
-          sequence.setName(jal.getDataset().getSequenceAt(i).getName());
-          sequence.setStart(jal.getDataset().getSequenceAt(i).getStart());
-          sequence.setEnd(jal.getDataset().getSequenceAt(i).getEnd());
-          dataset.addSequence(sequence);
-        }
-        else
-        {
-          // verify principal attributes. and update any new
-          // features/references.
-          System.out.println("update dataset sequence object.");
-        }
-        if (sq.getSequenceFeatures() != null)
+        Datasetsequence dssync = new jalview.io.vamsas.Datasetsequence(
+                this, sq, dict, dataset);
+        sequence = (Sequence) dssync.getVobj();
+        if (dssync.getModified())
         {
-          int sfSize = sq.getSequenceFeatures().length;
-
-          for (int sf = 0; sf < sfSize; sf++)
-          {
-            jalview.datamodel.SequenceFeature feature = (jalview.datamodel.
-                SequenceFeature) sq
-                .getSequenceFeatures()[sf];
-
-            DataSetAnnotations dsa = (DataSetAnnotations) getjv2vObj(feature);
-            if (dsa == null)
-            {
-              dsa = (DataSetAnnotations) getDSAnnotationFromJalview(
-                  new DataSetAnnotations(), feature);
-              if (dsa.getProvenance() == null)
-              {
-                dsa.setProvenance(new Provenance());
-              }
-              addProvenance(dsa.getProvenance(), "created"); // JBPNote - need
-              // to update
-              dsa.setSeqRef(sequence);
-              bindjvvobj(feature, dsa);
-              dataset.addDataSetAnnotations(dsa);
-            }
-            else
-            {
-              // todo: verify and update dataset annotations for sequence
-              System.out.println("update dataset sequence annotations.");
-            }
-          }
+          dssmods.addElement(sequence);
         }
-
-        if (sq.getDBRef() != null)
+        ;
+      }
+      if (dssmods.size() > 0)
+      {
+        if (!nw)
         {
-          DBRefEntry[] entries = sq.getDBRef();
-          jalview.datamodel.DBRefEntry dbentry;
-          for (int db = 0; db < entries.length; db++)
-          {
-            dbentry = entries[db];
-            dbref = (DbRef) getjv2vObj(dbentry);
-            if (dbref == null)
-            {
-              dbref = new DbRef();
-              bindjvvobj(dbentry, dbref);
-              dbref.setAccessionId(dbentry.getAccessionId());
-              dbref.setSource(dbentry.getSource());
-              dbref.setVersion(dbentry.getVersion());
-              /*
-               * TODO: Maps are not yet supported by Jalview. Map vMap = new
-               * Map(); vMap.set dbref.addMap(vMap);
-               */
-              sequence.addDbRef(dbref);
-            }
-            else
-            {
-              // TODO: verify and update dbrefs in vamsas document
-              // there will be trouble when a dataset sequence is modified to
-              // contain more residues than were originally referenced - we must
-              // then make a number of dataset sequence entries
-              System.out
-                  .println("update dataset sequence database references.");
-            }
-          }
-
+          Entry pentry = this.addProvenance(dataset.getProvenance(),
+                  "updated sequences");
+          // pentry.addInput(vInput); could write in which sequences were
+          // modified.
+          dssmods.removeAllElements();
         }
       }
       // dataset.setProvenance(getVamsasProvenance(jal.getDataset().getProvenance()));
       // ////////////////////////////////////////////
+      if (alignmentWillBeSkipped(av))
+      {
+        // TODO: trees could be written - but for the moment we just
+        addToSkipList(av);
+        // add to the JalviewXML skipList and ..
+        return false;
+      }
 
-      // ////////////////////////////////////////////
-      // Save the Alignments
-
-      Alignment alignment = (Alignment) getjv2vObj(av); // this is so we can get the alignviewport back
       if (alignment == null)
       {
         alignment = new Alignment();
-        bindjvvobj(av, alignment);
+        bindjvvobj(av.getSequenceSetId(), alignment);
         if (alignment.getProvenance() == null)
         {
           alignment.setProvenance(new Provenance());
@@ -320,80 +426,116 @@ public class VamsasAppDatastore
         dataset.addAlignment(alignment);
         {
           Property title = new Property();
-          title.setName("jalview:AlTitle");
+          title.setName("title");
           title.setType("string");
           title.setContent(aFtitle);
           alignment.addProperty(title);
         }
         alignment.setGapChar(String.valueOf(av.getGapCharacter()));
-        AlignmentSequence alseq = null;
         for (int i = 0; i < jal.getHeight(); i++)
         {
-          alseq = new AlignmentSequence();
-          // TODO: VAMSAS: translate lowercase symbols to annotation ?
-          alseq.setSequence(jal.getSequenceAt(i).getSequenceAsString());
-          alseq.setName(jal.getSequenceAt(i).getName());
-          alseq.setStart(jal.getSequenceAt(i).getStart());
-          alseq.setEnd(jal.getSequenceAt(i).getEnd());
-          if (getjv2vObj(jal.getSequenceAt(i).getDatasetSequence())==null)
-          {
-            Cache.log.warn("Serious. Unbound dataset sequence in alignment: "+jal.getSequenceAt(i).getDatasetSequence());
-          }
-          alseq.setRefid(getjv2vObj(jal.getSequenceAt(i).getDatasetSequence()));
-          alignment.addAlignmentSequence(alseq);
-          bindjvvobj(jal.getSequenceAt(i), alseq);
+          syncToAlignmentSequence(jal.getSequenceAt(i), alignment, null);
         }
+        alignRDHash.put(av.getSequenceSetId(), av.getUndoRedoHash());
       }
       else
       {
+        // always prepare to clone the alignment
+        boolean alismod = av.isUndoRedoHashModified((long[]) alignRDHash
+                .get(av.getSequenceSetId()));
         // todo: verify and update mutable alignment props.
-        if (alignment.getModifiable()==null) // TODO: USE VAMSAS LIBRARY OBJECT LOCK METHODS
+        // TODO: Use isLocked methods
+        if (alignment.getModifiable() == null
+                || alignment.getModifiable().length() == 0)
+        // && !alignment.isDependedOn())
         {
-          System.out.println("update alignment in document.");
+          boolean modified = false;
+          // check existing sequences in local and in document.
+          Vector docseqs = new Vector(
+                  alignment.getAlignmentSequenceAsReference());
+          for (int i = 0; i < jal.getHeight(); i++)
+          {
+            modified |= syncToAlignmentSequence(jal.getSequenceAt(i),
+                    alignment, docseqs);
+          }
+          if (docseqs.size() > 0)
+          {
+            // removeValignmentSequences(alignment, docseqs);
+            docseqs.removeAllElements();
+            System.out
+                    .println("Sequence deletion from alignment is not implemented.");
+
+          }
+          if (modified)
+          {
+            if (alismod)
+            {
+              // info in the undo
+              addProvenance(alignment.getProvenance(), "Edited"); // TODO:
+              // insert
+              // something
+              // sensible
+              // here again
+            }
+            else
+            {
+              // info in the undo
+              addProvenance(alignment.getProvenance(), "Attributes Edited"); // TODO:
+              // insert
+              // something
+              // sensible
+              // here
+              // again
+            }
+          }
+          if (alismod)
+          {
+            System.out.println("update alignment in document.");
+          }
+          else
+          {
+            System.out.println("alignment in document left unchanged.");
+          }
         }
         else
         {
+          // unbind alignment from view.
+          // create new binding and new alignment.
+          // mark trail on new alignment as being derived from old ?
           System.out
-              .println("update edited alignment to new alignment in document.");
+                  .println("update edited alignment to new alignment in document.");
         }
       }
       // ////////////////////////////////////////////
       // SAVE Alignment Sequence Features
-      for (int i = 0, iSize = alignment.getAlignmentSequenceCount(); i < iSize;
-           i++)
+      for (int i = 0, iSize = alignment.getAlignmentSequenceCount(); i < iSize; i++)
       {
         AlignmentSequence valseq;
         SequenceI alseq = (SequenceI) getvObj2jv(valseq = alignment
-                                                 .getAlignmentSequence(i));
+                .getAlignmentSequence(i));
         if (alseq != null && alseq.getSequenceFeatures() != null)
         {
-          jalview.datamodel.SequenceFeature[] features = alseq
-              .getSequenceFeatures();
-          for (int f = 0; f < features.length; f++)
-          {
-            if (features[f] != null)
-            {
-              AlignmentSequenceAnnotation valseqf = (
-                  AlignmentSequenceAnnotation) getjv2vObj(features[i]);
-              if (valseqf == null)
-              {
-
-                valseqf = (AlignmentSequenceAnnotation)
-                    getDSAnnotationFromJalview(
-                        new AlignmentSequenceAnnotation(), features[i]);
-                if (valseqf.getProvenance() == null)
-                {
-                  valseqf.setProvenance(new Provenance());
-                }
-                addProvenance(valseqf.getProvenance(), "created"); // JBPNote -
-                // need to
-                // update
-                bindjvvobj(features[i], valseqf);
-                valseq.addAlignmentSequenceAnnotation(valseqf);
-              }
-            }
-
-          }
+          /*
+           * We do not put local Alignment Sequence Features into the vamsas
+           * document yet.
+           * 
+           * 
+           * jalview.datamodel.SequenceFeature[] features = alseq
+           * .getSequenceFeatures(); for (int f = 0; f < features.length; f++) {
+           * if (features[f] != null) { AlignmentSequenceAnnotation valseqf = (
+           * AlignmentSequenceAnnotation) getjv2vObj(features[i]); if (valseqf
+           * == null) {
+           * 
+           * valseqf = (AlignmentSequenceAnnotation) getDSAnnotationFromJalview(
+           * new AlignmentSequenceAnnotation(), features[i]);
+           * valseqf.setGraph(false);
+           * valseqf.addProperty(newProperty("jalview:feature"
+           * ,"boolean","true")); if (valseqf.getProvenance() == null) {
+           * valseqf.setProvenance(new Provenance()); }
+           * addProvenance(valseqf.getProvenance(), "created"); // JBPNote - //
+           * need to // update bindjvvobj(features[i], valseqf);
+           * valseq.addAlignmentSequenceAnnotation(valseqf); } } }
+           */
         }
       }
 
@@ -402,7 +544,7 @@ public class VamsasAppDatastore
       if (jal.getAlignmentAnnotation() != null)
       {
         jalview.datamodel.AlignmentAnnotation[] aa = jal
-            .getAlignmentAnnotation();
+                .getAlignmentAnnotation();
         java.util.HashMap AlSeqMaps = new HashMap(); // stores int maps from
         // alignment columns to
         // sequence positions.
@@ -412,133 +554,53 @@ public class VamsasAppDatastore
           {
             continue;
           }
+          if (aa[i].groupRef != null)
+          {
+            // TODO: store any group associated annotation references
+            Cache.log
+                    .warn("Group associated sequence annotation is not stored in VAMSAS document.");
+            continue;
+          }
           if (aa[i].sequenceRef != null)
           {
-            uk.ac.vamsas.objects.core.AlignmentSequence alsref = (uk.ac.vamsas.
-                objects.core.AlignmentSequence) getjv2vObj(aa[i].sequenceRef);
-            uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation an = (uk.ac.
-                vamsas.objects.core.AlignmentSequenceAnnotation) getjv2vObj(aa[
-                i]);
-            int[] gapMap = null;
-            if (AlSeqMaps.containsKey(aa[i].sequenceRef))
+            // Deal with sequence associated annotation
+            Vobject sref = getjv2vObj(aa[i].sequenceRef);
+            if (sref instanceof uk.ac.vamsas.objects.core.AlignmentSequence)
             {
-              gapMap = (int[]) AlSeqMaps.get(aa[i].sequenceRef);
+              saveAlignmentSequenceAnnotation(AlSeqMaps,
+                      (AlignmentSequence) sref, aa[i]);
             }
             else
             {
-              gapMap = new int[aa[i].sequenceRef.getLength()];
-              // map from alignment position to sequence position.
-              int[] sgapMap = aa[i].sequenceRef.gapMap();
-              for (int a = 0; a < sgapMap.length; a++)
-              {
-                gapMap[sgapMap[a]] = a;
-              }
-            }
-            if (an == null)
-            {
-              an = new uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation();
-              Seg vSeg = new Seg();
-              vSeg.setStart(1);
-              vSeg.setInclusive(true);
-              vSeg.setEnd(gapMap.length);
-              an.addSeg(vSeg);
-              an.setType("jalview:SecondaryStructurePrediction"); // TODO: better fix this rough guess ;)
-              alsref.addAlignmentSequenceAnnotation(an);
-              bindjvvobj(aa[i], an);
-              // LATER: much of this is verbatim from the alignmentAnnotation
-              // method below. suggests refactoring to make rangeAnnotation the
-              // base class
-              an.setDescription(aa[i].description);
-              if (aa[i].graph > 0)
+              // first find the alignment sequence to associate this with.
+              for (SequenceI jvalsq : av.getAlignment().getSequences())
               {
-                an.setGraph(true); // aa[i].graph);
-              }
-              else
-              {
-                an.setGraph(false);
-              }
-              an.setLabel(aa[i].label);
-              an.setProvenance(dummyProvenance()); // get provenance as user
-              // created, or jnet, or
-              // something else.
-              an.setGroup(Integer.toString(aa[i].graphGroup)); // // JBPNote -
-              // originally we
-              // were going to
-              // store
-              // graphGroup in
-              // the Jalview
-              // specific
-              // bits.
-              AnnotationElement ae;
-              for (int a = 0; a < aa[i].annotations.length; a++)
-              {
-                if (aa[i].annotations[a] == null)
-                {
-                  continue;
-                }
-
-                ae = new AnnotationElement();
-                ae.setDescription(aa[i].annotations[a].description);
-                ae.addGlyph(new Glyph());
-                ae.getGlyph(0)
-                    .setContent(aa[i].annotations[a].displayCharacter); // assume
-                // jax-b
-                // takes
-                // care
-                // of
-                // utf8
-                // translation
-                if (aa[i].graph !=
-                    jalview.datamodel.AlignmentAnnotation.NO_GRAPH)
+                // saveDatasetSequenceAnnotation(AlSeqMaps,(uk.ac.vamsas.objects.core.Sequence)
+                // sref, aa[i]);
+                if (jvalsq.getDatasetSequence() == aa[i].sequenceRef)
                 {
-                  ae.addValue(aa[i].annotations[a].value);
-                }
-                ae.setPosition(gapMap[a] + 1); // position w.r.t. AlignmentSequence
-                // symbols
-                if (aa[i].annotations[a].secondaryStructure != ' ')
-                {
-                  // we only write an annotation where it really exists.
-                  Glyph ss = new Glyph();
-                  ss
-                      .setDict(uk.ac.vamsas.objects.utils.GlyphDictionary.
-                               PROTEIN_SS_3STATE);
-                  ss.setContent(String
-                                .valueOf(aa[i].annotations[a].
-                                         secondaryStructure));
-                  ae.addGlyph(ss);
+                  Vobject alsref = getjv2vObj(jvalsq);
+                  saveAlignmentSequenceAnnotation(AlSeqMaps,
+                          (AlignmentSequence) alsref, aa[i]);
+                  break;
                 }
-                an.addAnnotationElement(ae);
-              }
-            }
-            else
-            {
-              // update reference sequence Annotation
-              if (an.getModifiable()==null) // TODO: USE VAMSAS LIBRARY OBJECT LOCK METHODS)
-              {
-                // verify existing alignment sequence annotation is up to date
-                System.out.println("update alignment sequence annotation.");
-              }
-              else
-              {
-                // verify existing alignment sequence annotation is up to date
-                System.out
-                    .println(
-                    "make new alignment sequence annotation if modification has happened.");
+                ;
               }
             }
           }
           else
           {
             // add Alignment Annotation
-            uk.ac.vamsas.objects.core.AlignmentAnnotation an = (uk.ac.vamsas.
-                objects.core.AlignmentAnnotation) getjv2vObj(aa[i]);
+            uk.ac.vamsas.objects.core.AlignmentAnnotation an = (uk.ac.vamsas.objects.core.AlignmentAnnotation) getjv2vObj(aa[i]);
             if (an == null)
             {
               an = new uk.ac.vamsas.objects.core.AlignmentAnnotation();
-              an.setType("jalview:AnnotationRow");
+              an.setType(JALVIEW_ANNOTATION_ROW);
               an.setDescription(aa[i].description);
               alignment.addAlignmentAnnotation(an);
-              Seg vSeg = new Seg();
+              Seg vSeg = new Seg(); // TODO: refactor to have a default
+              // rangeAnnotationType initer/updater that
+              // takes a set of int ranges.
               vSeg.setStart(1);
               vSeg.setInclusive(true);
               vSeg.setEnd(jal.getWidth());
@@ -549,9 +611,10 @@ public class VamsasAppDatastore
               }
               an.setLabel(aa[i].label);
               an.setProvenance(dummyProvenance());
-              if (aa[i].graph != aa[i].NO_GRAPH)
+              if (aa[i].graph != AlignmentAnnotation.NO_GRAPH)
               {
-                an.setGroup(Integer.toString(aa[i].graphGroup)); // // JBPNote -
+                an.setGroup(Integer.toString(aa[i].graphGroup)); // // JBPNote
+                // -
                 // originally we
                 // were going to
                 // store
@@ -569,7 +632,7 @@ public class VamsasAppDatastore
 
               for (int a = 0; a < aa[i].annotations.length; a++)
               {
-                if ( (aa[i] == null) || (aa[i].annotations[a] == null))
+                if ((aa[i] == null) || (aa[i].annotations[a] == null))
                 {
                   continue;
                 }
@@ -577,64 +640,71 @@ public class VamsasAppDatastore
                 ae = new AnnotationElement();
                 ae.setDescription(aa[i].annotations[a].description);
                 ae.addGlyph(new Glyph());
-                ae.getGlyph(0)
-                    .setContent(aa[i].annotations[a].displayCharacter); // assume
+                ae.getGlyph(0).setContent(
+                        aa[i].annotations[a].displayCharacter); // assume
                 // jax-b
                 // takes
                 // care
                 // of
                 // utf8
                 // translation
-                ae.addValue(aa[i].annotations[a].value);
+                if (an.isGraph())
+                {
+                  ae.addValue(aa[i].annotations[a].value);
+                }
                 ae.setPosition(a + 1);
                 if (aa[i].annotations[a].secondaryStructure != ' ')
                 {
                   Glyph ss = new Glyph();
-                  ss
-                      .setDict(uk.ac.vamsas.objects.utils.GlyphDictionary.
-                               PROTEIN_SS_3STATE);
+                  ss.setDict(uk.ac.vamsas.objects.utils.GlyphDictionary.PROTEIN_SS_3STATE);
                   ss.setContent(String
-                                .valueOf(aa[i].annotations[a].
-                                         secondaryStructure));
+                          .valueOf(aa[i].annotations[a].secondaryStructure));
                   ae.addGlyph(ss);
                 }
                 an.addAnnotationElement(ae);
               }
               if (aa[i].editable)
               {
-                //an.addProperty(newProperty("jalview:editable", null, "true"));
-                // an.setModifiable(""); // TODO: This is not the way the modifiable flag is supposed to be used.
+                // an.addProperty(newProperty("jalview:editable", null,
+                // "true"));
+                // an.setModifiable(""); // TODO: This is not the way the
+                // modifiable flag is supposed to be used.
               }
+              setAnnotationType(an, aa[i]);
+
               if (aa[i].graph != jalview.datamodel.AlignmentAnnotation.NO_GRAPH)
               {
                 an.setGraph(true);
                 an.setGroup(Integer.toString(aa[i].graphGroup));
-                an.addProperty(newProperty("jalview:graphType", null,
-                                           ( (aa[i].graph ==
-                                              jalview.datamodel.AlignmentAnnotation.
-                                              BAR_GRAPH) ? "BAR_GRAPH" :
-                                            "LINE_GRAPH")));
-
-                /** and on and on..
-                 vProperty=new Property();
-                  vProperty.setName("jalview:graphThreshhold");
-                  vProperty.setContent(aa[i].threshold);
-                 */
-
+                if (aa[i].threshold != null && aa[i].threshold.displayed)
+                {
+                  an.addProperty(Properties.newProperty(THRESHOLD,
+                          Properties.FLOATTYPE, "" + aa[i].threshold.value));
+                  if (aa[i].threshold.label != null)
+                  {
+                    an.addProperty(Properties.newProperty(THRESHOLD
+                            + "Name", Properties.STRINGTYPE, ""
+                            + aa[i].threshold.label));
+                  }
+                }
               }
+
             }
+
             else
             {
-              if (an.getModifiable()==null) // TODO: USE VAMSAS LIBRARY OBJECT LOCK METHODS)
+              if (an.getModifiable() == null) // TODO: USE VAMSAS LIBRARY OBJECT
+              // LOCK METHODS)
               {
                 // verify annotation - update (perhaps)
-                Cache.log.info(
-                    "update alignment sequence annotation. not yet implemented.");
+                Cache.log
+                        .info("update alignment sequence annotation. not yet implemented.");
               }
               else
               {
                 // verify annotation - update (perhaps)
-                Cache.log.info("updated alignment sequence annotation added.");
+                Cache.log
+                        .info("updated alignment sequence annotation added.");
               }
             }
           }
@@ -648,7 +718,8 @@ public class VamsasAppDatastore
       // FIND ANY ASSOCIATED TREES
       if (Desktop.desktop != null)
       {
-        javax.swing.JInternalFrame[] frames = Desktop.instance.getAllFrames();
+        javax.swing.JInternalFrame[] frames = Desktop.instance
+                .getAllFrames();
 
         for (int t = 0; t < frames.length; t++)
         {
@@ -656,36 +727,11 @@ public class VamsasAppDatastore
           {
             TreePanel tp = (TreePanel) frames[t];
 
-            if (tp.getAlignment() == jal)
+            if (tp.getViewPort().getSequenceSetId()
+                    .equals(av.getSequenceSetId()))
             {
-              Tree tree = (Tree) getjv2vObj(tp);
-              if (tree == null)
-              {
-                tree = new Tree();
-                bindjvvobj(tp, tree);
-                tree.setTitle(tp.getTitle());
-                Newick newick = new Newick();
-                // TODO: translate sequenceI to leaf mappings to vamsas
-                // references - see tree specification in schema.
-                newick.setContent(tp.getTree().toString());
-                newick.setTitle(tp.getTitle());
-                tree.addNewick(newick);
-                tree.setProvenance(makeTreeProvenance(jal, tp));
-                alignment.addTree(tree);
-              }
-              else
-              {
-                if (tree.getModifiable()==null) // TODO: USE VAMSAS LIBRARY OBJECT LOCK METHODS)
-                {
-                  // verify any changes.
-                  System.out.println("Update tree in document.");
-                }
-                else
-                {
-                  System.out
-                      .println("Add modified tree as new tree in document.");
-                }
-              }
+              DatastoreItem vtree = new jalview.io.vamsas.Tree(this, tp,
+                      jal, alignment);
             }
           }
         }
@@ -697,189 +743,510 @@ public class VamsasAppDatastore
     catch (Exception ex)
     {
       ex.printStackTrace();
+      return false;
     }
+    return true;
+  }
 
+  /**
+   * very quick test to see if the viewport would be stored in the vamsas
+   * document. Reasons for not storing include the unaligned flag being false
+   * (for all sequences, including the hidden ones!)
+   * 
+   * @param av
+   * @return true if alignment associated with this view will be stored in
+   *         document.
+   */
+  public boolean alignmentWillBeSkipped(AlignmentViewport av)
+  {
+    return (!av.getAlignment().isAligned());
   }
 
-  private Property newProperty(String name, String type, String content)
+  private void addToSkipList(AlignmentViewport av)
   {
-    Property vProperty = new Property();
-    vProperty.setName(name);
-    if (type != null)
-    {
-      vProperty.setType(type);
-    }
-    else
+    if (skipList == null)
     {
-      vProperty.setType("String");
+      skipList = new Hashtable();
     }
-    vProperty.setContent(content);
-    return vProperty;
+    skipList.put(av.getSequenceSetId(), av);
   }
 
   /**
-   * correctly create a RangeAnnotation from a jalview sequence feature
-   *
-   * @param dsa
-   *          (typically DataSetAnnotations or AlignmentSequenceAnnotation)
-   * @param feature
-   *          (the feature to be mapped from)
-   * @return
+   * remove docseqs from the given alignment marking provenance appropriately
+   * and removing any references to the sequences.
+   * 
+   * @param alignment
+   * @param docseqs
    */
-  private RangeAnnotation getDSAnnotationFromJalview(RangeAnnotation dsa,
-      SequenceFeature feature)
+  private void removeValignmentSequences(Alignment alignment, Vector docseqs)
   {
-    dsa.setType(feature.getType());
-    Seg vSeg = new Seg();
-    vSeg.setStart(feature.getBegin());
-    vSeg.setEnd(feature.getEnd());
-    vSeg.setInclusive(true);
-    dsa.addSeg(vSeg);
-    dsa.setDescription(feature.getDescription());
-    dsa.setStatus(feature.getStatus());
-    if (feature.links != null && feature.links.size() > 0)
+    // delete these from document. This really needs to be a generic document
+    // API function derived by CASTOR.
+    Enumeration en = docseqs.elements();
+    while (en.hasMoreElements())
     {
-      for (int i = 0, iSize = feature.links.size(); i < iSize; i++)
+      alignment.removeAlignmentSequence((AlignmentSequence) en
+              .nextElement());
+    }
+    Entry pe = addProvenance(alignment.getProvenance(), "Removed "
+            + docseqs.size() + " sequences");
+    en = alignment.enumerateAlignmentAnnotation();
+    Vector toremove = new Vector();
+    while (en.hasMoreElements())
+    {
+      uk.ac.vamsas.objects.core.AlignmentAnnotation alan = (uk.ac.vamsas.objects.core.AlignmentAnnotation) en
+              .nextElement();
+      if (alan.getSeqrefsCount() > 0)
       {
-        String link = (String) feature.links.elementAt(i);
-        int sep = link.indexOf('|');
-        if (sep > -1)
+        int p = 0;
+        Vector storem = new Vector();
+        Enumeration sr = alan.enumerateSeqrefs();
+        while (sr.hasMoreElements())
         {
-          Link vLink = new Link();
-          if (sep > 0)
-          {
-            vLink.setContent(link.substring(0, sep - 1));
-          }
-          else
+          Object alsr = sr.nextElement();
+          if (docseqs.contains(alsr))
           {
-            vLink.setContent("");
+            storem.addElement(alsr);
           }
-          vLink.setHref(link.substring(sep + 1)); // TODO: validate href.
-          dsa.addLink(vLink);
+        }
+        // remove references to the deleted sequences
+        sr = storem.elements();
+        while (sr.hasMoreElements())
+        {
+          alan.removeSeqrefs(sr.nextElement());
+        }
+
+        if (alan.getSeqrefsCount() == 0)
+        {
+          // should then delete alan from dataset
+          toremove.addElement(alan);
         }
       }
     }
-    dsa.setGroup(feature.getFeatureGroup());
-    return dsa;
+    // remove any annotation that used to be associated to a specific bunch of
+    // sequences
+    en = toremove.elements();
+    while (en.hasMoreElements())
+    {
+      alignment
+              .removeAlignmentAnnotation((uk.ac.vamsas.objects.core.AlignmentAnnotation) en
+                      .nextElement());
+    }
+    // TODO: search through alignment annotations to remove any references to
+    // this alignment sequence
   }
 
   /**
-   * correctly creates provenance for trees calculated on an alignment by
-   * jalview.
-   *
-   * @param jal
-   * @param tp
-   * @return
+   * sync a jalview alignment seuqence into a vamsas alignment assumes all lock
+   * transformation/bindings have been sorted out before hand. creates/syncs the
+   * vamsas alignment sequence for jvalsq and adds it to the alignment if
+   * necessary. unbounddocseq is a duplicate of the vamsas alignment sequences
+   * and these are removed after being processed w.r.t a bound jvalsq
+   * 
    */
-  private Provenance makeTreeProvenance(AlignmentI jal, TreePanel tp)
+  private boolean syncToAlignmentSequence(SequenceI jvalsq,
+          Alignment alignment, Vector unbounddocseq)
   {
-    Provenance prov = new Provenance();
-    prov.addEntry(new Entry());
-    prov.getEntry(0).setAction("imported " + tp.getTitle());
-    prov.getEntry(0).setUser(provEntry.getUser());
-    prov.getEntry(0).setApp(provEntry.getApp());
-    prov.getEntry(0).setDate(provEntry.getDate());
-    if (tp.getTree().hasOriginalSequenceData())
-    {
-      Input vInput = new Input();
-      // LATER: check to see if tree input data is contained in this alignment -
-      // or just correctly resolve the tree's seqData to the correct alignment in
-      // the document.
-      // vInput.setObjRef(getjv2vObj(jal));
-      vInput.setObjRef(getjv2vObj(tp.getViewPort()));
-      prov.getEntry(0).setAction("created " + tp.getTitle());
-      prov.getEntry(0).addInput(vInput);
-      vInput.setName("jalview:seqdist");
-      prov.getEntry(0).addParam(new Param());
-      prov.getEntry(0).getParam(0).setName("treeType");
-      prov.getEntry(0).getParam(0).setType("utf8");
-      prov.getEntry(0).getParam(0).setContent("NJ");
-
-      int ranges[] = tp.getTree().seqData.getVisibleContigs();
-      // VisibleContigs are with respect to alignment coordinates. Still need offsets
-      int start = tp.getTree().seqData.getAlignmentOrigin();
-      for (int r = 0; r < ranges.length; r += 2)
-      {
-        Seg visSeg = new Seg();
-        visSeg.setStart(1 + start + ranges[r]);
-        visSeg.setEnd(start + ranges[r + 1]);
-        visSeg.setInclusive(true);
-        vInput.addSeg(visSeg);
+    boolean modal = false;
+    // todo: islocked method here
+    boolean up2doc = false;
+    AlignmentSequence alseq = (AlignmentSequence) getjv2vObj(jvalsq);
+    if (alseq == null)
+    {
+      alseq = new AlignmentSequence();
+      up2doc = true;
+    }
+    else
+    {
+      if (unbounddocseq != null)
+      {
+        unbounddocseq.removeElement(alseq);
       }
     }
-    return prov;
+    // boolean locked = (alignment.getModifiable()==null ||
+    // alignment.getModifiable().length()>0);
+    // TODO: VAMSAS: translate lowercase symbols to annotation ?
+    if (up2doc || !alseq.getSequence().equals(jvalsq.getSequenceAsString()))
+    {
+      alseq.setSequence(jvalsq.getSequenceAsString());
+      alseq.setStart(jvalsq.getStart());
+      alseq.setEnd(jvalsq.getEnd());
+      modal = true;
+    }
+    if (up2doc || !alseq.getName().equals(jvalsq.getName()))
+    {
+      modal = true;
+      alseq.setName(jvalsq.getName());
+    }
+    if (jvalsq.getDescription() != null
+            && (alseq.getDescription() == null || !jvalsq.getDescription()
+                    .equals(alseq.getDescription())))
+    {
+      modal = true;
+      alseq.setDescription(jvalsq.getDescription());
+    }
+    if (getjv2vObj(jvalsq.getDatasetSequence()) == null)
+    {
+      Cache.log
+              .warn("Serious Implementation error - Unbound dataset sequence in alignment: "
+                      + jvalsq.getDatasetSequence());
+    }
+    alseq.setRefid(getjv2vObj(jvalsq.getDatasetSequence()));
+    if (up2doc)
+    {
+
+      alignment.addAlignmentSequence(alseq);
+      bindjvvobj(jvalsq, alseq);
+    }
+    return up2doc || modal;
   }
 
   /**
-   *
-   * @param tp
-   * @return Object[] { AlignmentView, AlignmentI - reference alignment for
-   *         input }
+   * locally sync a jalview alignment seuqence from a vamsas alignment assumes
+   * all lock transformation/bindings have been sorted out before hand.
+   * creates/syncs the jvalsq from the alignment sequence
    */
-  private Object[] recoverInputData(Provenance tp)
+  private boolean syncFromAlignmentSequence(AlignmentSequence valseq,
+          char valGapchar, char gapChar, List<SequenceI> dsseqs)
+
   {
-    for (int pe = 0; pe < tp.getEntryCount(); pe++)
+    boolean modal = false;
+    // todo: islocked method here
+    boolean upFromdoc = false;
+    jalview.datamodel.SequenceI alseq = (SequenceI) getvObj2jv(valseq);
+    if (alseq == null)
     {
-      if (tp.getEntry(pe).getInputCount() > 0)
+      upFromdoc = true;
+    }
+    if (alseq != null)
+    {
+
+      // boolean locked = (alignment.getModifiable()==null ||
+      // alignment.getModifiable().length()>0);
+      // TODO: VAMSAS: translate lowercase symbols to annotation ?
+      if (upFromdoc
+              || !valseq.getSequence().equals(alseq.getSequenceAsString()))
+      {
+        // this might go *horribly* wrong
+        alseq.setSequence(new String(valseq.getSequence()).replace(
+                valGapchar, gapChar));
+        alseq.setStart((int) valseq.getStart());
+        alseq.setEnd((int) valseq.getEnd());
+        modal = true;
+      }
+      if (!valseq.getName().equals(alseq.getName()))
+      {
+        modal = true;
+        alseq.setName(valseq.getName());
+      }
+      if (alseq.getDescription() == null
+              || (valseq.getDescription() != null && !alseq
+                      .getDescription().equals(valseq.getDescription())))
+      {
+        alseq.setDescription(valseq.getDescription());
+        modal = true;
+      }
+      if (modal && Cache.log.isDebugEnabled())
       {
-        if (tp.getEntry(pe).getInputCount() > 1)
+        Cache.log.debug("Updating apparently edited sequence "
+                + alseq.getName());
+      }
+    }
+    else
+    {
+      alseq = new jalview.datamodel.Sequence(valseq.getName(), valseq
+              .getSequence().replace(valGapchar, gapChar),
+              (int) valseq.getStart(), (int) valseq.getEnd());
+
+      Vobject datsetseq = (Vobject) valseq.getRefid();
+      if (datsetseq != null)
+      {
+        alseq.setDatasetSequence((SequenceI) getvObj2jv(datsetseq)); // exceptions
+        if (valseq.getDescription() != null)
         {
-          Cache.log.warn("Ignoring additional input spec in provenance entry "
-                         + tp.getEntry(pe).toString());
+          alseq.setDescription(valseq.getDescription());
         }
-        // LATER: deal sensibly with multiple inputs.
-        Input vInput = tp.getEntry(pe).getInput(0);
-        if (vInput.getObjRef() instanceof uk.ac.vamsas.objects.core.Alignment)
+        else
         {
-          // recover an AlignmentView for the input data
-          AlignViewport javport = (AlignViewport) getvObj2jv( (uk.ac.vamsas.
-              client.Vobject) vInput
-              .getObjRef());
-          jalview.datamodel.AlignmentI jal = javport.getAlignment();
-          jalview.datamodel.CigarArray view = javport.getAlignment().
-              getCompactAlignment();
-          int from = 1, to = jal.getWidth();
-          int offset = 0; // deleteRange modifies its frame of reference
-          for (int r = 0, s = vInput.getSegCount(); r < s; r++)
+          // inherit description line from dataset.
+          if (alseq.getDatasetSequence().getDescription() != null)
           {
-            Seg visSeg = vInput.getSeg(r);
-            int se[] = getSegRange(visSeg, true); // jalview doesn't do bidirection alignments yet.
-            if (to < se[1])
-            {
-              Cache.log.warn("Ignoring invalid segment in InputData spec.");
-            }
-            else
-            {
-              if (se[0] > from)
-              {
-                view.deleteRange(offset + from - 1, offset + se[0] - 2);
-                offset -= se[0] - from;
-              }
-              from = se[1] + 1;
-            }
+            alseq.setDescription(alseq.getDatasetSequence()
+                    .getDescription());
           }
-          if (from < to)
-          {
-            view.deleteRange(offset + from - 1, offset + to - 1); // final deletion - TODO: check off by
-            // one for to
-          }
-          return new Object[]
-              {
-              new AlignmentView(view), jal};
         }
+        // if
+        // AlignemntSequence
+        // reference
+        // isn't
+        // a
+        // simple
+        // SequenceI
       }
+      else
+      {
+        Cache.log
+                .error("Invalid dataset sequence id (null) for alignment sequence "
+                        + valseq.getVorbaId());
+      }
+      bindjvvobj(alseq, valseq);
+      alseq.setVamsasId(valseq.getVorbaId().getId());
+      dsseqs.add(alseq);
+    }
+    Vobject datsetseq = (Vobject) valseq.getRefid();
+    if (datsetseq != null)
+    {
+      if (datsetseq != alseq.getDatasetSequence())
+      {
+        modal = true;
+      }
+      alseq.setDatasetSequence((SequenceI) getvObj2jv(datsetseq)); // exceptions
+    }
+    return upFromdoc || modal;
+  }
+
+  private void initRangeAnnotationType(RangeAnnotation an,
+          AlignmentAnnotation alan, int[] gapMap)
+  {
+    Seg vSeg = new Seg();
+    vSeg.setStart(1);
+    vSeg.setInclusive(true);
+    vSeg.setEnd(gapMap.length);
+    an.addSeg(vSeg);
+
+    // LATER: much of this is verbatim from the alignmentAnnotation
+    // method below. suggests refactoring to make rangeAnnotation the
+    // base class
+    an.setDescription(alan.description);
+    an.setLabel(alan.label);
+    an.setGroup(Integer.toString(alan.graphGroup));
+    // // JBPNote -
+    // originally we
+    // were going to
+    // store
+    // graphGroup in
+    // the Jalview
+    // specific
+    // bits.
+    AnnotationElement ae;
+    for (int a = 0; a < alan.annotations.length; a++)
+    {
+      if (alan.annotations[a] == null)
+      {
+        continue;
+      }
+
+      ae = new AnnotationElement();
+      ae.setDescription(alan.annotations[a].description);
+      ae.addGlyph(new Glyph());
+      ae.getGlyph(0).setContent(alan.annotations[a].displayCharacter); // assume
+      // jax-b
+      // takes
+      // care
+      // of
+      // utf8
+      // translation
+      if (alan.graph != jalview.datamodel.AlignmentAnnotation.NO_GRAPH)
+      {
+        ae.addValue(alan.annotations[a].value);
+      }
+      ae.setPosition(gapMap[a] + 1); // position w.r.t. AlignmentSequence
+      // symbols
+      if (alan.annotations[a].secondaryStructure != ' ')
+      {
+        // we only write an annotation where it really exists.
+        Glyph ss = new Glyph();
+        ss.setDict(uk.ac.vamsas.objects.utils.GlyphDictionary.PROTEIN_SS_3STATE);
+        ss.setContent(String
+                .valueOf(alan.annotations[a].secondaryStructure));
+        ae.addGlyph(ss);
+      }
+      an.addAnnotationElement(ae);
+    }
+
+  }
+
+  private void saveDatasetSequenceAnnotation(HashMap AlSeqMaps,
+          uk.ac.vamsas.objects.core.Sequence sref, AlignmentAnnotation alan)
+  {
+    // {
+    // uk.ac.vamsas.
+    // objects.core.AlignmentSequence alsref = (uk.ac.vamsas.
+    // objects.core.AlignmentSequence) sref;
+    uk.ac.vamsas.objects.core.DataSetAnnotations an = (uk.ac.vamsas.objects.core.DataSetAnnotations) getjv2vObj(alan);
+    int[] gapMap = getGapMap(AlSeqMaps, alan);
+    if (an == null)
+    {
+      an = new uk.ac.vamsas.objects.core.DataSetAnnotations();
+      initRangeAnnotationType(an, alan, gapMap);
+
+      an.setProvenance(dummyProvenance()); // get provenance as user
+      // created, or jnet, or
+      // something else.
+      setAnnotationType(an, alan);
+      an.setGroup(Integer.toString(alan.graphGroup)); // // JBPNote -
+      // originally we
+      // were going to
+      // store
+      // graphGroup in
+      // the Jalview
+      // specific
+      // bits.
+      if (alan.getThreshold() != null && alan.getThreshold().displayed)
+      {
+        an.addProperty(Properties.newProperty(THRESHOLD,
+                Properties.FLOATTYPE, "" + alan.getThreshold().value));
+        if (alan.getThreshold().label != null)
+        {
+          an.addProperty(Properties.newProperty(THRESHOLD + "Name",
+                  Properties.STRINGTYPE, "" + alan.getThreshold().label));
+        }
+      }
+      ((DataSet) sref.getV_parent()).addDataSetAnnotations(an);
+      bindjvvobj(alan, an);
+    }
+    else
+    {
+      // update reference sequence Annotation
+      if (an.getModifiable() == null) // TODO: USE VAMSAS LIBRARY OBJECT LOCK
+      // METHODS)
+      {
+        // verify existing alignment sequence annotation is up to date
+        System.out.println("update dataset sequence annotation.");
+      }
+      else
+      {
+        // verify existing alignment sequence annotation is up to date
+        System.out
+                .println("make new alignment dataset sequence annotation if modification has happened.");
+      }
+    }
+
+  }
+
+  private int[] getGapMap(HashMap AlSeqMaps, AlignmentAnnotation alan)
+  {
+    int[] gapMap;
+    if (AlSeqMaps.containsKey(alan.sequenceRef))
+    {
+      gapMap = (int[]) AlSeqMaps.get(alan.sequenceRef);
+    }
+    else
+    {
+      gapMap = new int[alan.sequenceRef.getLength()];
+      // map from alignment position to sequence position.
+      int[] sgapMap = alan.sequenceRef.gapMap();
+      for (int a = 0; a < sgapMap.length; a++)
+      {
+        gapMap[sgapMap[a]] = a;
+      }
+    }
+    return gapMap;
+  }
+
+  private void saveAlignmentSequenceAnnotation(HashMap AlSeqMaps,
+          AlignmentSequence alsref, AlignmentAnnotation alan)
+  {
+    // {
+    // uk.ac.vamsas.
+    // objects.core.AlignmentSequence alsref = (uk.ac.vamsas.
+    // objects.core.AlignmentSequence) sref;
+    uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation an = (uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation) getjv2vObj(alan);
+    int[] gapMap = getGapMap(AlSeqMaps, alan);
+    if (an == null)
+    {
+      an = new uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation();
+      initRangeAnnotationType(an, alan, gapMap);
+      /**
+       * I mean here that we don't actually have a semantic 'type' for the
+       * annotation (this might be - score, intrinsic property, measurement,
+       * something extracted from another program, etc)
+       */
+      an.setType(JALVIEW_ANNOTATION_ROW); // TODO: better fix
+      // this rough guess ;)
+      alsref.addAlignmentSequenceAnnotation(an);
+      bindjvvobj(alan, an);
+      // These properties are directly supported by the
+      // AlignmentSequenceAnnotation type.
+      setAnnotationType(an, alan);
+      an.setProvenance(dummyProvenance()); // get provenance as user
+      // created, or jnet, or
+      // something else.
+    }
+    else
+    {
+      // update reference sequence Annotation
+      if (an.getModifiable() == null) // TODO: USE VAMSAS LIBRARY OBJECT LOCK
+      // METHODS)
+      {
+        // verify existing alignment sequence annotation is up to date
+        System.out.println("update alignment sequence annotation.");
+      }
+      else
+      {
+        // verify existing alignment sequence annotation is up to date
+        System.out
+                .println("make new alignment sequence annotation if modification has happened.");
+      }
+    }
+  }
+
+  /**
+   * set vamsas annotation object type from jalview annotation
+   * 
+   * @param an
+   * @param alan
+   */
+  private void setAnnotationType(RangeAnnotation an,
+          AlignmentAnnotation alan)
+  {
+    if (an instanceof AlignmentSequenceAnnotation)
+    {
+      if (alan.graph != AlignmentAnnotation.NO_GRAPH)
+      {
+        ((AlignmentSequenceAnnotation) an).setGraph(true);
+      }
+      else
+      {
+        ((AlignmentSequenceAnnotation) an).setGraph(false);
+      }
+    }
+    if (an instanceof uk.ac.vamsas.objects.core.AlignmentAnnotation)
+    {
+      if (alan.graph != AlignmentAnnotation.NO_GRAPH)
+      {
+        ((uk.ac.vamsas.objects.core.AlignmentAnnotation) an).setGraph(true);
+      }
+      else
+      {
+        ((uk.ac.vamsas.objects.core.AlignmentAnnotation) an)
+                .setGraph(false);
+      }
+    }
+    switch (alan.graph)
+    {
+    case AlignmentAnnotation.BAR_GRAPH:
+      an.addProperty(Properties.newProperty(DISCRETE_ANNOTATION,
+              Properties.BOOLEANTYPE, "true"));
+      break;
+    case AlignmentAnnotation.LINE_GRAPH:
+      an.addProperty(Properties.newProperty(CONTINUOUS_ANNOTATION,
+              Properties.BOOLEANTYPE, "true"));
+      break;
+    default:
+      // don't add any kind of discrete or continous property info.
     }
-    Cache.log.debug("Returning null for input data recovery from provenance.");
-    return null;
   }
 
   /**
    * get start<end range of segment, adjusting for inclusivity flag and
    * polarity.
-   *
+   * 
    * @param visSeg
-   * @param ensureDirection when true - always ensure start is less than end.
-   * @return int[] { start, end, direction} where direction==1 for range running from end to start.
+   * @param ensureDirection
+   *          when true - always ensure start is less than end.
+   * @return int[] { start, end, direction} where direction==1 for range running
+   *         from end to start.
    */
   private int[] getSegRange(Seg visSeg, boolean ensureDirection)
   {
@@ -896,51 +1263,335 @@ public class VamsasAppDatastore
       end = start;
       start = t;
     }
-    return new int[]
-        {
-        start, end, pol < 0 ? 1 : 0};
+    return new int[] { start, end, pol < 0 ? 1 : 0 };
+  }
+
+  /**
+   * 
+   * @param annotation
+   * @return true if annotation is not to be stored in document
+   */
+  private boolean isJalviewOnly(AlignmentAnnotation annotation)
+  {
+    return annotation.autoCalculated || annotation.label.equals("Quality")
+            || annotation.label.equals("Conservation")
+            || annotation.label.equals("Consensus");
+  }
+
+  boolean dojvsync = true;
+
+  // boolean dojvsync = false; // disables Jalview AppData IO
+  /**
+   * list of alignment views created when updating Jalview from document.
+   */
+  private final Vector newAlignmentViews = new Vector();
+
+  /**
+   * update local jalview view settings from the stored appdata (if any)
+   */
+  public void updateJalviewFromAppdata()
+  {
+    // recover any existing Jalview data from appdata
+    // TODO: recover any PDB files stored as attachments in the vamsas session
+    // and initialise the Jalview2XML.alreadyLoadedPDB hashtable with mappings
+    // to temp files.
+    {
+      final IClientAppdata cappdata = cdoc.getClientAppdata();
+      if (cappdata != null)
+      {
+        if (cappdata.hasClientAppdata())
+        {
+          // TODO: how to check version of Jalview client app data and whether
+          // it has been modified
+          // client data is shared over all app clients
+          try
+          {
+            jalview.gui.Jalview2XML fromxml = new jalview.gui.Jalview2XML();
+            fromxml.attemptversion1parse = false;
+            fromxml.setUniqueSetSuffix("");
+            fromxml.setObjectMappingTables(vobj2jv, jv2vobj); // mapKeysToString
+            // and
+            // mapValuesToString
+            fromxml.setSkipList(skipList);
+            jalview.util.jarInputStreamProvider jprovider = new jalview.util.jarInputStreamProvider()
+            {
+
+              @Override
+              public String getFilename()
+              {
+
+                // TODO Get the vamsas session ID here
+                return "Jalview Vamsas Document Client Data";
+              }
+
+              @Override
+              public JarInputStream getJarInputStream() throws IOException
+              {
+                jalview.bin.Cache.log
+                        .debug("Returning client input stream for Jalview from Vamsas Document.");
+                return new JarInputStream(cappdata.getClientInputStream());
+              }
+            };
+            if (dojvsync)
+            {
+              fromxml.loadJalviewAlign(jprovider);
+            }
+          } catch (Exception e)
+          {
+
+          } catch (OutOfMemoryError e)
+          {
+
+          } catch (Error e)
+          {
+
+          }
+        }
+      }
+      if (cappdata.hasUserAppdata())
+      {
+        // TODO: how to check version of Jalview user app data and whether it
+        // has been modified
+        // user data overrides data shared over all app clients ?
+        try
+        {
+          jalview.gui.Jalview2XML fromxml = new jalview.gui.Jalview2XML();
+          fromxml.attemptversion1parse = false;
+          fromxml.setUniqueSetSuffix("");
+          fromxml.setSkipList(skipList);
+          fromxml.setObjectMappingTables(mapKeysToString(vobj2jv),
+                  mapValuesToString(jv2vobj));
+          jalview.util.jarInputStreamProvider jarstream = new jalview.util.jarInputStreamProvider()
+          {
+
+            @Override
+            public String getFilename()
+            {
+
+              // TODO Get the vamsas session ID here
+              return "Jalview Vamsas Document User Data";
+            }
+
+            @Override
+            public JarInputStream getJarInputStream() throws IOException
+            {
+              jalview.bin.Cache.log
+                      .debug("Returning user input stream for Jalview from Vamsas Document.");
+              return new JarInputStream(cappdata.getUserInputStream());
+            }
+          };
+          if (dojvsync)
+          {
+            fromxml.loadJalviewAlign(jarstream);
+          }
+        } catch (Exception e)
+        {
+
+        } catch (OutOfMemoryError e)
+        {
+
+        } catch (Error e)
+        {
+
+        }
+      }
+
+    }
+    flushAlignViewports();
+  }
+
+  /**
+   * remove any spurious views generated by document synchronization
+   */
+  private void flushAlignViewports()
+  {
+    // remove any additional viewports originally recovered from the vamsas
+    // document.
+    // search for all alignframes containing viewports generated from document
+    // sync,
+    // and if any contain more than one view, then remove the one generated by
+    // document update.
+    AlignmentViewport views[], av = null;
+    AlignFrame af = null;
+    Iterator newviews = newAlignmentViews.iterator();
+    while (newviews.hasNext())
+    {
+      av = (AlignmentViewport) newviews.next();
+      af = Desktop.getAlignFrameFor(av);
+      // TODO implement this : af.getNumberOfViews
+      String seqsetidobj = av.getSequenceSetId();
+      views = Desktop.getViewports(seqsetidobj);
+      Cache.log.debug("Found "
+              + (views == null ? " no " : "" + views.length)
+              + " views for '" + av.getSequenceSetId() + "'");
+      if (views.length > 1)
+      {
+        // we need to close the original document view.
+
+        // work out how to do this by seeing if the views are gathered.
+        // pretty clunky but the only way to do this without adding more flags
+        // to the align frames.
+        boolean gathered = false;
+        String newviewid = null;
+        Set<AlignedCodonFrame> mappings = av.getAlignment()
+                .getCodonFrames();
+        for (int i = 0; i < views.length; i++)
+        {
+          if (views[i] != av)
+          {
+            AlignFrame viewframe = Desktop.getAlignFrameFor(views[i]);
+            if (viewframe == af)
+            {
+              gathered = true;
+            }
+            newviewid = views[i].getSequenceSetId();
+          }
+          else
+          {
+            // lose the reference to the vamsas document created view
+            views[i] = null;
+          }
+        }
+        // close the view generated by the vamsas document synchronization
+        if (gathered)
+        {
+          af.closeView(av);
+        }
+        else
+        {
+          af.closeMenuItem_actionPerformed(false);
+        }
+        replaceJvObjMapping(seqsetidobj, newviewid);
+        seqsetidobj = newviewid;
+        // not sure if we need to do this:
+
+        if (false) // mappings != null)
+        {
+          // ensure sequence mappings from vamsas document view still
+          // active
+          if (mappings != null)
+          {
+            jalview.structure.StructureSelectionManager
+                    .getStructureSelectionManager(Desktop.instance)
+                    .registerMappings(mappings);
+          }
+        }
+      }
+      // ensure vamsas object binds to the stored views retrieved from
+      // Jalview appdata
+      // jalview.structure.StructureSelectionManager
+      // .getStructureSelectionManager()
+      // .addStructureViewerListener(viewframe.alignPanel);
+
+    }
+
+    newviews = null;
+    newAlignmentViews.clear();
+  }
+
+  /**
+   * replaces oldjvobject with newjvobject in the Jalview Object <> VorbaID
+   * binding tables
+   * 
+   * @param oldjvobject
+   * @param newjvobject
+   *          (may be null)
+   */
+  private void replaceJvObjMapping(Object oldjvobject, Object newjvobject)
+  {
+    Object vobject = jv2vobj.remove(oldjvobject);
+    if (vobject == null)
+    {
+      // NOTE: this happens if user deletes object in one session then updates
+      // from another client
+      throw new Error(MessageManager.formatMessage(
+              "error.implementation_error_old_jalview_object_not_bound",
+              new String[] { oldjvobject.toString() }));
+    }
+    if (newjvobject != null)
+    {
+      jv2vobj.put(newjvobject, vobject);
+      vobj2jv.put(vobject, newjvobject);
+    }
+  }
+
+  /**
+   * Update the jalview client and user appdata from the local jalview settings
+   */
+  public void updateJalviewClientAppdata()
+  {
+    final IClientAppdata cappdata = cdoc.getClientAppdata();
+    if (cappdata != null)
+    {
+      try
+      {
+        jalview.gui.Jalview2XML jxml = new jalview.gui.Jalview2XML();
+        jxml.setObjectMappingTables(mapKeysToString(vobj2jv),
+                mapValuesToString(jv2vobj));
+        jxml.setSkipList(skipList);
+        if (dojvsync)
+        {
+          jxml.saveState(new JarOutputStream(cappdata
+                  .getClientOutputStream()));
+        }
+
+      } catch (Exception e)
+      {
+        // TODO raise GUI warning if user requests it.
+        jalview.bin.Cache.log
+                .error("Couldn't update jalview client application data. Giving up - local settings probably lost.",
+                        e);
+      }
+    }
+    else
+    {
+      jalview.bin.Cache.log
+              .error("Couldn't access client application data for vamsas session. This is probably a vamsas client bug.");
+    }
   }
 
   /**
-   *
-   * @param annotation
-   * @return true if annotation is not to be stored in document
+   * translate the Vobject keys to strings for use in Jalview2XML
+   * 
+   * @param jv2vobj2
+   * @return
    */
-  private boolean isJalviewOnly(AlignmentAnnotation annotation)
+  private IdentityHashMap mapValuesToString(IdentityHashMap jv2vobj2)
   {
-    return annotation.label.equals("Quality")
-        || annotation.label.equals("Conservation")
-        || annotation.label.equals("Consensus");
+    IdentityHashMap mapped = new IdentityHashMap();
+    Iterator keys = jv2vobj2.keySet().iterator();
+    while (keys.hasNext())
+    {
+      Object key = keys.next();
+      mapped.put(key, jv2vobj2.get(key).toString());
+    }
+    return mapped;
   }
 
   /**
-   * This will return the first AlignFrame viewing AlignViewport av.
-   * It will break if there are more than one AlignFrames viewing a particular av.
-   * This also shouldn't be in the io package.
-   * @param av
-   * @return alignFrame for av
+   * translate the Vobject values to strings for use in Jalview2XML
+   * 
+   * @param vobj2jv2
+   * @return hashtable with string values
    */
-  public AlignFrame getAlignFrameFor(AlignViewport av)
+  private Hashtable mapKeysToString(Hashtable vobj2jv2)
   {
-    if (Desktop.desktop != null)
+    Hashtable mapped = new Hashtable();
+    Iterator keys = vobj2jv2.keySet().iterator();
+    while (keys.hasNext())
     {
-      javax.swing.JInternalFrame[] frames = Desktop.instance.getAllFrames();
-
-      for (int t = 0; t < frames.length; t++)
-      {
-        if (frames[t] instanceof AlignFrame)
-        {
-          if ( ( (AlignFrame) frames[t]).getViewport() == av)
-          {
-            return (AlignFrame) frames[t];
-          }
-        }
-      }
+      Object key = keys.next();
+      mapped.put(key.toString(), vobj2jv2.get(key));
     }
-    return null;
+    return mapped;
   }
 
-  public void updateToJalview()
+  /**
+   * synchronize Jalview from the vamsas document
+   * 
+   * @return number of new views from document
+   */
+  public int updateToJalview()
   {
     VAMSAS _roots[] = cdoc.getVamsasRoots();
 
@@ -954,9 +1605,8 @@ public class VamsasAppDatastore
         // ///LOAD DATASET
         DataSet dataset = root.getDataSet(_ds);
         int i, iSize = dataset.getSequenceCount();
-        Vector dsseqs;
-        jalview.datamodel.Alignment jdataset = (jalview.datamodel.Alignment)
-            getvObj2jv(dataset);
+        List<SequenceI> dsseqs;
+        jalview.datamodel.Alignment jdataset = (jalview.datamodel.Alignment) getvObj2jv(dataset);
         int jremain = 0;
         if (jdataset == null)
         {
@@ -977,26 +1627,12 @@ public class VamsasAppDatastore
         for (i = 0; i < iSize; i++)
         {
           Sequence vdseq = dataset.getSequence(i);
-          jalview.datamodel.SequenceI dsseq = (SequenceI) getvObj2jv(vdseq);
-          if (dsseq != null)
-          {
-            if (!dsseq.getSequenceAsString().equals(vdseq.getSequence()))
-            {
-              throw new Error(
-                  "Broken! - mismatch of dataset sequence: and jalview internal dataset sequence.");
-            }
-            jremain--;
-          }
-          else
+          jalview.io.vamsas.Datasetsequence dssync = new Datasetsequence(
+                  this, vdseq);
+
+          jalview.datamodel.SequenceI dsseq = (SequenceI) dssync.getJvobj();
+          if (dssync.isAddfromdoc())
           {
-            dsseq = new jalview.datamodel.Sequence(
-                dataset.getSequence(i).getName(),
-                dataset.getSequence(i).getSequence(),
-                (int)dataset.getSequence(i).getStart(),
-                (int)dataset.getSequence(i).getEnd());
-            dsseq.setDescription(dataset.getSequence(i).getDescription());
-            bindjvvobj(dsseq, dataset.getSequence(i));
-            dsseq.setVamsasId(dataset.getSequence(i).getVorbaId().getId());
             dsseqs.add(dsseq);
           }
           if (vdseq.getDbRefCount() > 0)
@@ -1004,19 +1640,10 @@ public class VamsasAppDatastore
             DbRef[] dbref = vdseq.getDbRef();
             for (int db = 0; db < dbref.length; db++)
             {
-              jalview.datamodel.DBRefEntry dbr = (jalview.datamodel.DBRefEntry)
-                  getvObj2jv(dbref[db]);
-              if (dbr == null)
-              {
-                // add new dbref
-                dsseq.addDBRef(dbr = new jalview.datamodel.DBRefEntry
-                               (
-                                   dbref[db].getSource().toString(),
-                                   dbref[db].getVersion().toString(),
-                                   dbref[db].getAccessionId().toString()));
-                bindjvvobj(dbr, dbref[db]);
-              }
+              new jalview.io.vamsas.Dbref(this, dbref[db], vdseq, dsseq);
+
             }
+            dsseq.updatePDBIds();
           }
         }
 
@@ -1025,8 +1652,8 @@ public class VamsasAppDatastore
           SequenceI[] seqs = new SequenceI[dsseqs.size()];
           for (i = 0, iSize = dsseqs.size(); i < iSize; i++)
           {
-            seqs[i] = (SequenceI) dsseqs.elementAt(i);
-            dsseqs.setElementAt(null, i);
+            seqs[i] = dsseqs.get(i);
+            dsseqs.set(i, null);
           }
           jdataset = new jalview.datamodel.Alignment(seqs);
           Cache.log.debug("New vamsas dataset imported into jalview.");
@@ -1039,57 +1666,71 @@ public class VamsasAppDatastore
           for (int dsa = 0; dsa < dataset.getDataSetAnnotationsCount(); dsa++)
           {
             DataSetAnnotations dseta = dataset.getDataSetAnnotations(dsa);
-            SequenceI dsSeq = (SequenceI) getvObj2jv( (Vobject) dseta.getSeqRef());
-            if (dsSeq == null)
-            {
-              jalview.bin.Cache.log.warn(
-                  "Couldn't resolve jalview sequenceI for dataset object reference " +
-                  ( (Vobject) dataset.getDataSetAnnotations(dsa).getSeqRef()).
-                  getVorbaId().getId());
-            }
-            else
+            // TODO: deal with group annotation on datset sequences.
+            if (dseta.getSeqRefCount() == 1)
             {
-              if (dseta.getAnnotationElementCount() == 0)
+              SequenceI dsSeq = (SequenceI) getvObj2jv((Vobject) dseta
+                      .getSeqRef(0)); // TODO: deal with group dataset
+              // annotations
+              if (dsSeq == null)
               {
-                jalview.datamodel.SequenceFeature sf = (jalview.datamodel.
-                    SequenceFeature) getvObj2jv(dseta);
-                if (sf == null)
-                {
-                  dsSeq.addSequenceFeature(sf = getJalviewSeqFeature(dseta));
-                  bindjvvobj(sf, dseta);
-                }
+                jalview.bin.Cache.log
+                        .warn("Couldn't resolve jalview sequenceI for dataset object reference "
+                                + ((Vobject) dataset.getDataSetAnnotations(
+                                        dsa).getSeqRef(0)).getVorbaId()
+                                        .getId());
               }
               else
               {
-                // TODO: deal with alignmentAnnotation style annotation
-                // appearing on dataset sequences.
-                // JBPNote: we could just add them to all alignments but
-                // that may complicate cross references in the jalview
-                // datamodel
-                Cache.log.warn("Ignoring dataset annotation with annotationElements. Not yet supported in jalview.");
+                if (dseta.getAnnotationElementCount() == 0)
+                {
+                  new jalview.io.vamsas.Sequencefeature(this, dseta, dsSeq);
+
+                }
+                else
+                {
+                  // TODO: deal with alignmentAnnotation style annotation
+                  // appearing on dataset sequences.
+                  // JBPNote: we could just add them to all alignments but
+                  // that may complicate cross references in the jalview
+                  // datamodel
+                  Cache.log
+                          .warn("Ignoring dataset annotation with annotationElements. Not yet supported in jalview.");
+                }
               }
             }
+            else
+            {
+              Cache.log
+                      .warn("Ignoring multiply referenced dataset sequence annotation for binding to datsaet sequence features.");
+            }
           }
         }
-
         if (dataset.getAlignmentCount() > 0)
         {
           // LOAD ALIGNMENTS from DATASET
 
           for (int al = 0, nal = dataset.getAlignmentCount(); al < nal; al++)
           {
-            uk.ac.vamsas.objects.core.Alignment alignment = dataset.getAlignment(
-                al);
-            AlignViewport av = (AlignViewport) getvObj2jv(alignment);
+            uk.ac.vamsas.objects.core.Alignment alignment = dataset
+                    .getAlignment(al);
+            // TODO check this handles multiple views properly
+            AlignmentViewport av = findViewport(alignment);
+
             jalview.datamodel.AlignmentI jal = null;
             if (av != null)
             {
-              jal = av.getAlignment();
+              // TODO check that correct alignment object is retrieved when
+              // hidden seqs exist.
+              jal = (av.hasHiddenRows()) ? av.getAlignment()
+                      .getHiddenSequences().getFullAlignment() : av
+                      .getAlignment();
             }
             iSize = alignment.getAlignmentSequenceCount();
-            boolean newal = (jal == null) ? true : false;
+            boolean refreshal = false;
             Vector newasAnnots = new Vector();
-            char gapChar = ' '; // default for new alignments read in from the document
+            char gapChar = ' '; // default for new alignments read in from the
+            // document
             if (jal != null)
             {
               dsseqs = jal.getSequences(); // for merge/update
@@ -1103,73 +1744,64 @@ public class VamsasAppDatastore
             for (i = 0; i < iSize; i++)
             {
               AlignmentSequence valseq = alignment.getAlignmentSequence(i);
-              jalview.datamodel.SequenceI alseq = (SequenceI) getvObj2jv(valseq);
-              if (alseq != null)
+              jalview.datamodel.Sequence alseq = (jalview.datamodel.Sequence) getvObj2jv(valseq);
+              if (syncFromAlignmentSequence(valseq, valGapchar, gapChar,
+                      dsseqs) && alseq != null)
               {
-                //TODO: upperCase/LowerCase situation here ? do we allow it ?
-                //if (!alseq.getSequence().equals(valseq.getSequence())) {
-                // throw new Error("Broken! - mismatch of dataset sequence and jalview internal dataset sequence.");
-                if (Cache.log.isDebugEnabled())
-                {
-                  Cache.log.debug("Updating apparently edited sequence " +
-                                  alseq.getName());
-                }
-                // this might go *horribly* wrong
-                alseq.setSequence(new String(valseq.getSequence()).replace(
-                    valGapchar, gapChar));
+
+                // updated to sequence from the document
                 jremain--;
-              }
-              else
-              {
-                alseq = new jalview.datamodel.Sequence(
-                    valseq.getName(),
-                    valseq.getSequence().replace(valGapchar, gapChar),
-                    (int)valseq.getStart(),
-                    (int)valseq.getEnd());
-
-                Vobject datsetseq = (Vobject) valseq.getRefid();
-                if (datsetseq != null)
-                {
-                  alseq.setDatasetSequence( (SequenceI) getvObj2jv(datsetseq)); // exceptions if AlignemntSequence reference isn't a simple SequenceI
-                }
-                else
-                {
-                  Cache.log.error(
-                      "Invalid dataset sequence id (null) for alignment sequence " +
-                      valseq.getVorbaId());
-                }
-                bindjvvobj(alseq, valseq);
-                alseq.setVamsasId(valseq.getVorbaId().getId());
-                dsseqs.add(alseq);
+                refreshal = true;
               }
               if (valseq.getAlignmentSequenceAnnotationCount() > 0)
               {
-                AlignmentSequenceAnnotation[] vasannot = valseq.
-                    getAlignmentSequenceAnnotation();
+                AlignmentSequenceAnnotation[] vasannot = valseq
+                        .getAlignmentSequenceAnnotation();
                 for (int a = 0; a < vasannot.length; a++)
                 {
-                  jalview.datamodel.AlignmentAnnotation asa = (jalview.
-                      datamodel.AlignmentAnnotation) getvObj2jv(vasannot[a]); // TODO: 1:many jalview alignment sequence annotations
+                  jalview.datamodel.AlignmentAnnotation asa = (jalview.datamodel.AlignmentAnnotation) getvObj2jv(vasannot[a]); // TODO:
+                  // 1:many
+                  // jalview
+                  // alignment
+                  // sequence
+                  // annotations
                   if (asa == null)
                   {
                     int se[] = getBounds(vasannot[a]);
                     asa = getjAlignmentAnnotation(jal, vasannot[a]);
-                    asa.sequenceRef = alseq;
-                    asa.createSequenceMapping(alseq, alseq.getStart() + se[0], false); // TODO: verify that positions in alseqAnnotation correspond to ungapped residue positions.
+                    asa.setSequenceRef(alseq);
+                    asa.createSequenceMapping(alseq, se[0], false); // TODO:
+                    // verify
+                    // that
+                    // positions
+                    // in
+                    // alseqAnnotation
+                    // correspond
+                    // to
+                    // ungapped
+                    // residue
+                    // positions.
+                    alseq.addAlignmentAnnotation(asa);
                     bindjvvobj(asa, vasannot[a]);
+                    refreshal = true;
                     newasAnnots.add(asa);
                   }
                   else
                   {
                     // update existing annotation - can do this in place
-                    if (vasannot[a].getModifiable()==null) // TODO: USE VAMSAS LIBRARY OBJECT LOCK METHODS)
+                    if (vasannot[a].getModifiable() == null) // TODO: USE
+                    // VAMSAS LIBRARY
+                    // OBJECT LOCK
+                    // METHODS)
                     {
-                      Cache.log.info(
-                          "UNIMPLEMENTED: not recovering user modifiable sequence alignment annotation");
-                      // TODO: should at least replace with new one - otherwise things will break
+                      Cache.log
+                              .info("UNIMPLEMENTED: not recovering user modifiable sequence alignment annotation");
+                      // TODO: should at least replace with new one - otherwise
+                      // things will break
                       // basically do this:
                       // int se[] = getBounds(vasannot[a]);
-                      // asa.update(getjAlignmentAnnotation(jal, vasannot[a])); //  update from another annotation object in place.
+                      // asa.update(getjAlignmentAnnotation(jal, vasannot[a]));
+                      // // update from another annotation object in place.
                       // asa.createSequenceMapping(alseq, se[0], false);
 
                     }
@@ -1182,12 +1814,12 @@ public class VamsasAppDatastore
               SequenceI[] seqs = new SequenceI[dsseqs.size()];
               for (i = 0, iSize = dsseqs.size(); i < iSize; i++)
               {
-                seqs[i] = (SequenceI) dsseqs.elementAt(i);
-                dsseqs.setElementAt(null, i);
+                seqs[i] = dsseqs.get(i);
+                dsseqs.set(i, null);
               }
               jal = new jalview.datamodel.Alignment(seqs);
-              Cache.log.debug("New vamsas alignment imported into jalview " +
-                              alignment.getVorbaId().getId());
+              Cache.log.debug("New vamsas alignment imported into jalview "
+                      + alignment.getVorbaId().getId());
               jal.setDataset(jdataset);
             }
             if (newasAnnots != null && newasAnnots.size() > 0)
@@ -1195,9 +1827,10 @@ public class VamsasAppDatastore
               // Add the new sequence annotations in to the alignment.
               for (int an = 0, anSize = newasAnnots.size(); an < anSize; an++)
               {
-                jal.addAnnotation( (AlignmentAnnotation) newasAnnots.elementAt(
-                    an));
-                // TODO: check if anything has to be done - like calling adjustForAlignment or something.
+                jal.addAnnotation((AlignmentAnnotation) newasAnnots
+                        .elementAt(an));
+                // TODO: check if anything has to be done - like calling
+                // adjustForAlignment or something.
                 newasAnnots.setElementAt(null, an);
               }
               newasAnnots = null;
@@ -1207,26 +1840,31 @@ public class VamsasAppDatastore
             // ////////////////////////////////////
             if (alignment.getAlignmentAnnotationCount() > 0)
             {
-              uk.ac.vamsas.objects.core.AlignmentAnnotation[] an = alignment.
-                  getAlignmentAnnotation();
+              uk.ac.vamsas.objects.core.AlignmentAnnotation[] an = alignment
+                      .getAlignmentAnnotation();
 
               for (int j = 0; j < an.length; j++)
               {
-                jalview.datamodel.AlignmentAnnotation jan = (jalview.datamodel.
-                    AlignmentAnnotation) getvObj2jv(an[j]);
+                jalview.datamodel.AlignmentAnnotation jan = (jalview.datamodel.AlignmentAnnotation) getvObj2jv(an[j]);
                 if (jan != null)
                 {
                   // update or stay the same.
-                  // TODO: should at least replace with a new one - otherwise things will break
+                  // TODO: should at least replace with a new one - otherwise
+                  // things will break
                   // basically do this:
-                  // jan.update(getjAlignmentAnnotation(jal, an[a])); //  update from another annotation object in place.
-
-                  Cache.log.debug("update from vamsas alignment annotation to existing jalview alignment annotation.");
-                  if (an[j].getModifiable()==null) // TODO: USE VAMSAS LIBRARY OBJECT LOCK METHODS)
+                  // jan.update(getjAlignmentAnnotation(jal, an[a])); // update
+                  // from another annotation object in place.
+
+                  Cache.log
+                          .debug("update from vamsas alignment annotation to existing jalview alignment annotation.");
+                  if (an[j].getModifiable() == null) // TODO: USE VAMSAS
+                  // LIBRARY OBJECT LOCK
+                  // METHODS)
                   {
-                    // TODO: user defined annotation is totally mutable... - so load it up or throw away if locally edited.
-                    Cache.log.info(
-                        "NOT IMPLEMENTED - Recovering user-modifiable annotation - yet...");
+                    // TODO: user defined annotation is totally mutable... - so
+                    // load it up or throw away if locally edited.
+                    Cache.log
+                            .info("NOT IMPLEMENTED - Recovering user-modifiable annotation - yet...");
                   }
                   // TODO: compare annotation element rows
                   // TODO: compare props.
@@ -1234,46 +1872,64 @@ public class VamsasAppDatastore
                 else
                 {
                   jan = getjAlignmentAnnotation(jal, an[j]);
+                  // TODO: ensure we add the alignment annotation before the
+                  // automatic annotation rows
                   jal.addAnnotation(jan);
                   bindjvvobj(jan, an[j]);
+                  refreshal = true;
                 }
               }
             }
             AlignFrame alignFrame;
             if (av == null)
             {
-              Cache.log.debug("New alignframe for alignment " +
-                              alignment.getVorbaId());
+              Cache.log.debug("New alignframe for alignment "
+                      + alignment.getVorbaId());
               // ///////////////////////////////
               // construct alignment view
               alignFrame = new AlignFrame(jal, AlignFrame.DEFAULT_WIDTH,
-                                          AlignFrame.DEFAULT_HEIGHT);
+                      AlignFrame.DEFAULT_HEIGHT, alignment.getVorbaId()
+                              .toString());
               av = alignFrame.getViewport();
-              String title = alignment.getProvenance().getEntry(alignment.
-                  getProvenance().getEntryCount() - 1).getAction();
+              newAlignmentViews.addElement(av);
+              String title = alignment
+                      .getProvenance()
+                      .getEntry(
+                              alignment.getProvenance().getEntryCount() - 1)
+                      .getAction();
               if (alignment.getPropertyCount() > 0)
               {
                 for (int p = 0, pe = alignment.getPropertyCount(); p < pe; p++)
                 {
-                  if (alignment.getProperty(p).getName().equals(
-                      "jalview:AlTitle"))
+                  if (alignment.getProperty(p).getName().equals("title"))
                   {
                     title = alignment.getProperty(p).getContent();
                   }
                 }
               }
-              // TODO: automatically create meaningful title for a vamsas alignment using its provenance.
-              jalview.gui.Desktop.addInternalFrame(alignFrame,
-                  title + "(" + alignment.getVorbaId() + ")",
-                  AlignFrame.DEFAULT_WIDTH,
-                  AlignFrame.DEFAULT_HEIGHT);
-              bindjvvobj(av, alignment);
+              // TODO: automatically create meaningful title for a vamsas
+              // alignment using its provenance.
+              if (Cache.log.isDebugEnabled())
+              {
+                title = title + "(" + alignment.getVorbaId() + ")";
+
+              }
+              jalview.gui.Desktop.addInternalFrame(alignFrame, title,
+                      AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
+              bindjvvobj(av.getSequenceSetId(), alignment);
             }
             else
             {
               // find the alignFrame for jal.
-              // TODO: fix this so we retrieve the alignFrame handing av *directly*
-              alignFrame = getAlignFrameFor(av);
+              // TODO: fix this so we retrieve the alignFrame handing av
+              // *directly* (JBPNote - don't understand this now)
+              // TODO: make sure all associated views are refreshed
+              alignFrame = Desktop.getAlignFrameFor(av);
+              if (refreshal)
+              {
+                av.alignmentChanged(alignFrame.alignPanel);
+                alignFrame.alignPanel.adjustAnnotationHeight();
+              }
             }
             // LOAD TREES
             // /////////////////////////////////////
@@ -1282,84 +1938,118 @@ public class VamsasAppDatastore
 
               for (int t = 0; t < alignment.getTreeCount(); t++)
               {
-                Tree tree = alignment.getTree(t);
-                TreePanel tp = (TreePanel) getvObj2jv(tree);
-                if (tp != null)
+                jalview.io.vamsas.Tree vstree = new jalview.io.vamsas.Tree(
+                        this, alignFrame, alignment.getTree(t));
+                TreePanel tp = null;
+                if (vstree.isValidTree())
                 {
-                  Cache.log.info(
-                      "Update from vamsas document to alignment associated tree not implemented yet.");
+                  tp = alignFrame.ShowNewickTree(vstree.getNewickTree(),
+                          vstree.getTitle(), vstree.getInputData(), 600,
+                          500, t * 20 + 50, t * 20 + 50);
+
                 }
-                else
+                if (tp != null)
                 {
-                  // make a new tree
-                  Object[] idata = this.recoverInputData(tree.getProvenance());
+                  bindjvvobj(tp, alignment.getTree(t));
                   try
                   {
-                    AlignmentView inputData = null;
-                    if (idata != null && idata[0] != null)
-                    {
-                      inputData = (AlignmentView) idata[0];
-                    }
-                    tp = alignFrame.ShowNewickTree(
-                        new jalview.io.NewickFile(tree.getNewick(0).getContent()),
-                        tree.getNewick(0).getTitle() + " (" + tree.getVorbaId() +
-                        ")", inputData,
-                        600, 500,
-                        t * 20 + 50, t * 20 + 50);
-                    bindjvvobj(tp, tree);
-                  }
-                  catch (Exception e)
+                    vstree.UpdateSequenceTreeMap(tp);
+                  } catch (RuntimeException e)
                   {
-                    Cache.log.warn("Problems parsing treefile '" +
-                                   tree.getNewick(0).getContent() + "'", e);
+                    Cache.log.warn("update of labels failed.", e);
                   }
                 }
+                else
+                {
+                  Cache.log.warn("Cannot create tree for tree " + t
+                          + " in document ("
+                          + alignment.getTree(t).getVorbaId());
+                }
+
               }
             }
-
           }
         }
       }
+      // we do sequenceMappings last because they span all datasets in a vamsas
+      // root
+      for (int _ds = 0, _nds = root.getDataSetCount(); _ds < _nds; _ds++)
+      {
+        DataSet dataset = root.getDataSet(_ds);
+        if (dataset.getSequenceMappingCount() > 0)
+        {
+          for (int sm = 0, smCount = dataset.getSequenceMappingCount(); sm < smCount; sm++)
+          {
+            Rangetype seqmap = new jalview.io.vamsas.Sequencemapping(this,
+                    dataset.getSequenceMapping(sm));
+          }
+        }
+      }
+    }
+    return newAlignmentViews.size();
+  }
+
+  public AlignmentViewport findViewport(Alignment alignment)
+  {
+    AlignmentViewport av = null;
+    AlignmentViewport[] avs = Desktop
+            .getViewports((String) getvObj2jv(alignment));
+    if (avs != null)
+    {
+      av = avs[0];
     }
+    return av;
   }
 
   // bitfields - should be a template in j1.5
   private static int HASSECSTR = 0;
+
   private static int HASVALS = 1;
+
   private static int HASHPHOB = 2;
+
   private static int HASDC = 3;
+
   private static int HASDESCSTR = 4;
+
   private static int HASTWOSTATE = 5; // not used yet.
+
   /**
-   * parses the AnnotationElements - if they exist - into jalview.datamodel.Annotation[] rows
-   * Two annotation rows are made if there are distinct annotation for both at 'pos' and 'after pos' at any particular site.
+   * parses the AnnotationElements - if they exist - into
+   * jalview.datamodel.Annotation[] rows Two annotation rows are made if there
+   * are distinct annotation for both at 'pos' and 'after pos' at any particular
+   * site.
+   * 
    * @param annotation
-   * @return { boolean[static int constants ], int[ae.length] - map to annotated object frame, jalview.datamodel.Annotation[], jalview.datamodel.Annotation[] (after)}
+   * @return { boolean[static int constants ], int[ae.length] - map to annotated
+   *         object frame, jalview.datamodel.Annotation[],
+   *         jalview.datamodel.Annotation[] (after)}
    */
-  private Object[] parseRangeAnnotation(uk.ac.vamsas.objects.core.RangeAnnotation
-                                        annotation)
+  private Object[] parseRangeAnnotation(
+          uk.ac.vamsas.objects.core.RangeAnnotation annotation)
   {
-    // set these attributes by looking in the annotation to decide what kind of alignment annotation rows will be made
-    // TODO: potentially we might make several annotation rows from one vamsas alignment annotation. the jv2Vobj binding mechanism
-    // may not quite cope with this (without binding an array of annotations to a vamsas alignment annotation)
+    // set these attributes by looking in the annotation to decide what kind of
+    // alignment annotation rows will be made
+    // TODO: potentially we might make several annotation rows from one vamsas
+    // alignment annotation. the jv2Vobj binding mechanism
+    // may not quite cope with this (without binding an array of annotations to
+    // a vamsas alignment annotation)
     // summary flags saying what we found over the set of annotation rows.
-    boolean[] AeContent = new boolean[]
-        {
-        false, false, false, false, false};
+    boolean[] AeContent = new boolean[] { false, false, false, false, false };
     int[] rangeMap = getMapping(annotation);
     jalview.datamodel.Annotation[][] anot = new jalview.datamodel.Annotation[][]
-        {
-        new jalview.datamodel.Annotation[rangeMap.length],
-        new jalview.datamodel.Annotation[rangeMap.length]
-    };
-    boolean mergeable = true; //false  if 'after positions cant be placed on same annotation row as positions.
+    { new jalview.datamodel.Annotation[rangeMap.length],
+        new jalview.datamodel.Annotation[rangeMap.length] };
+    boolean mergeable = true; // false if 'after positions cant be placed on
+    // same annotation row as positions.
 
     if (annotation.getAnnotationElementCount() > 0)
     {
       AnnotationElement ae[] = annotation.getAnnotationElement();
       for (int aa = 0; aa < ae.length; aa++)
       {
-        int pos = (int) ae[aa].getPosition() - 1; // pos counts from 1 to (|seg.start-seg.end|+1)
+        int pos = (int) ae[aa].getPosition() - 1; // pos counts from 1 to
+        // (|seg.start-seg.end|+1)
         if (pos >= 0 && pos < rangeMap.length)
         {
           int row = ae[aa].getAfter() ? 1 : 0;
@@ -1383,43 +2073,46 @@ public class VamsasAppDatastore
               AeContent[HASDESCSTR] = true;
             }
           }
-          String dc = null; //ae[aa].getDisplayCharacter()==null ? "dc" : ae[aa].getDisplayCharacter();
-          String ss = null; //ae[aa].getSecondaryStructure()==null ? "ss" : ae[aa].getSecondaryStructure();
+          String dc = null; // ae[aa].getDisplayCharacter()==null ? "dc" :
+          // ae[aa].getDisplayCharacter();
+          String ss = null; // ae[aa].getSecondaryStructure()==null ? "ss" :
+          // ae[aa].getSecondaryStructure();
           java.awt.Color colour = null;
           if (ae[aa].getGlyphCount() > 0)
           {
             Glyph[] glyphs = ae[aa].getGlyph();
             for (int g = 0; g < glyphs.length; g++)
             {
-              if (glyphs[g].getDict().equals(uk.ac.vamsas.objects.utils.
-                                             GlyphDictionary.PROTEIN_SS_3STATE))
+              if (glyphs[g]
+                      .getDict()
+                      .equals(uk.ac.vamsas.objects.utils.GlyphDictionary.PROTEIN_SS_3STATE))
               {
                 ss = glyphs[g].getContent();
                 AeContent[HASSECSTR] = true;
               }
-              else if (glyphs[g].getDict().equals(uk.ac.vamsas.objects.utils.
-                                                  GlyphDictionary.
-                                                  PROTEIN_HD_HYDRO))
+              else if (glyphs[g]
+                      .getDict()
+                      .equals(uk.ac.vamsas.objects.utils.GlyphDictionary.PROTEIN_HD_HYDRO))
               {
                 Cache.log.debug("ignoring hydrophobicity glyph marker.");
                 AeContent[HASHPHOB] = true;
                 char c = (dc = glyphs[g].getContent()).charAt(0);
                 // dc may get overwritten - but we still set the colour.
                 colour = new java.awt.Color(c == '+' ? 255 : 0,
-                                            c == '.' ? 255 : 0,
-                                            c == '-' ? 255 : 0);
+                        c == '.' ? 255 : 0, c == '-' ? 255 : 0);
 
               }
-              else if (glyphs[g].getDict().equals(uk.ac.vamsas.objects.utils.
-                                                  GlyphDictionary.DEFAULT))
+              else if (glyphs[g].getDict().equals(
+                      uk.ac.vamsas.objects.utils.GlyphDictionary.DEFAULT))
               {
                 dc = glyphs[g].getContent();
                 AeContent[HASDC] = true;
               }
               else
               {
-                Cache.log.debug("Ignoring unknown glyph type " +
-                                glyphs[g].getDict());
+                Cache.log
+                        .debug("IMPLEMENTATION TODO: Ignoring unknown glyph type "
+                                + glyphs[g].getDict());
               }
             }
           }
@@ -1429,27 +2122,29 @@ public class VamsasAppDatastore
             AeContent[HASVALS] = true;
             if (ae[aa].getValueCount() > 1)
             {
-              Cache.log.warn("ignoring additional " +
-                             (ae[aa].getValueCount() - 1) +
-                             "values in annotation element.");
+              Cache.log.warn("ignoring additional "
+                      + (ae[aa].getValueCount() - 1)
+                      + " values in annotation element.");
             }
             val = ae[aa].getValue(0);
           }
           if (colour == null)
           {
-            anot[row][pos] = new jalview.datamodel.Annotation( (dc != null) ?
-                dc : "", desc, (ss != null) ? ss.charAt(0) : ' ', val);
+            anot[row][pos] = new jalview.datamodel.Annotation(
+                    (dc != null) ? dc : "", desc,
+                    (ss != null) ? ss.charAt(0) : ' ', val);
           }
           else
           {
-            anot[row][pos] = new jalview.datamodel.Annotation( (dc != null) ?
-                dc : "", desc, (ss != null) ? ss.charAt(0) : ' ', val, colour);
+            anot[row][pos] = new jalview.datamodel.Annotation(
+                    (dc != null) ? dc : "", desc,
+                    (ss != null) ? ss.charAt(0) : ' ', val, colour);
           }
         }
         else
         {
-          Cache.log.warn("Ignoring out of bound annotation element " + aa +
-                         " in " + annotation.getVorbaId().getId());
+          Cache.log.warn("Ignoring out of bound annotation element " + aa
+                  + " in " + annotation.getVorbaId().getId());
         }
       }
       // decide on how many annotation rows are needed.
@@ -1461,7 +2156,8 @@ public class VamsasAppDatastore
           {
             anot[0][i] = anot[1][i];
             anot[0][i].description = anot[0][i].description + " (after)";
-            AeContent[HASDESCSTR] = true; // we have valid description string data
+            AeContent[HASDESCSTR] = true; // we have valid description string
+            // data
             anot[1][i] = null;
           }
         }
@@ -1474,43 +2170,95 @@ public class VamsasAppDatastore
           anot[1][i].description = anot[1][i].description + " (after)";
         }
       }
-      return new Object[]
-          {
-          AeContent, rangeMap, anot[0], anot[1]};
+      return new Object[] { AeContent, rangeMap, anot[0], anot[1] };
     }
     else
     {
-      // no annotations to parse. Just return an empty annotationElement[] array.
-      return new Object[]
-          {
-          AeContent, rangeMap, anot[0], anot[1]};
+      // no annotations to parse. Just return an empty annotationElement[]
+      // array.
+      return new Object[] { AeContent, rangeMap, anot[0], anot[1] };
     }
     // return null;
   }
 
   /**
-   * @param jal the jalview alignment to which the annotation will be attached (ideally - freshly updated from corresponding vamsas alignment)
+   * @param jal
+   *          the jalview alignment to which the annotation will be attached
+   *          (ideally - freshly updated from corresponding vamsas alignment)
    * @param annotation
    * @return unbound jalview alignment annotation object.
    */
-  private jalview.datamodel.AlignmentAnnotation getjAlignmentAnnotation(jalview.
-      datamodel.AlignmentI jal,
-      uk.ac.vamsas.objects.core.RangeAnnotation annotation)
+  private jalview.datamodel.AlignmentAnnotation getjAlignmentAnnotation(
+          jalview.datamodel.AlignmentI jal,
+          uk.ac.vamsas.objects.core.RangeAnnotation annotation)
   {
-    jalview.datamodel.AlignmentAnnotation jan = null;
     if (annotation == null)
     {
       return null;
     }
-    // boolean hasSequenceRef=annotation.getClass().equals(uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation.class);
-    //boolean hasProvenance=hasSequenceRef || (annotation.getClass().equals(uk.ac.vamsas.objects.core.AlignmentAnnotation.class));
-    /*int se[] = getBounds(annotation);
-         if (se==null)
-      se=new int[] {0,jal.getWidth()-1};
+    // boolean
+    // hasSequenceRef=annotation.getClass().equals(uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation.class);
+    // boolean hasProvenance=hasSequenceRef ||
+    // (annotation.getClass().equals(uk.ac.vamsas.objects.core.AlignmentAnnotation.class));
+    /*
+     * int se[] = getBounds(annotation); if (se==null) se=new int[]
+     * {0,jal.getWidth()-1};
      */
     Object[] parsedRangeAnnotation = parseRangeAnnotation(annotation);
     String a_label = annotation.getLabel();
     String a_descr = annotation.getDescription();
+    GraphLine gl = null;
+    int type = 0;
+    boolean interp = true; // cleared if annotation is DISCRETE
+    // set type and other attributes from properties
+    if (annotation.getPropertyCount() > 0)
+    {
+      // look for special jalview properties
+      uk.ac.vamsas.objects.core.Property[] props = annotation.getProperty();
+      for (int p = 0; p < props.length; p++)
+      {
+        if (props[p].getName().equalsIgnoreCase(DISCRETE_ANNOTATION))
+        {
+          type = AlignmentAnnotation.BAR_GRAPH;
+          interp = false;
+        }
+        else if (props[p].getName().equalsIgnoreCase(CONTINUOUS_ANNOTATION))
+        {
+          type = AlignmentAnnotation.LINE_GRAPH;
+        }
+        else if (props[p].getName().equalsIgnoreCase(THRESHOLD))
+        {
+          Float val = null;
+          try
+          {
+            val = new Float(props[p].getContent());
+          } catch (Exception e)
+          {
+            Cache.log.warn("Failed to parse threshold property");
+          }
+          if (val != null)
+          {
+            if (gl == null)
+            {
+              gl = new GraphLine(val.floatValue(), "", java.awt.Color.black);
+            }
+            else
+            {
+              gl.value = val.floatValue();
+            }
+          }
+        }
+        else if (props[p].getName().equalsIgnoreCase(THRESHOLD + "Name"))
+        {
+          if (gl == null)
+          {
+            gl = new GraphLine(0, "", java.awt.Color.black);
+          }
+          gl.label = props[p].getContent();
+        }
+      }
+    }
+    jalview.datamodel.AlignmentAnnotation jan = null;
     if (a_label == null || a_label.length() == 0)
     {
       a_label = annotation.getType();
@@ -1525,27 +2273,45 @@ public class VamsasAppDatastore
     }
     if (parsedRangeAnnotation == null)
     {
-      Cache.log.debug(
-          "Inserting empty annotation row elements for a whole-alignment annotation.");
-
+      Cache.log
+              .debug("Inserting empty annotation row elements for a whole-alignment annotation.");
     }
     else
     {
       if (parsedRangeAnnotation[3] != null)
       {
-        Cache.log.warn("Ignoring 'After' annotation row in " +
-                       annotation.getVorbaId());
+        Cache.log.warn("Ignoring 'After' annotation row in "
+                + annotation.getVorbaId());
       }
-      jalview.datamodel.Annotation[] arow = (jalview.datamodel.Annotation[])
-          parsedRangeAnnotation[2];
+      jalview.datamodel.Annotation[] arow = (jalview.datamodel.Annotation[]) parsedRangeAnnotation[2];
       boolean[] has = (boolean[]) parsedRangeAnnotation[0];
-      // VAMSAS: getGraph is only on derived annotation for alignments - in this way its 'odd' - there is already an existing TODO about removing this flag as being redundant
-      /*if ((annotation.getClass().equals(uk.ac.vamsas.objects.core.AlignmentAnnotation.class) && ((uk.ac.vamsas.objects.core.AlignmentAnnotation)annotation).getGraph())
-          || (hasSequenceRef=true && ((uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation)annotation).getGraph())) {
+      // VAMSAS: getGraph is only on derived annotation for alignments - in this
+      // way its 'odd' - there is already an existing TODO about removing this
+      // flag as being redundant
+      /*
+       * if((annotation.getClass().equals(uk.ac.vamsas.objects.core.
+       * AlignmentAnnotation.class) &&
+       * ((uk.ac.vamsas.objects.core.AlignmentAnnotation)annotation).getGraph())
+       * || (hasSequenceRef=true &&
+       * ((uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation
+       * )annotation).getGraph())) {
        */
       if (has[HASVALS])
       {
-        // make bounds and automatic description strings for jalview user's benefit (these shouldn't be written back to vamsas document)
+        if (type == 0)
+        {
+          type = jalview.datamodel.AlignmentAnnotation.BAR_GRAPH; // default
+          // type of
+          // value
+          // annotation
+          if (has[HASHPHOB])
+          {
+            // no hints - so we ensure HPHOB display is like this.
+            type = jalview.datamodel.AlignmentAnnotation.BAR_GRAPH;
+          }
+        }
+        // make bounds and automatic description strings for jalview user's
+        // benefit (these shouldn't be written back to vamsas document)
         boolean first = true;
         float min = 0, max = 1;
         int lastval = 0;
@@ -1553,7 +2319,7 @@ public class VamsasAppDatastore
         {
           if (arow[i] != null)
           {
-            if (i - lastval > 1)
+            if (i - lastval > 1 && interp)
             {
               // do some interpolation *between* points
               if (arow[lastval] != null)
@@ -1564,13 +2330,15 @@ public class VamsasAppDatastore
                 for (int ip = lastval + 1, np = 0; ip < i; np++, ip++)
                 {
                   arow[ip] = new jalview.datamodel.Annotation("", "", ' ',
-                      interval * np + base);
-                  // NB - Interpolated points don't get a tooltip and description.
+                          interval * np + base);
+                  // NB - Interpolated points don't get a tooltip and
+                  // description.
                 }
               }
             }
             lastval = i;
-            // check range - shouldn't we have a min and max property in the annotation object ?
+            // check range - shouldn't we have a min and max property in the
+            // annotation object ?
             if (first)
             {
               min = max = arow[i].value;
@@ -1594,68 +2362,71 @@ public class VamsasAppDatastore
             }
             if (!has[HASDC])
             {
-              arow[i].displayCharacter = arow[i].value + "";
+              if (!interp)
+              {
+                if (arow[i].description != null
+                        && arow[i].description.length() < 3)
+                {
+                  // copy over the description as the display char.
+                  arow[i].displayCharacter = new String(arow[i].description);
+                }
+              }
+              else
+              {
+                // mark the position as a point used for the interpolation.
+                arow[i].displayCharacter = arow[i].value + "";
+              }
             }
           }
         }
-        int type = jalview.datamodel.AlignmentAnnotation.LINE_GRAPH;
-        if (has[HASHPHOB])
-        {
-          type = jalview.datamodel.AlignmentAnnotation.BAR_GRAPH;
-        }
-        jan = new jalview.datamodel.AlignmentAnnotation(a_label, a_descr, arow,
-            min, max, type);
+        jan = new jalview.datamodel.AlignmentAnnotation(a_label, a_descr,
+                arow, min, max, type);
       }
       else
       {
-        jan = new jalview.datamodel.AlignmentAnnotation(a_label, a_descr, arow);
+        if (annotation.getAnnotationElementCount() == 0)
+        {
+          // empty annotation array
+          // TODO: alignment 'features' compare rangeType spec to alignment
+          // width - if it is not complete, then mark regions on the annotation
+          // row.
+        }
+        jan = new jalview.datamodel.AlignmentAnnotation(a_label, a_descr,
+                arow);
         jan.setThreshold(null);
+        jan.annotationId = annotation.getVorbaId().toString(); // keep all the
+        // ids together.
       }
       if (annotation.getLinkCount() > 0)
       {
-        Cache.log.warn("Ignoring " + annotation.getLinkCount() +
-                       "links added to AlignmentAnnotation.");
+        Cache.log.warn("Ignoring " + annotation.getLinkCount()
+                + "links added to AlignmentAnnotation.");
       }
-      if (annotation.getModifiable()==null) // TODO: USE VAMSAS LIBRARY OBJECT LOCK METHODS)
+      if (annotation.getModifiable() == null
+              || annotation.getModifiable().length() == 0) // TODO: USE VAMSAS
+      // LIBRARY OBJECT
+      // LOCK METHODS)
       {
         jan.editable = true;
       }
-
-      if (annotation.getPropertyCount() > 0)
+      try
       {
-        // look for special jalview properties
-        uk.ac.vamsas.objects.core.Property[] props = annotation.getProperty();
-        for (int p = 0; p < props.length; p++)
+        if (annotation.getGroup() != null
+                && annotation.getGroup().length() > 0)
         {
-          if (props[p].getName().equalsIgnoreCase("jalview:graphType"))
-          {
-            try
-            {
-              // probably a jalview annotation graph so recover the visualization hints.
-              jan.graph = jalview.datamodel.AlignmentAnnotation.
-                  getGraphValueFromString(props[p].getContent());
-            }
-            catch (Exception e)
-            {
-              Cache.log.debug(
-                  "Invalid graph type value in jalview:graphType property.");
-            }
-            try
-            {
-              if (annotation.getGroup() != null &&
-                  annotation.getGroup().length() > 0)
-              {
-                jan.graphGroup = Integer.parseInt(annotation.getGroup());
-              }
-            }
-            catch (Exception e)
-            {
-              Cache.log.info("UNIMPLEMENTED : Couldn't parse non-integer group value for setting graphGroup correctly.");
-            }
-          }
+          jan.graphGroup = Integer.parseInt(annotation.getGroup()); // TODO:
+          // group
+          // similarly
+          // named
+          // annotation
+          // together
+          // ?
         }
+      } catch (Exception e)
+      {
+        Cache.log
+                .info("UNIMPLEMENTED : Couldn't parse non-integer group value for setting graphGroup correctly.");
       }
-
       return jan;
 
     }
@@ -1663,27 +2434,11 @@ public class VamsasAppDatastore
     return null;
   }
 
-  private SequenceFeature getJalviewSeqFeature(RangeAnnotation dseta)
-  {
-    int[] se = getBounds(dseta);
-    SequenceFeature sf = new jalview.datamodel.SequenceFeature(dseta.getType(),
-        dseta.getDescription(), dseta.getStatus(), se[0], se[1], dseta
-        .getGroup());
-    if (dseta.getLinkCount() > 0)
-    {
-      Link[] links = dseta.getLink();
-      for (int i = 0; i < links.length; i++)
-      {
-        sf.addLink(links[i].getContent() + "|" + links[i].getHref());
-      }
-    }
-    return sf;
-  }
-
   /**
    * get real bounds of a RangeType's specification. start and end are an
-   * inclusive range within which all segments and positions lie.
-   * TODO: refactor to vamsas utils
+   * inclusive range within which all segments and positions lie. TODO: refactor
+   * to vamsas utils
+   * 
    * @param dseta
    * @return int[] { start, end}
    */
@@ -1694,7 +2449,9 @@ public class VamsasAppDatastore
       int[] se = null;
       if (dseta.getSegCount() > 0 && dseta.getPosCount() > 0)
       {
-        throw new Error("Invalid vamsas RangeType - cannot resolve both lists of Pos and Seg from choice!");
+        throw new Error(
+                MessageManager
+                        .getString("error.invalid_vamsas_rangetype_cannot_resolve_lists"));
       }
       if (dseta.getSegCount() > 0)
       {
@@ -1714,11 +2471,10 @@ public class VamsasAppDatastore
       }
       if (dseta.getPosCount() > 0)
       {
-        // could do a polarity for pos range too. and pass back indication of discontinuities.
+        // could do a polarity for pos range too. and pass back indication of
+        // discontinuities.
         int pos = dseta.getPos(0).getI();
-        se = new int[]
-            {
-            pos, pos};
+        se = new int[] { pos, pos };
         for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++)
         {
           pos = dseta.getPos(p).getI();
@@ -1738,7 +2494,9 @@ public class VamsasAppDatastore
   }
 
   /**
-   * map from a rangeType's internal frame to the referenced object's coordinate frame.
+   * map from a rangeType's internal frame to the referenced object's coordinate
+   * frame.
+   * 
    * @param dseta
    * @return int [] { ref(pos)...} for all pos in rangeType's frame.
    */
@@ -1750,7 +2508,9 @@ public class VamsasAppDatastore
       int[] se = null;
       if (dseta.getSegCount() > 0 && dseta.getPosCount() > 0)
       {
-        throw new Error("Invalid vamsas RangeType - cannot resolve both lists of Pos and Seg from choice!");
+        throw new Error(
+                MessageManager
+                        .getString("error.invalid_vamsas_rangetype_cannot_resolve_lists"));
       }
       if (dseta.getSegCount() > 0)
       {
@@ -1780,7 +2540,7 @@ public class VamsasAppDatastore
       int[] range = new int[posList.size()];
       for (int i = 0; i < range.length; i++)
       {
-        range[i] = ( (Integer) posList.elementAt(i)).intValue();
+        range[i] = ((Integer) posList.elementAt(i)).intValue();
       }
       posList.clear();
       return range;
@@ -1788,48 +2548,89 @@ public class VamsasAppDatastore
     return null;
   }
 
-  /* not needed now.
-   * Provenance getVamsasProvenance(jalview.datamodel.Provenance jprov) {
-    jalview.datamodel.ProvenanceEntry[] entries = null;
-    // TODO: fix App and Action here.
-    Provenance prov = new Provenance();
-    org.exolab.castor.types.Date date = new org.exolab.castor.types.Date(
-        new java.util.Date());
-    Entry provEntry;
+  /**
+   * 
+   * @param maprange
+   *          where the from range is the local mapped range, and the to range
+   *          is the 'mapped' range in the MapRangeType
+   * @param default unit for local
+   * @param default unit for mapped
+   * @return MapList
+   */
+  private jalview.util.MapList parsemapType(MapType maprange, int localu,
+          int mappedu)
+  {
+    jalview.util.MapList ml = null;
+    int[] localRange = getMapping(maprange.getLocal());
+    int[] mappedRange = getMapping(maprange.getMapped());
+    long lu = maprange.getLocal().hasUnit() ? maprange.getLocal().getUnit()
+            : localu;
+    long mu = maprange.getMapped().hasUnit() ? maprange.getMapped()
+            .getUnit() : mappedu;
+    ml = new jalview.util.MapList(localRange, mappedRange, (int) lu,
+            (int) mu);
+    return ml;
+  }
 
-    if (jprov != null)
+  /**
+   * initialise a range type object from a set of start/end inclusive intervals
+   * 
+   * @param mrt
+   * @param ranges
+   */
+  private void initRangeType(RangeType mrt, List<int[]> ranges)
+  {
+    for (int[] range : ranges)
     {
-      entries = jprov.getEntries();
-      for (int i = 0; i < entries.length; i++)
-      {
-        provEntry = new Entry();
-        try
-        {
-          date = new org.exolab.castor.types.Date(entries[i].getDate());
-        } catch (Exception ex)
-        {
-          ex.printStackTrace();
-
-          date = new org.exolab.castor.types.Date(entries[i].getDate());
-        }
-        provEntry.setDate(date);
-        provEntry.setUser(entries[i].getUser());
-        provEntry.setAction(entries[i].getAction());
-        prov.addEntry(provEntry);
-      }
+      Seg vSeg = new Seg();
+      vSeg.setStart(range[0]);
+      vSeg.setEnd(range[1]);
+      mrt.addSeg(vSeg);
     }
-    else
+  }
+
+  /**
+   * initialise a MapType object from a MapList object.
+   * 
+   * @param maprange
+   * @param ml
+   * @param setUnits
+   */
+  private void initMapType(MapType maprange, jalview.util.MapList ml,
+          boolean setUnits)
+  {
+    maprange.setLocal(new Local());
+    maprange.setMapped(new Mapped());
+    initRangeType(maprange.getLocal(), ml.getFromRanges());
+    initRangeType(maprange.getMapped(), ml.getToRanges());
+    if (setUnits)
     {
-      provEntry = new Entry();
-      provEntry.setDate(date);
-      provEntry.setUser(System.getProperty("user.name")); // TODO: ext string
-      provEntry.setApp("JVAPP"); // TODO: ext string
-      provEntry.setAction(action);
-      prov.addEntry(provEntry);
+      maprange.getLocal().setUnit(ml.getFromRatio());
+      maprange.getLocal().setUnit(ml.getToRatio());
     }
+  }
 
-    return prov;
-     }
+  /*
+   * not needed now. Provenance getVamsasProvenance(jalview.datamodel.Provenance
+   * jprov) { jalview.datamodel.ProvenanceEntry[] entries = null; // TODO: fix
+   * App and Action here. Provenance prov = new Provenance();
+   * org.exolab.castor.types.Date date = new org.exolab.castor.types.Date( new
+   * java.util.Date()); Entry provEntry;
+   * 
+   * if (jprov != null) { entries = jprov.getEntries(); for (int i = 0; i <
+   * entries.length; i++) { provEntry = new Entry(); try { date = new
+   * org.exolab.castor.types.Date(entries[i].getDate()); } catch (Exception ex)
+   * { ex.printStackTrace();
+   * 
+   * date = new org.exolab.castor.types.Date(entries[i].getDate()); }
+   * provEntry.setDate(date); provEntry.setUser(entries[i].getUser());
+   * provEntry.setAction(entries[i].getAction()); prov.addEntry(provEntry); } }
+   * else { provEntry = new Entry(); provEntry.setDate(date);
+   * provEntry.setUser(System.getProperty("user.name")); // TODO: ext string
+   * provEntry.setApp("JVAPP"); // TODO: ext string provEntry.setAction(action);
+   * prov.addEntry(provEntry); }
+   * 
+   * return prov; }
    */
   jalview.datamodel.Provenance getJalviewProvenance(Provenance prov)
   {
@@ -1837,16 +2638,16 @@ public class VamsasAppDatastore
     jalview.datamodel.Provenance jprov = new jalview.datamodel.Provenance();
     for (int i = 0; i < prov.getEntryCount(); i++)
     {
-      jprov.addEntry(prov.getEntry(i).getUser(), prov.getEntry(i).getAction(),
-                     prov.getEntry(i).getDate().toDate(),
-                     prov.getEntry(i).getId());
+      jprov.addEntry(prov.getEntry(i).getUser(), prov.getEntry(i)
+              .getAction(), prov.getEntry(i).getDate(), prov.getEntry(i)
+              .getId());
     }
 
     return jprov;
   }
 
   /**
-   *
+   * 
    * @return default initial provenance list for a Jalview created vamsas
    *         object.
    */
@@ -1867,7 +2668,7 @@ public class VamsasAppDatastore
     {
       entry.setAction("created.");
     }
-    entry.setDate(new org.exolab.castor.types.Date(new java.util.Date()));
+    entry.setDate(new java.util.Date());
     entry.setUser(this.provEntry.getUser());
     return entry;
   }
@@ -1879,9 +2680,131 @@ public class VamsasAppDatastore
     return prov;
   }
 
-  void addProvenance(Provenance p, String action)
+  Entry addProvenance(Provenance p, String action)
+  {
+    Entry dentry = dummyPEntry(action);
+    p.addEntry(dentry);
+    return dentry;
+  }
+
+  public Entry getProvEntry()
+  {
+    return provEntry;
+  }
+
+  public IClientDocument getClientDocument()
+  {
+    return cdoc;
+  }
+
+  public IdentityHashMap getJvObjectBinding()
+  {
+    return jv2vobj;
+  }
+
+  public Hashtable getVamsasObjectBinding()
+  {
+    return vobj2jv;
+  }
+
+  public void storeSequenceMappings(AlignmentViewport viewport, String title)
+          throws Exception
+  {
+    AlignmentViewport av = viewport;
+    try
+    {
+      jalview.datamodel.AlignmentI jal = av.getAlignment();
+      // /////////////////////////////////////////
+      // SAVE THE DATASET
+      DataSet dataset = null;
+      if (jal.getDataset() == null)
+      {
+        Cache.log.warn("Creating new dataset for an alignment.");
+        jal.setDataset(null);
+      }
+      dataset = (DataSet) ((Alignment) getjv2vObj(viewport
+              .getSequenceSetId())).getV_parent(); // jal.getDataset());
+      if (dataset == null)
+      {
+        dataset = (DataSet) getjv2vObj(jal.getDataset());
+        Cache.log
+                .error("Can't find the correct dataset for the alignment in this view. Creating new one.");
+
+      }
+      // Store any sequence mappings.
+      Set<AlignedCodonFrame> cframes = av.getAlignment().getCodonFrames();
+      if (cframes != null)
+      {
+        for (AlignedCodonFrame acf : cframes)
+        {
+          if (acf.getdnaSeqs() != null && acf.getdnaSeqs().length > 0)
+          {
+            jalview.datamodel.SequenceI[] dmps = acf.getdnaSeqs();
+            jalview.datamodel.Mapping[] mps = acf.getProtMappings();
+            for (int smp = 0; smp < mps.length; smp++)
+            {
+              uk.ac.vamsas.objects.core.SequenceType mfrom = (SequenceType) getjv2vObj(dmps[smp]);
+              if (mfrom != null)
+              {
+                new jalview.io.vamsas.Sequencemapping(this, mps[smp],
+                        mfrom, dataset);
+              }
+              else
+              {
+                Cache.log
+                        .warn("NO Vamsas Binding for local sequence! NOT CREATING MAPPING FOR "
+                                + dmps[smp].getDisplayId(true)
+                                + " to "
+                                + mps[smp].getTo().getName());
+              }
+            }
+          }
+        }
+      }
+    } catch (Exception e)
+    {
+      throw new Exception(MessageManager.formatMessage(
+              "exception.couldnt_store_sequence_mappings",
+              new String[] { title }), e);
+    }
+  }
+
+  public void clearSkipList()
+  {
+    if (skipList != null)
+    {
+      skipList.clear();
+    }
+  }
+
+  /**
+   * @return the skipList
+   */
+  public Hashtable getSkipList()
+  {
+    return skipList;
+  }
+
+  /**
+   * @param skipList
+   *          the skipList to set
+   */
+  public void setSkipList(Hashtable skipList)
   {
-    p.addEntry(dummyPEntry(action));
+    this.skipList = skipList;
   }
 
+  /**
+   * registry for datastoreItems
+   */
+  DatastoreRegistry dsReg = new DatastoreRegistry();
+
+  public DatastoreRegistry getDatastoreRegisty()
+  {
+    if (dsReg == null)
+    {
+      dsReg = new DatastoreRegistry();
+    }
+    return dsReg;
+  }
 }