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