merge from 2_4_Release branch
[jalview.git] / src / jalview / io / VamsasAppDatastore.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
3  * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.io;
20
21 import jalview.bin.Cache;
22 import jalview.datamodel.AlignmentAnnotation;
23 import jalview.datamodel.AlignmentI;
24 import jalview.datamodel.AlignmentView;
25 import jalview.datamodel.DBRefEntry;
26 import jalview.datamodel.GraphLine;
27 import jalview.datamodel.SequenceFeature;
28 import jalview.datamodel.SequenceI;
29 import jalview.gui.AlignFrame;
30 import jalview.gui.AlignViewport;
31 import jalview.gui.Desktop;
32 import jalview.gui.TreePanel;
33 import jalview.io.vamsas.DatastoreItem;
34 import jalview.io.vamsas.Rangetype;
35
36 import java.util.Enumeration;
37 import java.util.HashMap;
38 import java.util.Hashtable;
39 import java.util.IdentityHashMap;
40 import java.util.Vector;
41
42 import uk.ac.vamsas.client.*;
43 import uk.ac.vamsas.objects.core.*;
44
45 /*
46  * 
47  * static {
48  * org.exolab.castor.util.LocalConfiguration.getInstance().getProperties().setProperty(
49  * "org.exolab.castor.serializer", "org.apache.xml.serialize.XMLSerilazizer"); }
50  * 
51  */
52
53 public class VamsasAppDatastore
54 {
55   /**
56    * Type used for general jalview generated annotation added to vamsas document
57    */
58   public static final String JALVIEW_ANNOTATION_ROW = "JalviewAnnotation";
59
60   /**
61    * AlignmentAnnotation property to indicate that values should not be
62    * interpolated
63    */
64   public static final String DISCRETE_ANNOTATION = "discrete";
65
66   /**
67    * continuous property - optional to specify that annotation should be
68    * represented as a continous graph line
69    */
70   private static final String CONTINUOUS_ANNOTATION = "continuous";
71
72   private static final String THRESHOLD = "threshold";
73
74   Entry provEntry = null;
75
76   IClientDocument cdoc;
77
78   Hashtable vobj2jv;
79
80   IdentityHashMap jv2vobj;
81
82   Hashtable alignRDHash;
83
84   public VamsasAppDatastore(IClientDocument cdoc, Hashtable vobj2jv,
85           IdentityHashMap jv2vobj, Entry provEntry, Hashtable alignRDHash)
86   {
87     this.cdoc = cdoc;
88     this.vobj2jv = vobj2jv;
89     this.jv2vobj = jv2vobj;
90     this.provEntry = provEntry;
91     this.alignRDHash = alignRDHash;
92   }
93
94   /**
95    * @return the Vobject bound to Jalview datamodel object
96    */
97   protected Vobject getjv2vObj(Object jvobj)
98   {
99     if (jv2vobj.containsKey(jvobj))
100     {
101       return cdoc.getObject((VorbaId) jv2vobj.get(jvobj));
102     }
103     if (Cache.log.isDebugEnabled())
104     {
105       Cache.log.debug("Returning null VorbaID binding for jalview object "
106               + jvobj);
107     }
108     return null;
109   }
110
111   /**
112    * 
113    * @param vobj
114    * @return Jalview datamodel object bound to the vamsas document object
115    */
116   protected Object getvObj2jv(uk.ac.vamsas.client.Vobject vobj)
117   {
118     VorbaId id = vobj.getVorbaId();
119     if (id == null)
120     {
121       id = cdoc.registerObject(vobj);
122       Cache.log
123               .debug("Registering new object and returning null for getvObj2jv");
124       return null;
125     }
126     if (vobj2jv.containsKey(vobj.getVorbaId()))
127     {
128       return vobj2jv.get(vobj.getVorbaId());
129     }
130     return null;
131   }
132
133   protected void bindjvvobj(Object jvobj, uk.ac.vamsas.client.Vobject vobj)
134   {
135     VorbaId id = vobj.getVorbaId();
136     if (id == null)
137     {
138       id = cdoc.registerObject(vobj);
139       if (id == null || vobj.getVorbaId() == null
140               || cdoc.getObject(id) != vobj)
141       {
142         Cache.log.error("Failed to get id for "
143                 + (vobj.isRegisterable() ? "registerable"
144                         : "unregisterable") + " object " + vobj);
145       }
146     }
147
148     if (vobj2jv.containsKey(vobj.getVorbaId())
149             && !((VorbaId) vobj2jv.get(vobj.getVorbaId())).equals(jvobj))
150     {
151       Cache.log.debug(
152               "Warning? Overwriting existing vamsas id binding for "
153                       + vobj.getVorbaId(), new Exception(
154                       "Overwriting vamsas id binding."));
155     }
156     else if (jv2vobj.containsKey(jvobj)
157             && !((VorbaId) jv2vobj.get(jvobj)).equals(vobj.getVorbaId()))
158     {
159       Cache.log.debug(
160               "Warning? Overwriting existing jalview object binding for "
161                       + jvobj, new Exception(
162                       "Overwriting jalview object binding."));
163     }
164     /*
165      * Cache.log.error("Attempt to make conflicting object binding! "+vobj+" id "
166      * +vobj.getVorbaId()+" already bound to "+getvObj2jv(vobj)+" and "+jvobj+"
167      * already bound to "+getjv2vObj(jvobj),new Exception("Excessive call to
168      * bindjvvobj")); }
169      */
170     // we just update the hash's regardless!
171     Cache.log.debug("Binding " + vobj.getVorbaId() + " to " + jvobj);
172     vobj2jv.put(vobj.getVorbaId(), jvobj);
173     // JBPNote - better implementing a hybrid invertible hash.
174     jv2vobj.put(jvobj, vobj.getVorbaId());
175   }
176
177   /**
178    * put the alignment viewed by AlignViewport into cdoc.
179    * 
180    * @param av
181    *                alignViewport to be stored
182    * @param aFtitle
183    *                title for alignment
184    */
185   public void storeVAMSAS(AlignViewport av, String aFtitle)
186   {
187     try
188     {
189       jalview.datamodel.AlignmentI jal = av.getAlignment();
190       boolean nw = false;
191       VAMSAS root = null; // will be resolved based on Dataset Parent.
192       // /////////////////////////////////////////
193       // SAVE THE DATASET
194       DataSet dataset = null;
195       if (jal.getDataset() == null)
196       {
197         Cache.log.warn("Creating new dataset for an alignment.");
198         jal.setDataset(null);
199       }
200       dataset = (DataSet) getjv2vObj(jal.getDataset());
201       if (dataset == null)
202       {
203         // it might be that one of the dataset sequences does actually have a
204         // binding, so search for it indirectly.
205         jalview.datamodel.SequenceI[] jdatset = jal.getDataset()
206                 .getSequencesArray();
207         for (int i = 0; i < jdatset.length; i++)
208         {
209           Vobject vbound = getjv2vObj(jdatset[i]);
210           if (vbound != null)
211           {
212             if (vbound instanceof uk.ac.vamsas.objects.core.Sequence)
213             {
214               if (dataset == null)
215               {
216                 dataset = (DataSet) vbound.getV_parent();
217               }
218               else
219               {
220                 if (dataset != vbound.getV_parent())
221                 {
222                   throw new Error(
223                           "IMPLEMENTATION ERROR: Cannot map an alignment of sequences from datasets into the vamsas document.");
224                   // This occurs because the dataset for the alignment we are
225                   // trying to
226                 }
227               }
228             }
229           }
230         }
231       }
232
233       if (dataset == null)
234       {
235         // we create a new dataset on the default vamsas root.
236         root = cdoc.getVamsasRoots()[0]; // default vamsas root for modifying.
237         dataset = new DataSet();
238         root.addDataSet(dataset);
239         bindjvvobj(jal.getDataset(), dataset);
240         dataset.setProvenance(dummyProvenance());
241         // dataset.getProvenance().addEntry(provEntry);
242         nw = true;
243       }
244       else
245       {
246         root = (VAMSAS) dataset.getV_parent();
247       }
248       // update dataset
249       Sequence sequence;
250       DbRef dbref;
251       // set new dataset and alignment sequences based on alignment Nucleotide
252       // flag.
253       // this *will* break when alignment contains both nucleotide and amino
254       // acid sequences.
255       String dict = jal.isNucleotide() ? uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA
256               : uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_AA;
257       Vector dssmods = new Vector();
258       for (int i = 0; i < jal.getHeight(); i++)
259       {
260         SequenceI sq = jal.getSequenceAt(i).getDatasetSequence(); // only insert
261         // referenced
262         // sequences
263         // to dataset.
264         sequence = (Sequence) getjv2vObj(sq);
265         if (sequence == null)
266         {
267           sequence = new Sequence();
268           bindjvvobj(sq, sequence);
269           sq.setVamsasId(sequence.getVorbaId().getId());
270           sequence.setSequence(sq.getSequenceAsString());
271           sequence.setDictionary(dict);
272           sequence.setName(sq.getName());
273           sequence.setStart(sq.getStart());
274           sequence.setEnd(sq.getEnd());
275           sequence.setDescription(sq.getDescription());
276           dataset.addSequence(sequence);
277           dssmods.addElement(dssmods);
278         }
279         else
280         {
281           boolean dsmod = false;
282           // verify and update principal attributes.
283           if (sq.getDescription() != null
284                   && (sequence.getDescription() == null || !sequence
285                           .getDescription().equals(sq.getDescription())))
286           {
287             sequence.setDescription(sq.getDescription());
288             dsmod = true;
289           }
290           if (sequence.getSequence() == null
291                   || !sequence.getSequence().equals(
292                           sq.getSequenceAsString()))
293           {
294             if (sequence.getStart() != sq.getStart()
295                     || sequence.getEnd() != sq.getEnd())
296             {
297               // update modified sequence.
298               sequence.setSequence(sq.getSequenceAsString());
299               sequence.setStart(sq.getStart());
300               sequence.setEnd(sq.getEnd());
301               dsmod = true;
302             }
303           }
304           if (!dict.equals(sequence.getDictionary()))
305           {
306             sequence.setDictionary(dict);
307             dsmod = true;
308           }
309           if (!sequence.getName().equals(sq.getName()))
310           {
311             sequence.setName(sq.getName());
312             dsmod = true;
313           }
314           if (dsmod)
315           {
316             dssmods.addElement(sequence);
317           }
318         }
319         // add or update any new features/references on dataset sequence
320         if (sq.getSequenceFeatures() != null)
321         {
322           int sfSize = sq.getSequenceFeatures().length;
323
324           for (int sf = 0; sf < sfSize; sf++)
325           {
326             // TODO: update/modifiable synchronizer
327             jalview.datamodel.SequenceFeature feature = (jalview.datamodel.SequenceFeature) sq
328                     .getSequenceFeatures()[sf];
329
330             DataSetAnnotations dsa = (DataSetAnnotations) getjv2vObj(feature);
331             if (dsa == null)
332             {
333               dsa = (DataSetAnnotations) getDSAnnotationFromJalview(
334                       new DataSetAnnotations(), feature);
335               if (dsa.getProvenance() == null)
336               {
337                 dsa.setProvenance(new Provenance());
338               }
339               addProvenance(dsa.getProvenance(), "created"); // JBPNote - need
340               // to update
341               dsa.addSeqRef(sequence); // we have just created this annotation
342               // - so safe to use this
343               bindjvvobj(feature, dsa);
344               dataset.addDataSetAnnotations(dsa);
345             }
346             else
347             {
348               // todo: verify and update dataset annotations for sequence
349               System.out.println("update dataset sequence annotations.");
350             }
351           }
352         }
353         if (sq.getDatasetSequence() == null && sq.getDBRef() != null)
354         {
355           // only sync database references for dataset sequences
356           DBRefEntry[] entries = sq.getDBRef();
357           jalview.datamodel.DBRefEntry dbentry;
358           for (int db = 0; db < entries.length; db++)
359           {
360             Rangetype dbr = new jalview.io.vamsas.Dbref(this,
361                     dbentry = entries[db], sq, sequence);
362           }
363
364         }
365       }
366       if (dssmods.size() > 0)
367       {
368         if (!nw)
369         {
370           Entry pentry = this.addProvenance(dataset.getProvenance(),
371                   "updated sequences");
372           // pentry.addInput(vInput); could write in which sequences were
373           // modified.
374           dssmods.removeAllElements();
375         }
376       }
377       // dataset.setProvenance(getVamsasProvenance(jal.getDataset().getProvenance()));
378       // ////////////////////////////////////////////
379       if (!av.getAlignment().isAligned())
380         return; // TODO: trees could be written - but for the moment we just
381       // skip
382       // ////////////////////////////////////////////
383       // Save the Alignments
384
385       Alignment alignment = (Alignment) getjv2vObj(av.getSequenceSetId()); // bind
386       // to
387       // the
388       // value
389       // used
390       // to
391       // associate
392       // different
393       // views
394       // to
395       // same
396       // alignment
397
398       if (alignment == null)
399       {
400         alignment = new Alignment();
401         bindjvvobj(av.getSequenceSetId(), alignment);
402         if (alignment.getProvenance() == null)
403         {
404           alignment.setProvenance(new Provenance());
405         }
406         addProvenance(alignment.getProvenance(), "added"); // TODO: insert some
407         // sensible source
408         // here
409         dataset.addAlignment(alignment);
410         {
411           Property title = new Property();
412           title.setName("title");
413           title.setType("string");
414           title.setContent(aFtitle);
415           alignment.addProperty(title);
416         }
417         alignment.setGapChar(String.valueOf(av.getGapCharacter()));
418         for (int i = 0; i < jal.getHeight(); i++)
419         {
420           syncToAlignmentSequence(jal.getSequenceAt(i), alignment, null);
421         }
422         alignRDHash.put(av.getSequenceSetId(), av.getUndoRedoHash());
423       }
424       else
425       {
426         // always prepare to clone the alignment
427         boolean alismod = av.isUndoRedoHashModified((long[]) alignRDHash
428                 .get(av.getSequenceSetId()));
429         // todo: verify and update mutable alignment props.
430         // TODO: Use isLocked methods
431         if (alignment.getModifiable() == null
432                 || alignment.getModifiable().length() == 0)
433         // && !alignment.isDependedOn())
434         {
435           boolean modified = false;
436           // check existing sequences in local and in document.
437           Vector docseqs = new Vector(alignment
438                   .getAlignmentSequenceAsReference());
439           for (int i = 0; i < jal.getHeight(); i++)
440           {
441             modified |= syncToAlignmentSequence(jal.getSequenceAt(i),
442                     alignment, docseqs);
443           }
444           if (docseqs.size() > 0)
445           {
446             // removeValignmentSequences(alignment, docseqs);
447             docseqs.removeAllElements();
448             System.out
449                     .println("Sequence deletion from alignment is not implemented.");
450
451           }
452           if (modified)
453           {
454             if (alismod)
455             {
456               // info in the undo
457               addProvenance(alignment.getProvenance(), "Edited"); // TODO:
458               // insert
459               // something
460               // sensible
461               // here again
462             }
463             else
464             {
465               // info in the undo
466               addProvenance(alignment.getProvenance(), "Attributes Edited"); // TODO:
467               // insert
468               // something
469               // sensible
470               // here
471               // again
472             }
473           }
474           if (alismod)
475           {
476             System.out.println("update alignment in document.");
477           }
478           else
479           {
480             System.out.println("alignment in document left unchanged.");
481           }
482         }
483         else
484         {
485           // unbind alignment from view.
486           // create new binding and new alignment.
487           // mark trail on new alignment as being derived from old ?
488           System.out
489                   .println("update edited alignment to new alignment in document.");
490         }
491       }
492       // ////////////////////////////////////////////
493       // SAVE Alignment Sequence Features
494       for (int i = 0, iSize = alignment.getAlignmentSequenceCount(); i < iSize; i++)
495       {
496         AlignmentSequence valseq;
497         SequenceI alseq = (SequenceI) getvObj2jv(valseq = alignment
498                 .getAlignmentSequence(i));
499         if (alseq != null && alseq.getSequenceFeatures() != null)
500         {
501           /*
502            * We do not put local Alignment Sequence Features into the vamsas
503            * document yet.
504            * 
505            * 
506            * jalview.datamodel.SequenceFeature[] features = alseq
507            * .getSequenceFeatures(); for (int f = 0; f < features.length; f++) {
508            * if (features[f] != null) { AlignmentSequenceAnnotation valseqf = (
509            * AlignmentSequenceAnnotation) getjv2vObj(features[i]); if (valseqf ==
510            * null) {
511            * 
512            * valseqf = (AlignmentSequenceAnnotation) getDSAnnotationFromJalview(
513            * new AlignmentSequenceAnnotation(), features[i]);
514            * valseqf.setGraph(false);
515            * valseqf.addProperty(newProperty("jalview:feature","boolean","true"));
516            * if (valseqf.getProvenance() == null) { valseqf.setProvenance(new
517            * Provenance()); } addProvenance(valseqf.getProvenance(), "created"); //
518            * JBPNote - // need to // update bindjvvobj(features[i], valseqf);
519            * valseq.addAlignmentSequenceAnnotation(valseqf); } } }
520            */
521         }
522       }
523
524       // ////////////////////////////////////////////
525       // SAVE ANNOTATIONS
526       if (jal.getAlignmentAnnotation() != null)
527       {
528         jalview.datamodel.AlignmentAnnotation[] aa = jal
529                 .getAlignmentAnnotation();
530         java.util.HashMap AlSeqMaps = new HashMap(); // stores int maps from
531         // alignment columns to
532         // sequence positions.
533         for (int i = 0; i < aa.length; i++)
534         {
535           if (aa[i] == null || isJalviewOnly(aa[i]))
536           {
537             continue;
538           }
539           if (aa[i].sequenceRef != null)
540           {
541             // Deal with sequence associated annotation
542             Vobject sref = getjv2vObj(aa[i].sequenceRef);
543             if (sref instanceof uk.ac.vamsas.objects.core.AlignmentSequence)
544             {
545               saveAlignmentSequenceAnnotation(AlSeqMaps,
546                       (AlignmentSequence) sref, aa[i]);
547             }
548             else
549             {
550               // first find the alignment sequence to associate this with.
551               SequenceI jvalsq = null;
552               Enumeration jval = av.getAlignment().getSequences()
553                       .elements();
554               while (jval.hasMoreElements())
555               {
556                 jvalsq = (SequenceI) jval.nextElement();
557                 // saveDatasetSequenceAnnotation(AlSeqMaps,(uk.ac.vamsas.objects.core.Sequence)
558                 // sref, aa[i]);
559                 if (jvalsq.getDatasetSequence() == aa[i].sequenceRef)
560                 {
561                   Vobject alsref = getjv2vObj(jvalsq);
562                   saveAlignmentSequenceAnnotation(AlSeqMaps,
563                           (AlignmentSequence) alsref, aa[i]);
564                   break;
565                 }
566                 ;
567               }
568             }
569           }
570           else
571           {
572             // add Alignment Annotation
573             uk.ac.vamsas.objects.core.AlignmentAnnotation an = (uk.ac.vamsas.objects.core.AlignmentAnnotation) getjv2vObj(aa[i]);
574             if (an == null)
575             {
576               an = new uk.ac.vamsas.objects.core.AlignmentAnnotation();
577               an.setType(JALVIEW_ANNOTATION_ROW);
578               an.setDescription(aa[i].description);
579               alignment.addAlignmentAnnotation(an);
580               Seg vSeg = new Seg(); // TODO: refactor to have a default
581               // rangeAnnotationType initer/updater that
582               // takes a set of int ranges.
583               vSeg.setStart(1);
584               vSeg.setInclusive(true);
585               vSeg.setEnd(jal.getWidth());
586               an.addSeg(vSeg);
587               if (aa[i].graph > 0)
588               {
589                 an.setGraph(true); // aa[i].graph);
590               }
591               an.setLabel(aa[i].label);
592               an.setProvenance(dummyProvenance());
593               if (aa[i].graph != AlignmentAnnotation.NO_GRAPH)
594               {
595                 an.setGroup(Integer.toString(aa[i].graphGroup)); // // JBPNote
596                 // -
597                 // originally we
598                 // were going to
599                 // store
600                 // graphGroup in
601                 // the Jalview
602                 // specific
603                 // bits.
604                 an.setGraph(true);
605               }
606               else
607               {
608                 an.setGraph(false);
609               }
610               AnnotationElement ae;
611
612               for (int a = 0; a < aa[i].annotations.length; a++)
613               {
614                 if ((aa[i] == null) || (aa[i].annotations[a] == null))
615                 {
616                   continue;
617                 }
618
619                 ae = new AnnotationElement();
620                 ae.setDescription(aa[i].annotations[a].description);
621                 ae.addGlyph(new Glyph());
622                 ae.getGlyph(0).setContent(
623                         aa[i].annotations[a].displayCharacter); // assume
624                 // jax-b
625                 // takes
626                 // care
627                 // of
628                 // utf8
629                 // translation
630                 if (an.isGraph())
631                 {
632                   ae.addValue(aa[i].annotations[a].value);
633                 }
634                 ae.setPosition(a + 1);
635                 if (aa[i].annotations[a].secondaryStructure != ' ')
636                 {
637                   Glyph ss = new Glyph();
638                   ss
639                           .setDict(uk.ac.vamsas.objects.utils.GlyphDictionary.PROTEIN_SS_3STATE);
640                   ss
641                           .setContent(String
642                                   .valueOf(aa[i].annotations[a].secondaryStructure));
643                   ae.addGlyph(ss);
644                 }
645                 an.addAnnotationElement(ae);
646               }
647               if (aa[i].editable)
648               {
649                 // an.addProperty(newProperty("jalview:editable", null,
650                 // "true"));
651                 // an.setModifiable(""); // TODO: This is not the way the
652                 // modifiable flag is supposed to be used.
653               }
654               setAnnotationType(an, aa[i]);
655
656               if (aa[i].graph != jalview.datamodel.AlignmentAnnotation.NO_GRAPH)
657               {
658                 an.setGraph(true);
659                 an.setGroup(Integer.toString(aa[i].graphGroup));
660                 if (aa[i].threshold != null && aa[i].threshold.displayed)
661                 {
662                   an.addProperty(newProperty(THRESHOLD, "float", ""
663                           + aa[i].threshold.value));
664                   if (aa[i].threshold.label != null)
665                   {
666                     an.addProperty(newProperty(THRESHOLD + "Name",
667                             "string", "" + aa[i].threshold.label));
668                   }
669                 }
670               }
671
672             }
673
674             else
675             {
676               if (an.getModifiable() == null) // TODO: USE VAMSAS LIBRARY OBJECT
677               // LOCK METHODS)
678               {
679                 // verify annotation - update (perhaps)
680                 Cache.log
681                         .info("update alignment sequence annotation. not yet implemented.");
682               }
683               else
684               {
685                 // verify annotation - update (perhaps)
686                 Cache.log
687                         .info("updated alignment sequence annotation added.");
688               }
689             }
690           }
691         }
692       }
693       // /////////////////////////////////////////////////////
694
695       // //////////////////////////////////////////////
696       // /SAVE THE TREES
697       // /////////////////////////////////
698       // FIND ANY ASSOCIATED TREES
699       if (Desktop.desktop != null)
700       {
701         javax.swing.JInternalFrame[] frames = Desktop.instance
702                 .getAllFrames();
703
704         for (int t = 0; t < frames.length; t++)
705         {
706           if (frames[t] instanceof TreePanel)
707           {
708             TreePanel tp = (TreePanel) frames[t];
709
710             if (tp.getAlignment() == jal)
711             {
712               DatastoreItem vtree = new jalview.io.vamsas.Tree(this, tp,
713                       jal, alignment);
714             }
715           }
716         }
717       }
718       // Store Jalview specific stuff in the Jalview appData
719       // not implemented in the SimpleDoc interface.
720     }
721
722     catch (Exception ex)
723     {
724       ex.printStackTrace();
725     }
726
727   }
728
729   /**
730    * remove docseqs from the given alignment marking provenance appropriately
731    * and removing any references to the sequences.
732    * 
733    * @param alignment
734    * @param docseqs
735    */
736   private void removeValignmentSequences(Alignment alignment, Vector docseqs)
737   {
738     // delete these from document. This really needs to be a generic document
739     // API function derived by CASTOR.
740     Enumeration en = docseqs.elements();
741     while (en.hasMoreElements())
742     {
743       alignment.removeAlignmentSequence((AlignmentSequence) en
744               .nextElement());
745     }
746     Entry pe = addProvenance(alignment.getProvenance(), "Removed "
747             + docseqs.size() + " sequences");
748     en = alignment.enumerateAlignmentAnnotation();
749     Vector toremove = new Vector();
750     while (en.hasMoreElements())
751     {
752       uk.ac.vamsas.objects.core.AlignmentAnnotation alan = (uk.ac.vamsas.objects.core.AlignmentAnnotation) en
753               .nextElement();
754       if (alan.getSeqrefsCount() > 0)
755       {
756         int p = 0;
757         Vector storem = new Vector();
758         Enumeration sr = alan.enumerateSeqrefs();
759         while (sr.hasMoreElements())
760         {
761           Object alsr = sr.nextElement();
762           if (docseqs.contains(alsr))
763           {
764             storem.addElement(alsr);
765           }
766         }
767         // remove references to the deleted sequences
768         sr = storem.elements();
769         while (sr.hasMoreElements())
770         {
771           alan.removeSeqrefs(sr.nextElement());
772         }
773
774         if (alan.getSeqrefsCount() == 0)
775         {
776           // should then delete alan from dataset
777           toremove.addElement(alan);
778         }
779       }
780     }
781     // remove any annotation that used to be associated to a specific bunch of
782     // sequences
783     en = toremove.elements();
784     while (en.hasMoreElements())
785     {
786       alignment
787               .removeAlignmentAnnotation((uk.ac.vamsas.objects.core.AlignmentAnnotation) en
788                       .nextElement());
789     }
790     // TODO: search through alignment annotations to remove any references to
791     // this alignment sequence
792   }
793
794   /**
795    * sync a jalview alignment seuqence into a vamsas alignment assumes all lock
796    * transformation/bindings have been sorted out before hand. creates/syncs the
797    * vamsas alignment sequence for jvalsq and adds it to the alignment if
798    * necessary. unbounddocseq is a duplicate of the vamsas alignment sequences
799    * and these are removed after being processed w.r.t a bound jvalsq
800    * 
801    */
802   private boolean syncToAlignmentSequence(SequenceI jvalsq,
803           Alignment alignment, Vector unbounddocseq)
804   {
805     boolean modal = false;
806     // todo: islocked method here
807     boolean up2doc = false;
808     AlignmentSequence alseq = (AlignmentSequence) getjv2vObj(jvalsq);
809     if (alseq == null)
810     {
811       alseq = new AlignmentSequence();
812       up2doc = true;
813     }
814     else
815     {
816       if (unbounddocseq != null)
817       {
818         unbounddocseq.removeElement(alseq);
819       }
820     }
821     // boolean locked = (alignment.getModifiable()==null ||
822     // alignment.getModifiable().length()>0);
823     // TODO: VAMSAS: translate lowercase symbols to annotation ?
824     if (up2doc || !alseq.getSequence().equals(jvalsq.getSequenceAsString()))
825     {
826       alseq.setSequence(jvalsq.getSequenceAsString());
827       alseq.setStart(jvalsq.getStart());
828       alseq.setEnd(jvalsq.getEnd());
829       modal = true;
830     }
831     if (up2doc || !alseq.getName().equals(jvalsq.getName()))
832     {
833       modal = true;
834       alseq.setName(jvalsq.getName());
835     }
836     if (jvalsq.getDescription() != null
837             && (alseq.getDescription() == null || !jvalsq.getDescription()
838                     .equals(alseq.getDescription())))
839     {
840       modal = true;
841       alseq.setDescription(jvalsq.getDescription());
842     }
843     if (getjv2vObj(jvalsq.getDatasetSequence()) == null)
844     {
845       Cache.log
846               .warn("Serious Implementation error - Unbound dataset sequence in alignment: "
847                       + jvalsq.getDatasetSequence());
848     }
849     alseq.setRefid(getjv2vObj(jvalsq.getDatasetSequence()));
850     if (up2doc)
851     {
852
853       alignment.addAlignmentSequence(alseq);
854       bindjvvobj(jvalsq, alseq);
855     }
856     return up2doc || modal;
857   }
858
859   /**
860    * locally sync a jalview alignment seuqence from a vamsas alignment assumes
861    * all lock transformation/bindings have been sorted out before hand.
862    * creates/syncs the jvalsq from the alignment sequence
863    */
864   private boolean syncFromAlignmentSequence(AlignmentSequence valseq,
865           char valGapchar, char gapChar, Vector dsseqs)
866
867   {
868     boolean modal = false;
869     // todo: islocked method here
870     boolean upFromdoc = false;
871     jalview.datamodel.SequenceI alseq = (SequenceI) getvObj2jv(valseq);
872     if (alseq == null)
873     {
874       upFromdoc = true;
875     }
876     if (alseq != null)
877     {
878
879       // boolean locked = (alignment.getModifiable()==null ||
880       // alignment.getModifiable().length()>0);
881       // TODO: VAMSAS: translate lowercase symbols to annotation ?
882       if (upFromdoc
883               || !valseq.getSequence().equals(alseq.getSequenceAsString()))
884       {
885         // this might go *horribly* wrong
886         alseq.setSequence(new String(valseq.getSequence()).replace(
887                 valGapchar, gapChar));
888         alseq.setStart((int) valseq.getStart());
889         alseq.setEnd((int) valseq.getEnd());
890         modal = true;
891       }
892       if (!valseq.getName().equals(alseq.getName()))
893       {
894         modal = true;
895         alseq.setName(valseq.getName());
896       }
897       if (alseq.getDescription() == null
898               || (valseq.getDescription() == null || alseq.getDescription()
899                       .equals(valseq.getDescription())))
900       {
901         alseq.setDescription(valseq.getDescription());
902         modal = true;
903       }
904       if (modal && Cache.log.isDebugEnabled())
905       {
906         Cache.log.debug("Updating apparently edited sequence "
907                 + alseq.getName());
908       }
909     }
910     else
911     {
912       alseq = new jalview.datamodel.Sequence(valseq.getName(), valseq
913               .getSequence().replace(valGapchar, gapChar), (int) valseq
914               .getStart(), (int) valseq.getEnd());
915
916       Vobject datsetseq = (Vobject) valseq.getRefid();
917       if (datsetseq != null)
918       {
919         alseq.setDatasetSequence((SequenceI) getvObj2jv(datsetseq)); // exceptions
920         // if
921         // AlignemntSequence
922         // reference
923         // isn't
924         // a
925         // simple
926         // SequenceI
927       }
928       else
929       {
930         Cache.log
931                 .error("Invalid dataset sequence id (null) for alignment sequence "
932                         + valseq.getVorbaId());
933       }
934       bindjvvobj(alseq, valseq);
935       alseq.setVamsasId(valseq.getVorbaId().getId());
936       dsseqs.add(alseq);
937     }
938     Vobject datsetseq = (Vobject) valseq.getRefid();
939     if (datsetseq != null)
940     {
941       if (datsetseq != alseq.getDatasetSequence())
942       {
943         modal = true;
944       }
945       alseq.setDatasetSequence((SequenceI) getvObj2jv(datsetseq)); // exceptions
946     }
947     return upFromdoc || modal;
948   }
949
950   private void initRangeAnnotationType(RangeAnnotation an,
951           AlignmentAnnotation alan, int[] gapMap)
952   {
953     Seg vSeg = new Seg();
954     vSeg.setStart(1);
955     vSeg.setInclusive(true);
956     vSeg.setEnd(gapMap.length);
957     an.addSeg(vSeg);
958
959     // LATER: much of this is verbatim from the alignmentAnnotation
960     // method below. suggests refactoring to make rangeAnnotation the
961     // base class
962     an.setDescription(alan.description);
963     an.setLabel(alan.label);
964     an.setGroup(Integer.toString(alan.graphGroup));
965     // // JBPNote -
966     // originally we
967     // were going to
968     // store
969     // graphGroup in
970     // the Jalview
971     // specific
972     // bits.
973     AnnotationElement ae;
974     for (int a = 0; a < alan.annotations.length; a++)
975     {
976       if (alan.annotations[a] == null)
977       {
978         continue;
979       }
980
981       ae = new AnnotationElement();
982       ae.setDescription(alan.annotations[a].description);
983       ae.addGlyph(new Glyph());
984       ae.getGlyph(0).setContent(alan.annotations[a].displayCharacter); // assume
985       // jax-b
986       // takes
987       // care
988       // of
989       // utf8
990       // translation
991       if (alan.graph != jalview.datamodel.AlignmentAnnotation.NO_GRAPH)
992       {
993         ae.addValue(alan.annotations[a].value);
994       }
995       ae.setPosition(gapMap[a] + 1); // position w.r.t. AlignmentSequence
996       // symbols
997       if (alan.annotations[a].secondaryStructure != ' ')
998       {
999         // we only write an annotation where it really exists.
1000         Glyph ss = new Glyph();
1001         ss
1002                 .setDict(uk.ac.vamsas.objects.utils.GlyphDictionary.PROTEIN_SS_3STATE);
1003         ss.setContent(String
1004                 .valueOf(alan.annotations[a].secondaryStructure));
1005         ae.addGlyph(ss);
1006       }
1007       an.addAnnotationElement(ae);
1008     }
1009
1010   }
1011
1012   private void saveDatasetSequenceAnnotation(HashMap AlSeqMaps,
1013           uk.ac.vamsas.objects.core.Sequence sref, AlignmentAnnotation alan)
1014   {
1015     // {
1016     // uk.ac.vamsas.
1017     // objects.core.AlignmentSequence alsref = (uk.ac.vamsas.
1018     // objects.core.AlignmentSequence) sref;
1019     uk.ac.vamsas.objects.core.DataSetAnnotations an = (uk.ac.vamsas.objects.core.DataSetAnnotations) getjv2vObj(alan);
1020     int[] gapMap = getGapMap(AlSeqMaps, alan);
1021     if (an == null)
1022     {
1023       an = new uk.ac.vamsas.objects.core.DataSetAnnotations();
1024       initRangeAnnotationType(an, alan, gapMap);
1025
1026       an.setProvenance(dummyProvenance()); // get provenance as user
1027       // created, or jnet, or
1028       // something else.
1029       setAnnotationType(an, alan);
1030       an.setGroup(Integer.toString(alan.graphGroup)); // // JBPNote -
1031       // originally we
1032       // were going to
1033       // store
1034       // graphGroup in
1035       // the Jalview
1036       // specific
1037       // bits.
1038       if (alan.getThreshold() != null && alan.getThreshold().displayed)
1039       {
1040         an.addProperty(newProperty(THRESHOLD, "float", ""
1041                 + alan.getThreshold().value));
1042         if (alan.getThreshold().label != null)
1043           an.addProperty(newProperty(THRESHOLD + "Name", "string", ""
1044                   + alan.getThreshold().label));
1045       }
1046       ((DataSet) sref.getV_parent()).addDataSetAnnotations(an);
1047       bindjvvobj(alan, an);
1048     }
1049     else
1050     {
1051       // update reference sequence Annotation
1052       if (an.getModifiable() == null) // TODO: USE VAMSAS LIBRARY OBJECT LOCK
1053       // METHODS)
1054       {
1055         // verify existing alignment sequence annotation is up to date
1056         System.out.println("update dataset sequence annotation.");
1057       }
1058       else
1059       {
1060         // verify existing alignment sequence annotation is up to date
1061         System.out
1062                 .println("make new alignment dataset sequence annotation if modification has happened.");
1063       }
1064     }
1065
1066   }
1067
1068   private int[] getGapMap(HashMap AlSeqMaps, AlignmentAnnotation alan)
1069   {
1070     int[] gapMap;
1071     if (AlSeqMaps.containsKey(alan.sequenceRef))
1072     {
1073       gapMap = (int[]) AlSeqMaps.get(alan.sequenceRef);
1074     }
1075     else
1076     {
1077       gapMap = new int[alan.sequenceRef.getLength()];
1078       // map from alignment position to sequence position.
1079       int[] sgapMap = alan.sequenceRef.gapMap();
1080       for (int a = 0; a < sgapMap.length; a++)
1081       {
1082         gapMap[sgapMap[a]] = a;
1083       }
1084     }
1085     return gapMap;
1086   }
1087
1088   private void saveAlignmentSequenceAnnotation(HashMap AlSeqMaps,
1089           AlignmentSequence alsref, AlignmentAnnotation alan)
1090   {
1091     // {
1092     // uk.ac.vamsas.
1093     // objects.core.AlignmentSequence alsref = (uk.ac.vamsas.
1094     // objects.core.AlignmentSequence) sref;
1095     uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation an = (uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation) getjv2vObj(alan);
1096     int[] gapMap = getGapMap(AlSeqMaps, alan);
1097     if (an == null)
1098     {
1099       an = new uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation();
1100       initRangeAnnotationType(an, alan, gapMap);
1101       /**
1102        * I mean here that we don't actually have a semantic 'type' for the
1103        * annotation (this might be - score, intrinsic property, measurement,
1104        * something extracted from another program, etc)
1105        */
1106       an.setType(JALVIEW_ANNOTATION_ROW); // TODO: better fix
1107       // this rough guess ;)
1108       alsref.addAlignmentSequenceAnnotation(an);
1109       bindjvvobj(alan, an);
1110       // These properties are directly supported by the
1111       // AlignmentSequenceAnnotation type.
1112       setAnnotationType(an, alan);
1113       an.setProvenance(dummyProvenance()); // get provenance as user
1114       // created, or jnet, or
1115       // something else.
1116     }
1117     else
1118     {
1119       // update reference sequence Annotation
1120       if (an.getModifiable() == null) // TODO: USE VAMSAS LIBRARY OBJECT LOCK
1121       // METHODS)
1122       {
1123         // verify existing alignment sequence annotation is up to date
1124         System.out.println("update alignment sequence annotation.");
1125       }
1126       else
1127       {
1128         // verify existing alignment sequence annotation is up to date
1129         System.out
1130                 .println("make new alignment sequence annotation if modification has happened.");
1131       }
1132     }
1133   }
1134
1135   /**
1136    * set vamsas annotation object type from jalview annotation
1137    * 
1138    * @param an
1139    * @param alan
1140    */
1141   private void setAnnotationType(RangeAnnotation an,
1142           AlignmentAnnotation alan)
1143   {
1144     if (an instanceof AlignmentSequenceAnnotation)
1145     {
1146       if (alan.graph != AlignmentAnnotation.NO_GRAPH)
1147       {
1148         ((AlignmentSequenceAnnotation) an).setGraph(true);
1149       }
1150       else
1151       {
1152         ((AlignmentSequenceAnnotation) an).setGraph(false);
1153       }
1154     }
1155     if (an instanceof uk.ac.vamsas.objects.core.AlignmentAnnotation)
1156     {
1157       if (alan.graph != AlignmentAnnotation.NO_GRAPH)
1158       {
1159         ((uk.ac.vamsas.objects.core.AlignmentAnnotation) an).setGraph(true);
1160       }
1161       else
1162       {
1163         ((uk.ac.vamsas.objects.core.AlignmentAnnotation) an)
1164                 .setGraph(false);
1165       }
1166     }
1167     switch (alan.graph)
1168     {
1169     case AlignmentAnnotation.BAR_GRAPH:
1170       an.addProperty(newProperty(DISCRETE_ANNOTATION, "boolean", "true"));
1171       break;
1172     case AlignmentAnnotation.LINE_GRAPH:
1173       an.addProperty(newProperty(CONTINUOUS_ANNOTATION, "boolean", "true"));
1174       break;
1175     default:
1176       // don't add any kind of discrete or continous property info.
1177     }
1178   }
1179
1180   private Property newProperty(String name, String type, String content)
1181   {
1182     Property vProperty = new Property();
1183     vProperty.setName(name);
1184     if (type != null)
1185     {
1186       vProperty.setType(type);
1187     }
1188     else
1189     {
1190       vProperty.setType("String");
1191     }
1192     vProperty.setContent(content);
1193     return vProperty;
1194   }
1195
1196   /**
1197    * correctly create a RangeAnnotation from a jalview sequence feature
1198    * 
1199    * @param dsa
1200    *                (typically DataSetAnnotations or
1201    *                AlignmentSequenceAnnotation)
1202    * @param feature
1203    *                (the feature to be mapped from)
1204    * @return
1205    */
1206   private RangeAnnotation getDSAnnotationFromJalview(RangeAnnotation dsa,
1207           SequenceFeature feature)
1208   {
1209     dsa.setType(feature.getType());
1210     Seg vSeg = new Seg();
1211     vSeg.setStart(feature.getBegin());
1212     vSeg.setEnd(feature.getEnd());
1213     vSeg.setInclusive(true);
1214     dsa.addSeg(vSeg);
1215     dsa.setDescription(feature.getDescription());
1216     dsa.setStatus(feature.getStatus());
1217     if (feature.links != null && feature.links.size() > 0)
1218     {
1219       for (int i = 0, iSize = feature.links.size(); i < iSize; i++)
1220       {
1221         String link = (String) feature.links.elementAt(i);
1222         int sep = link.indexOf('|');
1223         if (sep > -1)
1224         {
1225           Link vLink = new Link();
1226           if (sep > 0)
1227           {
1228             vLink.setContent(link.substring(0, sep - 1));
1229           }
1230           else
1231           {
1232             vLink.setContent("");
1233           }
1234           vLink.setHref(link.substring(sep + 1)); // TODO: validate href.
1235           dsa.addLink(vLink);
1236         }
1237       }
1238     }
1239     dsa.setGroup(feature.getFeatureGroup());
1240     return dsa;
1241   }
1242
1243   /**
1244    * get start<end range of segment, adjusting for inclusivity flag and
1245    * polarity.
1246    * 
1247    * @param visSeg
1248    * @param ensureDirection
1249    *                when true - always ensure start is less than end.
1250    * @return int[] { start, end, direction} where direction==1 for range running
1251    *         from end to start.
1252    */
1253   private int[] getSegRange(Seg visSeg, boolean ensureDirection)
1254   {
1255     boolean incl = visSeg.getInclusive();
1256     // adjust for inclusive flag.
1257     int pol = (visSeg.getStart() <= visSeg.getEnd()) ? 1 : -1; // polarity of
1258     // region.
1259     int start = visSeg.getStart() + (incl ? 0 : pol);
1260     int end = visSeg.getEnd() + (incl ? 0 : -pol);
1261     if (ensureDirection && pol == -1)
1262     {
1263       // jalview doesn't deal with inverted ranges, yet.
1264       int t = end;
1265       end = start;
1266       start = t;
1267     }
1268     return new int[]
1269     { start, end, pol < 0 ? 1 : 0 };
1270   }
1271
1272   /**
1273    * 
1274    * @param annotation
1275    * @return true if annotation is not to be stored in document
1276    */
1277   private boolean isJalviewOnly(AlignmentAnnotation annotation)
1278   {
1279     return annotation.label.equals("Quality")
1280             || annotation.label.equals("Conservation")
1281             || annotation.label.equals("Consensus");
1282   }
1283
1284   /**
1285    * This will return the first AlignFrame viewing AlignViewport av. It will
1286    * break if there are more than one AlignFrames viewing a particular av. This
1287    * also shouldn't be in the io package.
1288    * 
1289    * @param av
1290    * @return alignFrame for av
1291    */
1292   public AlignFrame getAlignFrameFor(AlignViewport av)
1293   {
1294     if (Desktop.desktop != null)
1295     {
1296       javax.swing.JInternalFrame[] frames = Desktop.instance.getAllFrames();
1297
1298       for (int t = 0; t < frames.length; t++)
1299       {
1300         if (frames[t] instanceof AlignFrame)
1301         {
1302           if (((AlignFrame) frames[t]).getViewport() == av)
1303           {
1304             return (AlignFrame) frames[t];
1305           }
1306         }
1307       }
1308     }
1309     return null;
1310   }
1311
1312   public void updateToJalview()
1313   {
1314     VAMSAS _roots[] = cdoc.getVamsasRoots();
1315
1316     for (int _root = 0; _root < _roots.length; _root++)
1317     {
1318       VAMSAS root = _roots[_root];
1319       boolean newds = false;
1320       for (int _ds = 0, _nds = root.getDataSetCount(); _ds < _nds; _ds++)
1321       {
1322         // ///////////////////////////////////
1323         // ///LOAD DATASET
1324         DataSet dataset = root.getDataSet(_ds);
1325         int i, iSize = dataset.getSequenceCount();
1326         Vector dsseqs;
1327         jalview.datamodel.Alignment jdataset = (jalview.datamodel.Alignment) getvObj2jv(dataset);
1328         int jremain = 0;
1329         if (jdataset == null)
1330         {
1331           Cache.log.debug("Initialising new jalview dataset fields");
1332           newds = true;
1333           dsseqs = new Vector();
1334         }
1335         else
1336         {
1337           Cache.log.debug("Update jalview dataset from vamsas.");
1338           jremain = jdataset.getHeight();
1339           dsseqs = jdataset.getSequences();
1340         }
1341
1342         // TODO: test sequence merging - we preserve existing non vamsas
1343         // sequences but add in any new vamsas ones, and don't yet update any
1344         // sequence attributes
1345         for (i = 0; i < iSize; i++)
1346         {
1347           Sequence vdseq = dataset.getSequence(i);
1348           jalview.datamodel.SequenceI dsseq = (SequenceI) getvObj2jv(vdseq);
1349           if (dsseq != null)
1350           {
1351             if (!dsseq.getSequenceAsString().equals(vdseq.getSequence()))
1352             {
1353               throw new Error(
1354                       "Broken! - mismatch of dataset sequence: and jalview internal dataset sequence.");
1355             }
1356             jremain--;
1357           }
1358           else
1359           {
1360             dsseq = new jalview.datamodel.Sequence(dataset.getSequence(i)
1361                     .getName(), dataset.getSequence(i).getSequence(),
1362                     (int) dataset.getSequence(i).getStart(), (int) dataset
1363                             .getSequence(i).getEnd());
1364             dsseq.setDescription(dataset.getSequence(i).getDescription());
1365             bindjvvobj(dsseq, dataset.getSequence(i));
1366             dsseq.setVamsasId(dataset.getSequence(i).getVorbaId().getId());
1367             dsseqs.add(dsseq);
1368           }
1369           if (vdseq.getDbRefCount() > 0)
1370           {
1371             DbRef[] dbref = vdseq.getDbRef();
1372             for (int db = 0; db < dbref.length; db++)
1373             {
1374               new jalview.io.vamsas.Dbref(this, dbref[db], vdseq, dsseq);
1375
1376             }
1377             dsseq.updatePDBIds();
1378           }
1379         }
1380
1381         if (newds)
1382         {
1383           SequenceI[] seqs = new SequenceI[dsseqs.size()];
1384           for (i = 0, iSize = dsseqs.size(); i < iSize; i++)
1385           {
1386             seqs[i] = (SequenceI) dsseqs.elementAt(i);
1387             dsseqs.setElementAt(null, i);
1388           }
1389           jdataset = new jalview.datamodel.Alignment(seqs);
1390           Cache.log.debug("New vamsas dataset imported into jalview.");
1391           bindjvvobj(jdataset, dataset);
1392         }
1393         // ////////
1394         // add any new dataset sequence feature annotations
1395         if (dataset.getDataSetAnnotations() != null)
1396         {
1397           for (int dsa = 0; dsa < dataset.getDataSetAnnotationsCount(); dsa++)
1398           {
1399             DataSetAnnotations dseta = dataset.getDataSetAnnotations(dsa);
1400             // TODO: deal with group annotation on datset sequences.
1401             if (dseta.getSeqRefCount() == 1)
1402             {
1403               SequenceI dsSeq = (SequenceI) getvObj2jv((Vobject) dseta
1404                       .getSeqRef(0)); // TODO: deal with group dataset
1405               // annotations
1406               if (dsSeq == null)
1407               {
1408                 jalview.bin.Cache.log
1409                         .warn("Couldn't resolve jalview sequenceI for dataset object reference "
1410                                 + ((Vobject) dataset.getDataSetAnnotations(
1411                                         dsa).getSeqRef(0)).getVorbaId()
1412                                         .getId());
1413               }
1414               else
1415               {
1416                 if (dseta.getAnnotationElementCount() == 0)
1417                 {
1418                   jalview.datamodel.SequenceFeature sf = (jalview.datamodel.SequenceFeature) getvObj2jv(dseta);
1419                   if (sf == null)
1420                   {
1421                     dsSeq
1422                             .addSequenceFeature(sf = getJalviewSeqFeature(dseta));
1423                     bindjvvobj(sf, dseta);
1424                   }
1425                 }
1426                 else
1427                 {
1428                   // TODO: deal with alignmentAnnotation style annotation
1429                   // appearing on dataset sequences.
1430                   // JBPNote: we could just add them to all alignments but
1431                   // that may complicate cross references in the jalview
1432                   // datamodel
1433                   Cache.log
1434                           .warn("Ignoring dataset annotation with annotationElements. Not yet supported in jalview.");
1435                 }
1436               }
1437             }
1438           }
1439         }
1440         if (dataset.getAlignmentCount() > 0)
1441         {
1442           // LOAD ALIGNMENTS from DATASET
1443
1444           for (int al = 0, nal = dataset.getAlignmentCount(); al < nal; al++)
1445           {
1446             uk.ac.vamsas.objects.core.Alignment alignment = dataset
1447                     .getAlignment(al);
1448             AlignViewport av = findViewport(alignment);
1449
1450             jalview.datamodel.AlignmentI jal = null;
1451             if (av != null)
1452             {
1453               jal = av.getAlignment();
1454             }
1455             iSize = alignment.getAlignmentSequenceCount();
1456             boolean newal = (jal == null) ? true : false;
1457             boolean refreshal = false;
1458             Vector newasAnnots = new Vector();
1459             char gapChar = ' '; // default for new alignments read in from the
1460             // document
1461             if (jal != null)
1462             {
1463               dsseqs = jal.getSequences(); // for merge/update
1464               gapChar = jal.getGapCharacter();
1465             }
1466             else
1467             {
1468               dsseqs = new Vector();
1469             }
1470             char valGapchar = alignment.getGapChar().charAt(0);
1471             for (i = 0; i < iSize; i++)
1472             {
1473               AlignmentSequence valseq = alignment.getAlignmentSequence(i);
1474               jalview.datamodel.Sequence alseq = (jalview.datamodel.Sequence) getvObj2jv(valseq);
1475               if (syncFromAlignmentSequence(valseq, valGapchar, gapChar,
1476                       dsseqs)
1477                       && alseq != null)
1478               {
1479
1480                 // updated to sequence from the document
1481                 jremain--;
1482                 refreshal = true;
1483               }
1484               if (valseq.getAlignmentSequenceAnnotationCount() > 0)
1485               {
1486                 AlignmentSequenceAnnotation[] vasannot = valseq
1487                         .getAlignmentSequenceAnnotation();
1488                 for (int a = 0; a < vasannot.length; a++)
1489                 {
1490                   jalview.datamodel.AlignmentAnnotation asa = (jalview.datamodel.AlignmentAnnotation) getvObj2jv(vasannot[a]); // TODO:
1491                   // 1:many
1492                   // jalview
1493                   // alignment
1494                   // sequence
1495                   // annotations
1496                   if (asa == null)
1497                   {
1498                     int se[] = getBounds(vasannot[a]);
1499                     asa = getjAlignmentAnnotation(jal, vasannot[a]);
1500                     asa.setSequenceRef(alseq);
1501                     asa.createSequenceMapping(alseq, se[0], false); // TODO:
1502                     // verify
1503                     // that
1504                     // positions
1505                     // in
1506                     // alseqAnnotation
1507                     // correspond
1508                     // to
1509                     // ungapped
1510                     // residue
1511                     // positions.
1512                     alseq.addAlignmentAnnotation(asa);
1513                     bindjvvobj(asa, vasannot[a]);
1514                     newasAnnots.add(asa);
1515                   }
1516                   else
1517                   {
1518                     // update existing annotation - can do this in place
1519                     if (vasannot[a].getModifiable() == null) // TODO: USE
1520                     // VAMSAS LIBRARY
1521                     // OBJECT LOCK
1522                     // METHODS)
1523                     {
1524                       Cache.log
1525                               .info("UNIMPLEMENTED: not recovering user modifiable sequence alignment annotation");
1526                       // TODO: should at least replace with new one - otherwise
1527                       // things will break
1528                       // basically do this:
1529                       // int se[] = getBounds(vasannot[a]);
1530                       // asa.update(getjAlignmentAnnotation(jal, vasannot[a]));
1531                       // // update from another annotation object in place.
1532                       // asa.createSequenceMapping(alseq, se[0], false);
1533
1534                     }
1535                   }
1536                 }
1537               }
1538             }
1539             if (jal == null)
1540             {
1541               SequenceI[] seqs = new SequenceI[dsseqs.size()];
1542               for (i = 0, iSize = dsseqs.size(); i < iSize; i++)
1543               {
1544                 seqs[i] = (SequenceI) dsseqs.elementAt(i);
1545                 dsseqs.setElementAt(null, i);
1546               }
1547               jal = new jalview.datamodel.Alignment(seqs);
1548               Cache.log.debug("New vamsas alignment imported into jalview "
1549                       + alignment.getVorbaId().getId());
1550               jal.setDataset(jdataset);
1551             }
1552             if (newasAnnots != null && newasAnnots.size() > 0)
1553             {
1554               // Add the new sequence annotations in to the alignment.
1555               for (int an = 0, anSize = newasAnnots.size(); an < anSize; an++)
1556               {
1557                 jal.addAnnotation((AlignmentAnnotation) newasAnnots
1558                         .elementAt(an));
1559                 // TODO: check if anything has to be done - like calling
1560                 // adjustForAlignment or something.
1561                 newasAnnots.setElementAt(null, an);
1562               }
1563               newasAnnots = null;
1564             }
1565             // //////////////////////////////////////////
1566             // //LOAD ANNOTATIONS FOR THE ALIGNMENT
1567             // ////////////////////////////////////
1568             if (alignment.getAlignmentAnnotationCount() > 0)
1569             {
1570               uk.ac.vamsas.objects.core.AlignmentAnnotation[] an = alignment
1571                       .getAlignmentAnnotation();
1572
1573               for (int j = 0; j < an.length; j++)
1574               {
1575                 jalview.datamodel.AlignmentAnnotation jan = (jalview.datamodel.AlignmentAnnotation) getvObj2jv(an[j]);
1576                 if (jan != null)
1577                 {
1578                   // update or stay the same.
1579                   // TODO: should at least replace with a new one - otherwise
1580                   // things will break
1581                   // basically do this:
1582                   // jan.update(getjAlignmentAnnotation(jal, an[a])); // update
1583                   // from another annotation object in place.
1584
1585                   Cache.log
1586                           .debug("update from vamsas alignment annotation to existing jalview alignment annotation.");
1587                   if (an[j].getModifiable() == null) // TODO: USE VAMSAS
1588                   // LIBRARY OBJECT LOCK
1589                   // METHODS)
1590                   {
1591                     // TODO: user defined annotation is totally mutable... - so
1592                     // load it up or throw away if locally edited.
1593                     Cache.log
1594                             .info("NOT IMPLEMENTED - Recovering user-modifiable annotation - yet...");
1595                   }
1596                   // TODO: compare annotation element rows
1597                   // TODO: compare props.
1598                 }
1599                 else
1600                 {
1601                   jan = getjAlignmentAnnotation(jal, an[j]);
1602                   jal.addAnnotation(jan);
1603                   bindjvvobj(jan, an[j]);
1604                 }
1605               }
1606             }
1607             AlignFrame alignFrame;
1608             if (av == null)
1609             {
1610               Cache.log.debug("New alignframe for alignment "
1611                       + alignment.getVorbaId());
1612               // ///////////////////////////////
1613               // construct alignment view
1614               alignFrame = new AlignFrame(jal, AlignFrame.DEFAULT_WIDTH,
1615                       AlignFrame.DEFAULT_HEIGHT);
1616               av = alignFrame.getViewport();
1617               String title = alignment.getProvenance().getEntry(
1618                       alignment.getProvenance().getEntryCount() - 1)
1619                       .getAction();
1620               if (alignment.getPropertyCount() > 0)
1621               {
1622                 for (int p = 0, pe = alignment.getPropertyCount(); p < pe; p++)
1623                 {
1624                   if (alignment.getProperty(p).getName().equals("title"))
1625                   {
1626                     title = alignment.getProperty(p).getContent();
1627                   }
1628                 }
1629               }
1630               // TODO: automatically create meaningful title for a vamsas
1631               // alignment using its provenance.
1632               if (Cache.log.isDebugEnabled())
1633               {
1634                 title = title + "(" + alignment.getVorbaId() + ")";
1635
1636               }
1637               jalview.gui.Desktop.addInternalFrame(alignFrame, title,
1638                       AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
1639               bindjvvobj(av.getSequenceSetId(), alignment);
1640             }
1641             else
1642             {
1643               // find the alignFrame for jal.
1644               // TODO: fix this so we retrieve the alignFrame handing av
1645               // *directly*
1646               alignFrame = getAlignFrameFor(av);
1647               if (refreshal)
1648               {
1649                 av.alignmentChanged(alignFrame.alignPanel);
1650               }
1651             }
1652             // LOAD TREES
1653             // /////////////////////////////////////
1654             if (alignment.getTreeCount() > 0)
1655             {
1656
1657               for (int t = 0; t < alignment.getTreeCount(); t++)
1658               {
1659                 jalview.io.vamsas.Tree vstree = new jalview.io.vamsas.Tree(
1660                         this, alignFrame, alignment.getTree(t));
1661                 TreePanel tp = null;
1662                 if (vstree.isValidTree())
1663                 {
1664                   tp = alignFrame.ShowNewickTree(vstree.getNewickTree(),
1665                           vstree.getTitle(), vstree.getInputData(), 600,
1666                           500, t * 20 + 50, t * 20 + 50);
1667
1668                 }
1669                 if (tp != null)
1670                 {
1671                   bindjvvobj(tp, alignment.getTree(t));
1672                   try
1673                   {
1674                     vstree.UpdateSequenceTreeMap(tp);
1675                   } catch (RuntimeException e)
1676                   {
1677                     Cache.log.warn("update of labels failed.", e);
1678                   }
1679                 }
1680                 else
1681                 {
1682                   Cache.log.warn("Cannot create tree for tree " + t
1683                           + " in document ("
1684                           + alignment.getTree(t).getVorbaId());
1685                 }
1686
1687               }
1688             }
1689           }
1690         }
1691       }
1692       // we do sequenceMappings last because they span all datasets in a vamsas
1693       // root
1694       for (int _ds = 0, _nds = root.getDataSetCount(); _ds < _nds; _ds++)
1695       {
1696         DataSet dataset = root.getDataSet(_ds);
1697         if (dataset.getSequenceMappingCount() > 0)
1698         {
1699           for (int sm = 0, smCount = dataset.getSequenceMappingCount(); sm < smCount; sm++)
1700           {
1701             Rangetype seqmap = new jalview.io.vamsas.Sequencemapping(this,
1702                     dataset.getSequenceMapping(sm));
1703           }
1704         }
1705       }
1706     }
1707   }
1708
1709   public AlignViewport findViewport(Alignment alignment)
1710   {
1711     AlignViewport av = null;
1712     AlignViewport[] avs = findViewportForSequenceSetId((String) getvObj2jv(alignment));
1713     if (avs != null)
1714     {
1715       av = avs[0];
1716     }
1717     return av;
1718   }
1719
1720   private AlignViewport[] findViewportForSequenceSetId(String sequenceSetId)
1721   {
1722     Vector viewp = new Vector();
1723     if (Desktop.desktop != null)
1724     {
1725       javax.swing.JInternalFrame[] frames = Desktop.instance.getAllFrames();
1726
1727       for (int t = 0; t < frames.length; t++)
1728       {
1729         if (frames[t] instanceof AlignFrame)
1730         {
1731           if (((AlignFrame) frames[t]).getViewport().getSequenceSetId()
1732                   .equals(sequenceSetId))
1733           {
1734             viewp.addElement(((AlignFrame) frames[t]).getViewport());
1735           }
1736         }
1737       }
1738       if (viewp.size() > 0)
1739       {
1740         AlignViewport[] vp = new AlignViewport[viewp.size()];
1741         viewp.copyInto(vp);
1742         return vp;
1743       }
1744     }
1745     return null;
1746   }
1747
1748   // bitfields - should be a template in j1.5
1749   private static int HASSECSTR = 0;
1750
1751   private static int HASVALS = 1;
1752
1753   private static int HASHPHOB = 2;
1754
1755   private static int HASDC = 3;
1756
1757   private static int HASDESCSTR = 4;
1758
1759   private static int HASTWOSTATE = 5; // not used yet.
1760
1761   /**
1762    * parses the AnnotationElements - if they exist - into
1763    * jalview.datamodel.Annotation[] rows Two annotation rows are made if there
1764    * are distinct annotation for both at 'pos' and 'after pos' at any particular
1765    * site.
1766    * 
1767    * @param annotation
1768    * @return { boolean[static int constants ], int[ae.length] - map to annotated
1769    *         object frame, jalview.datamodel.Annotation[],
1770    *         jalview.datamodel.Annotation[] (after)}
1771    */
1772   private Object[] parseRangeAnnotation(
1773           uk.ac.vamsas.objects.core.RangeAnnotation annotation)
1774   {
1775     // set these attributes by looking in the annotation to decide what kind of
1776     // alignment annotation rows will be made
1777     // TODO: potentially we might make several annotation rows from one vamsas
1778     // alignment annotation. the jv2Vobj binding mechanism
1779     // may not quite cope with this (without binding an array of annotations to
1780     // a vamsas alignment annotation)
1781     // summary flags saying what we found over the set of annotation rows.
1782     boolean[] AeContent = new boolean[]
1783     { false, false, false, false, false };
1784     int[] rangeMap = getMapping(annotation);
1785     jalview.datamodel.Annotation[][] anot = new jalview.datamodel.Annotation[][]
1786     { new jalview.datamodel.Annotation[rangeMap.length],
1787         new jalview.datamodel.Annotation[rangeMap.length] };
1788     boolean mergeable = true; // false if 'after positions cant be placed on
1789     // same annotation row as positions.
1790
1791     if (annotation.getAnnotationElementCount() > 0)
1792     {
1793       AnnotationElement ae[] = annotation.getAnnotationElement();
1794       for (int aa = 0; aa < ae.length; aa++)
1795       {
1796         int pos = (int) ae[aa].getPosition() - 1; // pos counts from 1 to
1797         // (|seg.start-seg.end|+1)
1798         if (pos >= 0 && pos < rangeMap.length)
1799         {
1800           int row = ae[aa].getAfter() ? 1 : 0;
1801           if (anot[row][pos] != null)
1802           {
1803             // only time this should happen is if the After flag is set.
1804             Cache.log.debug("Ignoring duplicate annotation site at " + pos);
1805             continue;
1806           }
1807           if (anot[1 - row][pos] != null)
1808           {
1809             mergeable = false;
1810           }
1811           String desc = "";
1812           if (ae[aa].getDescription() != null)
1813           {
1814             desc = ae[aa].getDescription();
1815             if (desc.length() > 0)
1816             {
1817               // have imported valid description string
1818               AeContent[HASDESCSTR] = true;
1819             }
1820           }
1821           String dc = null; // ae[aa].getDisplayCharacter()==null ? "dc" :
1822           // ae[aa].getDisplayCharacter();
1823           String ss = null; // ae[aa].getSecondaryStructure()==null ? "ss" :
1824           // ae[aa].getSecondaryStructure();
1825           java.awt.Color colour = null;
1826           if (ae[aa].getGlyphCount() > 0)
1827           {
1828             Glyph[] glyphs = ae[aa].getGlyph();
1829             for (int g = 0; g < glyphs.length; g++)
1830             {
1831               if (glyphs[g]
1832                       .getDict()
1833                       .equals(
1834                               uk.ac.vamsas.objects.utils.GlyphDictionary.PROTEIN_SS_3STATE))
1835               {
1836                 ss = glyphs[g].getContent();
1837                 AeContent[HASSECSTR] = true;
1838               }
1839               else if (glyphs[g]
1840                       .getDict()
1841                       .equals(
1842                               uk.ac.vamsas.objects.utils.GlyphDictionary.PROTEIN_HD_HYDRO))
1843               {
1844                 Cache.log.debug("ignoring hydrophobicity glyph marker.");
1845                 AeContent[HASHPHOB] = true;
1846                 char c = (dc = glyphs[g].getContent()).charAt(0);
1847                 // dc may get overwritten - but we still set the colour.
1848                 colour = new java.awt.Color(c == '+' ? 255 : 0,
1849                         c == '.' ? 255 : 0, c == '-' ? 255 : 0);
1850
1851               }
1852               else if (glyphs[g].getDict().equals(
1853                       uk.ac.vamsas.objects.utils.GlyphDictionary.DEFAULT))
1854               {
1855                 dc = glyphs[g].getContent();
1856                 AeContent[HASDC] = true;
1857               }
1858               else
1859               {
1860                 Cache.log
1861                         .debug("IMPLEMENTATION TODO: Ignoring unknown glyph type "
1862                                 + glyphs[g].getDict());
1863               }
1864             }
1865           }
1866           float val = 0;
1867           if (ae[aa].getValueCount() > 0)
1868           {
1869             AeContent[HASVALS] = true;
1870             if (ae[aa].getValueCount() > 1)
1871             {
1872               Cache.log.warn("ignoring additional "
1873                       + (ae[aa].getValueCount() - 1)
1874                       + "values in annotation element.");
1875             }
1876             val = ae[aa].getValue(0);
1877           }
1878           if (colour == null)
1879           {
1880             anot[row][pos] = new jalview.datamodel.Annotation(
1881                     (dc != null) ? dc : "", desc, (ss != null) ? ss
1882                             .charAt(0) : ' ', val);
1883           }
1884           else
1885           {
1886             anot[row][pos] = new jalview.datamodel.Annotation(
1887                     (dc != null) ? dc : "", desc, (ss != null) ? ss
1888                             .charAt(0) : ' ', val, colour);
1889           }
1890         }
1891         else
1892         {
1893           Cache.log.warn("Ignoring out of bound annotation element " + aa
1894                   + " in " + annotation.getVorbaId().getId());
1895         }
1896       }
1897       // decide on how many annotation rows are needed.
1898       if (mergeable)
1899       {
1900         for (int i = 0; i < anot[0].length; i++)
1901         {
1902           if (anot[1][i] != null)
1903           {
1904             anot[0][i] = anot[1][i];
1905             anot[0][i].description = anot[0][i].description + " (after)";
1906             AeContent[HASDESCSTR] = true; // we have valid description string
1907             // data
1908             anot[1][i] = null;
1909           }
1910         }
1911         anot[1] = null;
1912       }
1913       else
1914       {
1915         for (int i = 0; i < anot[0].length; i++)
1916         {
1917           anot[1][i].description = anot[1][i].description + " (after)";
1918         }
1919       }
1920       return new Object[]
1921       { AeContent, rangeMap, anot[0], anot[1] };
1922     }
1923     else
1924     {
1925       // no annotations to parse. Just return an empty annotationElement[]
1926       // array.
1927       return new Object[]
1928       { AeContent, rangeMap, anot[0], anot[1] };
1929     }
1930     // return null;
1931   }
1932
1933   /**
1934    * @param jal
1935    *                the jalview alignment to which the annotation will be
1936    *                attached (ideally - freshly updated from corresponding
1937    *                vamsas alignment)
1938    * @param annotation
1939    * @return unbound jalview alignment annotation object.
1940    */
1941   private jalview.datamodel.AlignmentAnnotation getjAlignmentAnnotation(
1942           jalview.datamodel.AlignmentI jal,
1943           uk.ac.vamsas.objects.core.RangeAnnotation annotation)
1944   {
1945     if (annotation == null)
1946     {
1947       return null;
1948     }
1949     // boolean
1950     // hasSequenceRef=annotation.getClass().equals(uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation.class);
1951     // boolean hasProvenance=hasSequenceRef ||
1952     // (annotation.getClass().equals(uk.ac.vamsas.objects.core.AlignmentAnnotation.class));
1953     /*
1954      * int se[] = getBounds(annotation); if (se==null) se=new int[]
1955      * {0,jal.getWidth()-1};
1956      */
1957     Object[] parsedRangeAnnotation = parseRangeAnnotation(annotation);
1958     String a_label = annotation.getLabel();
1959     String a_descr = annotation.getDescription();
1960     GraphLine gl = null;
1961     int type = 0;
1962     boolean interp = true; // cleared if annotation is DISCRETE
1963     // set type and other attributes from properties
1964     if (annotation.getPropertyCount() > 0)
1965     {
1966       // look for special jalview properties
1967       uk.ac.vamsas.objects.core.Property[] props = annotation.getProperty();
1968       for (int p = 0; p < props.length; p++)
1969       {
1970         if (props[p].getName().equalsIgnoreCase(DISCRETE_ANNOTATION))
1971         {
1972           type = AlignmentAnnotation.BAR_GRAPH;
1973           interp = false;
1974         }
1975         else if (props[p].getName().equalsIgnoreCase(CONTINUOUS_ANNOTATION))
1976         {
1977           type = AlignmentAnnotation.LINE_GRAPH;
1978         }
1979         else if (props[p].getName().equalsIgnoreCase(THRESHOLD))
1980         {
1981           Float val = null;
1982           try
1983           {
1984             val = new Float(props[p].getContent());
1985           } catch (Exception e)
1986           {
1987             Cache.log.warn("Failed to parse threshold property");
1988           }
1989           if (val != null)
1990             if (gl == null)
1991             {
1992               gl = new GraphLine(val.floatValue(), "", java.awt.Color.black);
1993             }
1994             else
1995             {
1996               gl.value = val.floatValue();
1997             }
1998         }
1999         else if (props[p].getName().equalsIgnoreCase(THRESHOLD + "Name"))
2000         {
2001           if (gl == null)
2002             gl = new GraphLine(0, "", java.awt.Color.black);
2003           gl.label = props[p].getContent();
2004         }
2005       }
2006     }
2007     jalview.datamodel.AlignmentAnnotation jan = null;
2008     if (a_label == null || a_label.length() == 0)
2009     {
2010       a_label = annotation.getType();
2011       if (a_label.length() == 0)
2012       {
2013         a_label = "Unamed annotation";
2014       }
2015     }
2016     if (a_descr == null || a_descr.length() == 0)
2017     {
2018       a_descr = "Annotation of type '" + annotation.getType() + "'";
2019     }
2020     if (parsedRangeAnnotation == null)
2021     {
2022       Cache.log
2023               .debug("Inserting empty annotation row elements for a whole-alignment annotation.");
2024     }
2025     else
2026     {
2027       if (parsedRangeAnnotation[3] != null)
2028       {
2029         Cache.log.warn("Ignoring 'After' annotation row in "
2030                 + annotation.getVorbaId());
2031       }
2032       jalview.datamodel.Annotation[] arow = (jalview.datamodel.Annotation[]) parsedRangeAnnotation[2];
2033       boolean[] has = (boolean[]) parsedRangeAnnotation[0];
2034       // VAMSAS: getGraph is only on derived annotation for alignments - in this
2035       // way its 'odd' - there is already an existing TODO about removing this
2036       // flag as being redundant
2037       /*
2038        * if
2039        * ((annotation.getClass().equals(uk.ac.vamsas.objects.core.AlignmentAnnotation.class) &&
2040        * ((uk.ac.vamsas.objects.core.AlignmentAnnotation)annotation).getGraph()) ||
2041        * (hasSequenceRef=true &&
2042        * ((uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation)annotation).getGraph())) {
2043        */
2044       if (has[HASVALS])
2045       {
2046         if (type == 0)
2047         {
2048           type = jalview.datamodel.AlignmentAnnotation.BAR_GRAPH; // default
2049           // type of
2050           // value
2051           // annotation
2052           if (has[HASHPHOB])
2053           {
2054             // no hints - so we ensure HPHOB display is like this.
2055             type = jalview.datamodel.AlignmentAnnotation.BAR_GRAPH;
2056           }
2057         }
2058         // make bounds and automatic description strings for jalview user's
2059         // benefit (these shouldn't be written back to vamsas document)
2060         boolean first = true;
2061         float min = 0, max = 1;
2062         int lastval = 0;
2063         for (int i = 0; i < arow.length; i++)
2064         {
2065           if (arow[i] != null)
2066           {
2067             if (i - lastval > 1 && interp)
2068             {
2069               // do some interpolation *between* points
2070               if (arow[lastval] != null)
2071               {
2072                 float interval = arow[i].value - arow[lastval].value;
2073                 interval /= i - lastval;
2074                 float base = arow[lastval].value;
2075                 for (int ip = lastval + 1, np = 0; ip < i; np++, ip++)
2076                 {
2077                   arow[ip] = new jalview.datamodel.Annotation("", "", ' ',
2078                           interval * np + base);
2079                   // NB - Interpolated points don't get a tooltip and
2080                   // description.
2081                 }
2082               }
2083             }
2084             lastval = i;
2085             // check range - shouldn't we have a min and max property in the
2086             // annotation object ?
2087             if (first)
2088             {
2089               min = max = arow[i].value;
2090               first = false;
2091             }
2092             else
2093             {
2094               if (arow[i].value < min)
2095               {
2096                 min = arow[i].value;
2097               }
2098               else if (arow[i].value > max)
2099               {
2100                 max = arow[i].value;
2101               }
2102             }
2103             // make tooltip and display char value
2104             if (!has[HASDESCSTR])
2105             {
2106               arow[i].description = arow[i].value + "";
2107             }
2108             if (!has[HASDC])
2109             {
2110               if (!interp)
2111               {
2112                 if (arow[i].description != null
2113                         && arow[i].description.length() < 3)
2114                 {
2115                   // copy over the description as the display char.
2116                   arow[i].displayCharacter = new String(arow[i].description);
2117                 }
2118               }
2119               else
2120               {
2121                 // mark the position as a point used for the interpolation.
2122                 arow[i].displayCharacter = arow[i].value + "";
2123               }
2124             }
2125           }
2126         }
2127         jan = new jalview.datamodel.AlignmentAnnotation(a_label, a_descr,
2128                 arow, min, max, type);
2129       }
2130       else
2131       {
2132         if (annotation.getAnnotationElementCount() == 0)
2133         {
2134           // empty annotation array
2135           // TODO: alignment 'features' compare rangeType spec to alignment
2136           // width - if it is not complete, then mark regions on the annotation
2137           // row.
2138         }
2139         jan = new jalview.datamodel.AlignmentAnnotation(a_label, a_descr,
2140                 arow);
2141         jan.setThreshold(null);
2142       }
2143       if (annotation.getLinkCount() > 0)
2144       {
2145         Cache.log.warn("Ignoring " + annotation.getLinkCount()
2146                 + "links added to AlignmentAnnotation.");
2147       }
2148       if (annotation.getModifiable() == null
2149               || annotation.getModifiable().length() == 0) // TODO: USE VAMSAS
2150       // LIBRARY OBJECT
2151       // LOCK METHODS)
2152       {
2153         jan.editable = true;
2154       }
2155       try
2156       {
2157         if (annotation.getGroup() != null
2158                 && annotation.getGroup().length() > 0)
2159         {
2160           jan.graphGroup = Integer.parseInt(annotation.getGroup()); // TODO:
2161           // group
2162           // similarly
2163           // named
2164           // annotation
2165           // together
2166           // ?
2167         }
2168       } catch (Exception e)
2169       {
2170         Cache.log
2171                 .info("UNIMPLEMENTED : Couldn't parse non-integer group value for setting graphGroup correctly.");
2172       }
2173       return jan;
2174
2175     }
2176
2177     return null;
2178   }
2179
2180   private SequenceFeature getJalviewSeqFeature(RangeAnnotation dseta)
2181   {
2182     int[] se = getBounds(dseta);
2183     SequenceFeature sf = new jalview.datamodel.SequenceFeature(dseta
2184             .getType(), dseta.getDescription(), dseta.getStatus(), se[0],
2185             se[1], dseta.getGroup());
2186     if (dseta.getLinkCount() > 0)
2187     {
2188       Link[] links = dseta.getLink();
2189       for (int i = 0; i < links.length; i++)
2190       {
2191         sf.addLink(links[i].getContent() + "|" + links[i].getHref());
2192       }
2193     }
2194     return sf;
2195   }
2196
2197   /**
2198    * get real bounds of a RangeType's specification. start and end are an
2199    * inclusive range within which all segments and positions lie. TODO: refactor
2200    * to vamsas utils
2201    * 
2202    * @param dseta
2203    * @return int[] { start, end}
2204    */
2205   private int[] getBounds(RangeType dseta)
2206   {
2207     if (dseta != null)
2208     {
2209       int[] se = null;
2210       if (dseta.getSegCount() > 0 && dseta.getPosCount() > 0)
2211       {
2212         throw new Error(
2213                 "Invalid vamsas RangeType - cannot resolve both lists of Pos and Seg from choice!");
2214       }
2215       if (dseta.getSegCount() > 0)
2216       {
2217         se = getSegRange(dseta.getSeg(0), true);
2218         for (int s = 1, sSize = dseta.getSegCount(); s < sSize; s++)
2219         {
2220           int nse[] = getSegRange(dseta.getSeg(s), true);
2221           if (se[0] > nse[0])
2222           {
2223             se[0] = nse[0];
2224           }
2225           if (se[1] < nse[1])
2226           {
2227             se[1] = nse[1];
2228           }
2229         }
2230       }
2231       if (dseta.getPosCount() > 0)
2232       {
2233         // could do a polarity for pos range too. and pass back indication of
2234         // discontinuities.
2235         int pos = dseta.getPos(0).getI();
2236         se = new int[]
2237         { pos, pos };
2238         for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++)
2239         {
2240           pos = dseta.getPos(p).getI();
2241           if (se[0] > pos)
2242           {
2243             se[0] = pos;
2244           }
2245           if (se[1] < pos)
2246           {
2247             se[1] = pos;
2248           }
2249         }
2250       }
2251       return se;
2252     }
2253     return null;
2254   }
2255
2256   /**
2257    * map from a rangeType's internal frame to the referenced object's coordinate
2258    * frame.
2259    * 
2260    * @param dseta
2261    * @return int [] { ref(pos)...} for all pos in rangeType's frame.
2262    */
2263   private int[] getMapping(RangeType dseta)
2264   {
2265     Vector posList = new Vector();
2266     if (dseta != null)
2267     {
2268       int[] se = null;
2269       if (dseta.getSegCount() > 0 && dseta.getPosCount() > 0)
2270       {
2271         throw new Error(
2272                 "Invalid vamsas RangeType - cannot resolve both lists of Pos and Seg from choice!");
2273       }
2274       if (dseta.getSegCount() > 0)
2275       {
2276         for (int s = 0, sSize = dseta.getSegCount(); s < sSize; s++)
2277         {
2278           se = getSegRange(dseta.getSeg(s), false);
2279           int se_end = se[1 - se[2]] + (se[2] == 0 ? 1 : -1);
2280           for (int p = se[se[2]]; p != se_end; p += se[2] == 0 ? 1 : -1)
2281           {
2282             posList.add(new Integer(p));
2283           }
2284         }
2285       }
2286       else if (dseta.getPosCount() > 0)
2287       {
2288         int pos = dseta.getPos(0).getI();
2289
2290         for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++)
2291         {
2292           pos = dseta.getPos(p).getI();
2293           posList.add(new Integer(pos));
2294         }
2295       }
2296     }
2297     if (posList != null && posList.size() > 0)
2298     {
2299       int[] range = new int[posList.size()];
2300       for (int i = 0; i < range.length; i++)
2301       {
2302         range[i] = ((Integer) posList.elementAt(i)).intValue();
2303       }
2304       posList.clear();
2305       return range;
2306     }
2307     return null;
2308   }
2309
2310   /**
2311    * 
2312    * @param maprange
2313    *                where the from range is the local mapped range, and the to
2314    *                range is the 'mapped' range in the MapRangeType
2315    * @param default
2316    *                unit for local
2317    * @param default
2318    *                unit for mapped
2319    * @return MapList
2320    */
2321   private jalview.util.MapList parsemapType(MapType maprange, int localu,
2322           int mappedu)
2323   {
2324     jalview.util.MapList ml = null;
2325     int[] localRange = getMapping(maprange.getLocal());
2326     int[] mappedRange = getMapping(maprange.getMapped());
2327     long lu = maprange.getLocal().hasUnit() ? maprange.getLocal().getUnit()
2328             : localu;
2329     long mu = maprange.getMapped().hasUnit() ? maprange.getMapped()
2330             .getUnit() : mappedu;
2331     ml = new jalview.util.MapList(localRange, mappedRange, (int) lu,
2332             (int) mu);
2333     return ml;
2334   }
2335
2336   /**
2337    * initialise a range type object from a set of start/end inclusive intervals
2338    * 
2339    * @param mrt
2340    * @param range
2341    */
2342   private void initRangeType(RangeType mrt, int[] range)
2343   {
2344     for (int i = 0; i < range.length; i += 2)
2345     {
2346       Seg vSeg = new Seg();
2347       vSeg.setStart(range[i]);
2348       vSeg.setEnd(range[i + 1]);
2349       mrt.addSeg(vSeg);
2350     }
2351   }
2352
2353   /**
2354    * initialise a MapType object from a MapList object.
2355    * 
2356    * @param maprange
2357    * @param ml
2358    * @param setUnits
2359    */
2360   private void initMapType(MapType maprange, jalview.util.MapList ml,
2361           boolean setUnits)
2362   {
2363     maprange.setLocal(new Local());
2364     maprange.setMapped(new Mapped());
2365     initRangeType(maprange.getLocal(), ml.getFromRanges());
2366     initRangeType(maprange.getMapped(), ml.getToRanges());
2367     if (setUnits)
2368     {
2369       maprange.getLocal().setUnit(ml.getFromRatio());
2370       maprange.getLocal().setUnit(ml.getToRatio());
2371     }
2372   }
2373
2374   /*
2375    * not needed now. Provenance getVamsasProvenance(jalview.datamodel.Provenance
2376    * jprov) { jalview.datamodel.ProvenanceEntry[] entries = null; // TODO: fix
2377    * App and Action here. Provenance prov = new Provenance();
2378    * org.exolab.castor.types.Date date = new org.exolab.castor.types.Date( new
2379    * java.util.Date()); Entry provEntry;
2380    * 
2381    * if (jprov != null) { entries = jprov.getEntries(); for (int i = 0; i <
2382    * entries.length; i++) { provEntry = new Entry(); try { date = new
2383    * org.exolab.castor.types.Date(entries[i].getDate()); } catch (Exception ex) {
2384    * ex.printStackTrace();
2385    * 
2386    * date = new org.exolab.castor.types.Date(entries[i].getDate()); }
2387    * provEntry.setDate(date); provEntry.setUser(entries[i].getUser());
2388    * provEntry.setAction(entries[i].getAction()); prov.addEntry(provEntry); } }
2389    * else { provEntry = new Entry(); provEntry.setDate(date);
2390    * provEntry.setUser(System.getProperty("user.name")); // TODO: ext string
2391    * provEntry.setApp("JVAPP"); // TODO: ext string provEntry.setAction(action);
2392    * prov.addEntry(provEntry); }
2393    * 
2394    * return prov; }
2395    */
2396   jalview.datamodel.Provenance getJalviewProvenance(Provenance prov)
2397   {
2398     // TODO: fix App and Action entries and check use of provenance in jalview.
2399     jalview.datamodel.Provenance jprov = new jalview.datamodel.Provenance();
2400     for (int i = 0; i < prov.getEntryCount(); i++)
2401     {
2402       jprov.addEntry(prov.getEntry(i).getUser(), prov.getEntry(i)
2403               .getAction(), prov.getEntry(i).getDate(), prov.getEntry(i)
2404               .getId());
2405     }
2406
2407     return jprov;
2408   }
2409
2410   /**
2411    * 
2412    * @return default initial provenance list for a Jalview created vamsas
2413    *         object.
2414    */
2415   Provenance dummyProvenance()
2416   {
2417     return dummyProvenance(null);
2418   }
2419
2420   Entry dummyPEntry(String action)
2421   {
2422     Entry entry = new Entry();
2423     entry.setApp(this.provEntry.getApp());
2424     if (action != null)
2425     {
2426       entry.setAction(action);
2427     }
2428     else
2429     {
2430       entry.setAction("created.");
2431     }
2432     entry.setDate(new java.util.Date());
2433     entry.setUser(this.provEntry.getUser());
2434     return entry;
2435   }
2436
2437   Provenance dummyProvenance(String action)
2438   {
2439     Provenance prov = new Provenance();
2440     prov.addEntry(dummyPEntry(action));
2441     return prov;
2442   }
2443
2444   Entry addProvenance(Provenance p, String action)
2445   {
2446     Entry dentry = dummyPEntry(action);
2447     p.addEntry(dentry);
2448     return dentry;
2449   }
2450
2451   public Entry getProvEntry()
2452   {
2453     return provEntry;
2454   }
2455
2456   public IClientDocument getClientDocument()
2457   {
2458     return cdoc;
2459   }
2460
2461   public IdentityHashMap getJvObjectBinding()
2462   {
2463     return jv2vobj;
2464   }
2465
2466   public Hashtable getVamsasObjectBinding()
2467   {
2468     return vobj2jv;
2469   }
2470
2471   public void storeSequenceMappings(AlignViewport viewport, String title)
2472           throws Exception
2473   {
2474     AlignViewport av = viewport;
2475     try
2476     {
2477       jalview.datamodel.AlignmentI jal = av.getAlignment();
2478       // /////////////////////////////////////////
2479       // SAVE THE DATASET
2480       DataSet dataset = null;
2481       if (jal.getDataset() == null)
2482       {
2483         Cache.log.warn("Creating new dataset for an alignment.");
2484         jal.setDataset(null);
2485       }
2486       dataset = (DataSet) getjv2vObj(jal.getDataset());
2487       // Store any sequence mappings.
2488       if (av.getAlignment().getCodonFrames() != null
2489               && av.getAlignment().getCodonFrames().length > 0)
2490       {
2491         jalview.datamodel.AlignedCodonFrame[] cframes = av.getAlignment()
2492                 .getCodonFrames();
2493         for (int cf = 0; cf < cframes.length; cf++)
2494         {
2495           if (cframes[cf].getdnaSeqs().length > 0)
2496           {
2497             jalview.datamodel.SequenceI[] dmps = cframes[cf].getdnaSeqs();
2498             jalview.datamodel.Mapping[] mps = cframes[cf].getProtMappings();
2499             for (int smp = 0; smp < mps.length; smp++)
2500             {
2501               uk.ac.vamsas.objects.core.SequenceType mfrom = (SequenceType) getjv2vObj(dmps[smp]);
2502               if (mfrom != null)
2503               {
2504                 new jalview.io.vamsas.Sequencemapping(this, mps[smp],
2505                         mfrom, dataset);
2506               }
2507               else
2508               {
2509                 Cache.log
2510                         .warn("NO Vamsas Binding for local sequence! NOT CREATING MAPPING FOR "
2511                                 + dmps[smp].getDisplayId(true)
2512                                 + " to "
2513                                 + mps[smp].getTo().getName());
2514               }
2515             }
2516           }
2517         }
2518       }
2519     } catch (Exception e)
2520     {
2521       throw new Exception("Couldn't store sequence mappings for " + title,
2522               e);
2523     }
2524   }
2525 }