modifiable lock check
[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           }
1228         }
1229
1230         if (newds)
1231         {
1232           SequenceI[] seqs = new SequenceI[dsseqs.size()];
1233           for (i = 0, iSize = dsseqs.size(); i < iSize; i++)
1234           {
1235             seqs[i] = (SequenceI) dsseqs.elementAt(i);
1236             dsseqs.setElementAt(null, i);
1237           }
1238           jdataset = new jalview.datamodel.Alignment(seqs);
1239           Cache.log.debug("New vamsas dataset imported into jalview.");
1240           bindjvvobj(jdataset, dataset);
1241         }
1242         // ////////
1243         // add any new dataset sequence feature annotations
1244         if (dataset.getDataSetAnnotations() != null)
1245         {
1246           for (int dsa = 0; dsa < dataset.getDataSetAnnotationsCount(); dsa++)
1247           {
1248             DataSetAnnotations dseta = dataset.getDataSetAnnotations(dsa);
1249             // TODO: deal with group annotation on datset sequences.
1250             if (dseta.getSeqRefCount() == 1)
1251             {
1252               SequenceI dsSeq = (SequenceI) getvObj2jv((Vobject) dseta
1253                       .getSeqRef(0)); // TODO: deal with group dataset
1254                                       // annotations
1255               if (dsSeq == null)
1256               {
1257                 jalview.bin.Cache.log
1258                         .warn("Couldn't resolve jalview sequenceI for dataset object reference "
1259                                 + ((Vobject) dataset.getDataSetAnnotations(
1260                                         dsa).getSeqRef(0)).getVorbaId()
1261                                         .getId());
1262               }
1263               else
1264               {
1265                 if (dseta.getAnnotationElementCount() == 0)
1266                 {
1267                   jalview.datamodel.SequenceFeature sf = (jalview.datamodel.SequenceFeature) getvObj2jv(dseta);
1268                   if (sf == null)
1269                   {
1270                     dsSeq
1271                             .addSequenceFeature(sf = getJalviewSeqFeature(dseta));
1272                     bindjvvobj(sf, dseta);
1273                   }
1274                 }
1275                 else
1276                 {
1277                   // TODO: deal with alignmentAnnotation style annotation
1278                   // appearing on dataset sequences.
1279                   // JBPNote: we could just add them to all alignments but
1280                   // that may complicate cross references in the jalview
1281                   // datamodel
1282                   Cache.log
1283                           .warn("Ignoring dataset annotation with annotationElements. Not yet supported in jalview.");
1284                 }
1285               }
1286             }
1287           }
1288         }
1289         if (dataset.getAlignmentCount() > 0)
1290         {
1291           // LOAD ALIGNMENTS from DATASET
1292
1293           for (int al = 0, nal = dataset.getAlignmentCount(); al < nal; al++)
1294           {
1295             uk.ac.vamsas.objects.core.Alignment alignment = dataset
1296                     .getAlignment(al);
1297             AlignViewport av=findViewport(alignment);
1298             
1299             jalview.datamodel.AlignmentI jal = null;
1300             if (av != null)
1301             {
1302               jal = av.getAlignment();
1303             }
1304             iSize = alignment.getAlignmentSequenceCount();
1305             boolean newal = (jal == null) ? true : false;
1306             boolean refreshal = false;
1307             Vector newasAnnots = new Vector();
1308             char gapChar = ' '; // default for new alignments read in from the
1309                                 // document
1310             if (jal != null)
1311             {
1312               dsseqs = jal.getSequences(); // for merge/update
1313               gapChar = jal.getGapCharacter();
1314             }
1315             else
1316             {
1317               dsseqs = new Vector();
1318             }
1319             char valGapchar = alignment.getGapChar().charAt(0);
1320             for (i = 0; i < iSize; i++)
1321             {
1322               AlignmentSequence valseq = alignment.getAlignmentSequence(i);
1323               jalview.datamodel.Sequence alseq = (jalview.datamodel.Sequence) getvObj2jv(valseq);
1324               if (syncFromAlignmentSequence(valseq, valGapchar, gapChar, dsseqs) && alseq!=null)
1325               {
1326                 
1327                 // updated to sequence from the document
1328                 jremain--;
1329                 refreshal = true;
1330               }
1331               if (valseq.getAlignmentSequenceAnnotationCount() > 0)
1332               {
1333                 AlignmentSequenceAnnotation[] vasannot = valseq
1334                         .getAlignmentSequenceAnnotation();
1335                 for (int a = 0; a < vasannot.length; a++)
1336                 {
1337                   jalview.datamodel.AlignmentAnnotation asa = (jalview.datamodel.AlignmentAnnotation) getvObj2jv(vasannot[a]); // TODO:
1338                                                                                                                                 // 1:many
1339                                                                                                                                 // jalview
1340                                                                                                                                 // alignment
1341                                                                                                                                 // sequence
1342                                                                                                                                 // annotations
1343                   if (asa == null)
1344                   {
1345                     int se[] = getBounds(vasannot[a]);
1346                     asa = getjAlignmentAnnotation(jal, vasannot[a]);
1347                     asa.setSequenceRef(alseq);
1348                     asa.createSequenceMapping(alseq, se[0], false); // TODO:
1349                                                                     // verify
1350                                                                     // that
1351                                                                     // positions
1352                                                                     // in
1353                                                                     // alseqAnnotation
1354                                                                     // correspond
1355                                                                     // to
1356                                                                     // ungapped
1357                                                                     // residue
1358                                                                     // positions.
1359                     alseq.addAlignmentAnnotation(asa);
1360                     bindjvvobj(asa, vasannot[a]);
1361                     newasAnnots.add(asa);
1362                   }
1363                   else
1364                   {
1365                     // update existing annotation - can do this in place
1366                     if (vasannot[a].getModifiable() == null) // TODO: USE
1367                                                               // VAMSAS LIBRARY
1368                                                               // OBJECT LOCK
1369                                                               // METHODS)
1370                     {
1371                       Cache.log
1372                               .info("UNIMPLEMENTED: not recovering user modifiable sequence alignment annotation");
1373                       // TODO: should at least replace with new one - otherwise
1374                       // things will break
1375                       // basically do this:
1376                       // int se[] = getBounds(vasannot[a]);
1377                       // asa.update(getjAlignmentAnnotation(jal, vasannot[a]));
1378                       // // update from another annotation object in place.
1379                       // asa.createSequenceMapping(alseq, se[0], false);
1380
1381                     }
1382                   }
1383                 }
1384               }
1385             }
1386             if (jal == null)
1387             {
1388               SequenceI[] seqs = new SequenceI[dsseqs.size()];
1389               for (i = 0, iSize = dsseqs.size(); i < iSize; i++)
1390               {
1391                 seqs[i] = (SequenceI) dsseqs.elementAt(i);
1392                 dsseqs.setElementAt(null, i);
1393               }
1394               jal = new jalview.datamodel.Alignment(seqs);
1395               Cache.log.debug("New vamsas alignment imported into jalview "
1396                       + alignment.getVorbaId().getId());
1397               jal.setDataset(jdataset);
1398             }
1399             if (newasAnnots != null && newasAnnots.size() > 0)
1400             {
1401               // Add the new sequence annotations in to the alignment.
1402               for (int an = 0, anSize = newasAnnots.size(); an < anSize; an++)
1403               {
1404                 jal.addAnnotation((AlignmentAnnotation) newasAnnots
1405                         .elementAt(an));
1406                 // TODO: check if anything has to be done - like calling
1407                 // adjustForAlignment or something.
1408                 newasAnnots.setElementAt(null, an);
1409               }
1410               newasAnnots = null;
1411             }
1412             // //////////////////////////////////////////
1413             // //LOAD ANNOTATIONS FOR THE ALIGNMENT
1414             // ////////////////////////////////////
1415             if (alignment.getAlignmentAnnotationCount() > 0)
1416             {
1417               uk.ac.vamsas.objects.core.AlignmentAnnotation[] an = alignment
1418                       .getAlignmentAnnotation();
1419
1420               for (int j = 0; j < an.length; j++)
1421               {
1422                 jalview.datamodel.AlignmentAnnotation jan = (jalview.datamodel.AlignmentAnnotation) getvObj2jv(an[j]);
1423                 if (jan != null)
1424                 {
1425                   // update or stay the same.
1426                   // TODO: should at least replace with a new one - otherwise
1427                   // things will break
1428                   // basically do this:
1429                   // jan.update(getjAlignmentAnnotation(jal, an[a])); // update
1430                   // from another annotation object in place.
1431
1432                   Cache.log
1433                           .debug("update from vamsas alignment annotation to existing jalview alignment annotation.");
1434                   if (an[j].getModifiable() == null) // TODO: USE VAMSAS
1435                                                       // LIBRARY OBJECT LOCK
1436                                                       // METHODS)
1437                   {
1438                     // TODO: user defined annotation is totally mutable... - so
1439                     // load it up or throw away if locally edited.
1440                     Cache.log
1441                             .info("NOT IMPLEMENTED - Recovering user-modifiable annotation - yet...");
1442                   }
1443                   // TODO: compare annotation element rows
1444                   // TODO: compare props.
1445                 }
1446                 else
1447                 {
1448                   jan = getjAlignmentAnnotation(jal, an[j]);
1449                   jal.addAnnotation(jan);
1450                   bindjvvobj(jan, an[j]);
1451                 }
1452               }
1453             }
1454             AlignFrame alignFrame;
1455             if (av == null)
1456             {
1457               Cache.log.debug("New alignframe for alignment "
1458                       + alignment.getVorbaId());
1459               // ///////////////////////////////
1460               // construct alignment view
1461               alignFrame = new AlignFrame(jal, AlignFrame.DEFAULT_WIDTH,
1462                       AlignFrame.DEFAULT_HEIGHT);
1463               av = alignFrame.getViewport();
1464               String title = alignment.getProvenance().getEntry(
1465                       alignment.getProvenance().getEntryCount() - 1)
1466                       .getAction();
1467               if (alignment.getPropertyCount() > 0)
1468               {
1469                 for (int p = 0, pe = alignment.getPropertyCount(); p < pe; p++)
1470                 {
1471                   if (alignment.getProperty(p).getName().equals(
1472                           "title"))
1473                   {
1474                     title = alignment.getProperty(p).getContent();
1475                   }
1476                 }
1477               }
1478               // TODO: automatically create meaningful title for a vamsas
1479               // alignment using its provenance.
1480               if (Cache.log.isDebugEnabled())
1481               {
1482                 title = title + "("
1483                  + alignment.getVorbaId() + ")";
1484                 
1485               }
1486               jalview.gui.Desktop.addInternalFrame(alignFrame, title 
1487                       ,
1488                       AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
1489               bindjvvobj(av.getSequenceSetId(), alignment);
1490             }
1491             else
1492             {
1493               // find the alignFrame for jal.
1494               // TODO: fix this so we retrieve the alignFrame handing av
1495               // *directly*
1496               alignFrame = getAlignFrameFor(av);
1497               if (refreshal)
1498               {
1499                 av.alignmentChanged(alignFrame.alignPanel);
1500               }
1501             }
1502             // LOAD TREES
1503             // /////////////////////////////////////
1504             if (alignment.getTreeCount() > 0)
1505             {
1506
1507               for (int t = 0; t < alignment.getTreeCount(); t++)
1508               {
1509                 jalview.io.vamsas.Tree vstree = new jalview.io.vamsas.Tree(
1510                         this, alignFrame, alignment.getTree(t));
1511                 TreePanel tp = null;
1512                 if (vstree.isValidTree())
1513                 { 
1514                   tp = alignFrame
1515                         .ShowNewickTree(vstree.getNewickTree(), vstree
1516                                 .getTitle(), vstree.getInputData(), 600,
1517                                 500, t * 20 + 50, t * 20 + 50);
1518                   
1519                 }
1520                 if (tp!=null)
1521                 { 
1522                   bindjvvobj(tp, alignment.getTree(t));
1523                   try
1524                   {
1525                     vstree.UpdateSequenceTreeMap(tp);
1526                   } catch (RuntimeException e)
1527                   {
1528                     Cache.log.warn("update of labels failed.",e);
1529                   }
1530                 }
1531                 else
1532                 {
1533                   Cache.log.warn("Cannot create tree for tree "+t+" in document ("+alignment.getTree(t).getVorbaId());
1534                 }
1535
1536               }
1537             }
1538           }
1539         }
1540       }
1541       // we do sequenceMappings last because they span all datasets in a vamsas
1542       // root
1543       for (int _ds = 0, _nds = root.getDataSetCount(); _ds < _nds; _ds++)
1544       {
1545         DataSet dataset = root.getDataSet(_ds);
1546         if (dataset.getSequenceMappingCount() > 0)
1547         {
1548           for (int sm = 0, smCount = dataset.getSequenceMappingCount(); sm < smCount; sm++)
1549           {
1550             Rangetype seqmap = new jalview.io.vamsas.Sequencemapping(this,
1551                     dataset.getSequenceMapping(sm));
1552           }
1553         }
1554       }
1555     }
1556   }
1557
1558   public AlignViewport findViewport(Alignment alignment)
1559   {
1560     AlignViewport av=null;
1561     AlignViewport[] avs = findViewportForSequenceSetId((String)getvObj2jv(alignment));
1562     if (avs!=null)
1563     {
1564       av = avs[0];
1565     }
1566     return av;
1567   }
1568
1569   private AlignViewport[] findViewportForSequenceSetId(String sequenceSetId)
1570   {
1571     Vector viewp = new Vector();
1572     if (Desktop.desktop != null)
1573     {
1574       javax.swing.JInternalFrame[] frames = Desktop.instance.getAllFrames();
1575
1576       for (int t = 0; t < frames.length; t++)
1577       {
1578         if (frames[t] instanceof AlignFrame)
1579         {
1580           if (((AlignFrame) frames[t]).getViewport().getSequenceSetId().equals(sequenceSetId))
1581           {
1582             viewp.addElement(((AlignFrame) frames[t]).getViewport());
1583           }
1584         }
1585       }
1586       if (viewp.size()>0)
1587       {
1588         AlignViewport[] vp = new AlignViewport[viewp.size()];
1589         viewp.copyInto(vp);
1590         return vp;
1591       }
1592     }
1593     return null;
1594   }
1595
1596   // bitfields - should be a template in j1.5
1597   private static int HASSECSTR = 0;
1598
1599   private static int HASVALS = 1;
1600
1601   private static int HASHPHOB = 2;
1602
1603   private static int HASDC = 3;
1604
1605   private static int HASDESCSTR = 4;
1606
1607   private static int HASTWOSTATE = 5; // not used yet.
1608
1609   /**
1610    * parses the AnnotationElements - if they exist - into
1611    * jalview.datamodel.Annotation[] rows Two annotation rows are made if there
1612    * are distinct annotation for both at 'pos' and 'after pos' at any particular
1613    * site.
1614    * 
1615    * @param annotation
1616    * @return { boolean[static int constants ], int[ae.length] - map to annotated
1617    *         object frame, jalview.datamodel.Annotation[],
1618    *         jalview.datamodel.Annotation[] (after)}
1619    */
1620   private Object[] parseRangeAnnotation(
1621           uk.ac.vamsas.objects.core.RangeAnnotation annotation)
1622   {
1623     // set these attributes by looking in the annotation to decide what kind of
1624     // alignment annotation rows will be made
1625     // TODO: potentially we might make several annotation rows from one vamsas
1626     // alignment annotation. the jv2Vobj binding mechanism
1627     // may not quite cope with this (without binding an array of annotations to
1628     // a vamsas alignment annotation)
1629     // summary flags saying what we found over the set of annotation rows.
1630     boolean[] AeContent = new boolean[]
1631     { false, false, false, false, false };
1632     int[] rangeMap = getMapping(annotation);
1633     jalview.datamodel.Annotation[][] anot = new jalview.datamodel.Annotation[][]
1634     { new jalview.datamodel.Annotation[rangeMap.length],
1635         new jalview.datamodel.Annotation[rangeMap.length] };
1636     boolean mergeable = true; // false if 'after positions cant be placed on
1637                               // same annotation row as positions.
1638
1639     if (annotation.getAnnotationElementCount() > 0)
1640     {
1641       AnnotationElement ae[] = annotation.getAnnotationElement();
1642       for (int aa = 0; aa < ae.length; aa++)
1643       {
1644         int pos = (int) ae[aa].getPosition() - 1; // pos counts from 1 to
1645                                                   // (|seg.start-seg.end|+1)
1646         if (pos >= 0 && pos < rangeMap.length)
1647         {
1648           int row = ae[aa].getAfter() ? 1 : 0;
1649           if (anot[row][pos] != null)
1650           {
1651             // only time this should happen is if the After flag is set.
1652             Cache.log.debug("Ignoring duplicate annotation site at " + pos);
1653             continue;
1654           }
1655           if (anot[1 - row][pos] != null)
1656           {
1657             mergeable = false;
1658           }
1659           String desc = "";
1660           if (ae[aa].getDescription() != null)
1661           {
1662             desc = ae[aa].getDescription();
1663             if (desc.length() > 0)
1664             {
1665               // have imported valid description string
1666               AeContent[HASDESCSTR] = true;
1667             }
1668           }
1669           String dc = null; // ae[aa].getDisplayCharacter()==null ? "dc" :
1670                             // ae[aa].getDisplayCharacter();
1671           String ss = null; // ae[aa].getSecondaryStructure()==null ? "ss" :
1672                             // ae[aa].getSecondaryStructure();
1673           java.awt.Color colour = null;
1674           if (ae[aa].getGlyphCount() > 0)
1675           {
1676             Glyph[] glyphs = ae[aa].getGlyph();
1677             for (int g = 0; g < glyphs.length; g++)
1678             {
1679               if (glyphs[g]
1680                       .getDict()
1681                       .equals(
1682                               uk.ac.vamsas.objects.utils.GlyphDictionary.PROTEIN_SS_3STATE))
1683               {
1684                 ss = glyphs[g].getContent();
1685                 AeContent[HASSECSTR] = true;
1686               }
1687               else if (glyphs[g]
1688                       .getDict()
1689                       .equals(
1690                               uk.ac.vamsas.objects.utils.GlyphDictionary.PROTEIN_HD_HYDRO))
1691               {
1692                 Cache.log.debug("ignoring hydrophobicity glyph marker.");
1693                 AeContent[HASHPHOB] = true;
1694                 char c = (dc = glyphs[g].getContent()).charAt(0);
1695                 // dc may get overwritten - but we still set the colour.
1696                 colour = new java.awt.Color(c == '+' ? 255 : 0,
1697                         c == '.' ? 255 : 0, c == '-' ? 255 : 0);
1698
1699               }
1700               else if (glyphs[g].getDict().equals(
1701                       uk.ac.vamsas.objects.utils.GlyphDictionary.DEFAULT))
1702               {
1703                 dc = glyphs[g].getContent();
1704                 AeContent[HASDC] = true;
1705               }
1706               else
1707               {
1708                 Cache.log.debug("IMPLEMENTATION TODO: Ignoring unknown glyph type "
1709                         + glyphs[g].getDict());
1710               }
1711             }
1712           }
1713           float val = 0;
1714           if (ae[aa].getValueCount() > 0)
1715           {
1716             AeContent[HASVALS] = true;
1717             if (ae[aa].getValueCount() > 1)
1718             {
1719               Cache.log.warn("ignoring additional "
1720                       + (ae[aa].getValueCount() - 1)
1721                       + "values in annotation element.");
1722             }
1723             val = ae[aa].getValue(0);
1724           }
1725           if (colour == null)
1726           {
1727             anot[row][pos] = new jalview.datamodel.Annotation(
1728                     (dc != null) ? dc : "", desc, (ss != null) ? ss
1729                             .charAt(0) : ' ', val);
1730           }
1731           else
1732           {
1733             anot[row][pos] = new jalview.datamodel.Annotation(
1734                     (dc != null) ? dc : "", desc, (ss != null) ? ss
1735                             .charAt(0) : ' ', val, colour);
1736           }
1737         }
1738         else
1739         {
1740           Cache.log.warn("Ignoring out of bound annotation element " + aa
1741                   + " in " + annotation.getVorbaId().getId());
1742         }
1743       }
1744       // decide on how many annotation rows are needed.
1745       if (mergeable)
1746       {
1747         for (int i = 0; i < anot[0].length; i++)
1748         {
1749           if (anot[1][i] != null)
1750           {
1751             anot[0][i] = anot[1][i];
1752             anot[0][i].description = anot[0][i].description + " (after)";
1753             AeContent[HASDESCSTR] = true; // we have valid description string
1754                                           // data
1755             anot[1][i] = null;
1756           }
1757         }
1758         anot[1] = null;
1759       }
1760       else
1761       {
1762         for (int i = 0; i < anot[0].length; i++)
1763         {
1764           anot[1][i].description = anot[1][i].description + " (after)";
1765         }
1766       }
1767       return new Object[]
1768       { AeContent, rangeMap, anot[0], anot[1] };
1769     }
1770     else
1771     {
1772       // no annotations to parse. Just return an empty annotationElement[]
1773       // array.
1774       return new Object[]
1775       { AeContent, rangeMap, anot[0], anot[1] };
1776     }
1777     // return null;
1778   }
1779
1780   /**
1781    * @param jal
1782    *          the jalview alignment to which the annotation will be attached
1783    *          (ideally - freshly updated from corresponding vamsas alignment)
1784    * @param annotation
1785    * @return unbound jalview alignment annotation object.
1786    */
1787   private jalview.datamodel.AlignmentAnnotation getjAlignmentAnnotation(
1788           jalview.datamodel.AlignmentI jal,
1789           uk.ac.vamsas.objects.core.RangeAnnotation annotation)
1790   {
1791     if (annotation == null)
1792     {
1793       return null;
1794     }
1795     // boolean
1796     // hasSequenceRef=annotation.getClass().equals(uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation.class);
1797     // boolean hasProvenance=hasSequenceRef ||
1798     // (annotation.getClass().equals(uk.ac.vamsas.objects.core.AlignmentAnnotation.class));
1799     /*
1800      * int se[] = getBounds(annotation); if (se==null) se=new int[]
1801      * {0,jal.getWidth()-1};
1802      */
1803     Object[] parsedRangeAnnotation = parseRangeAnnotation(annotation);
1804     String a_label = annotation.getLabel();
1805     String a_descr = annotation.getDescription();
1806     GraphLine gl=null;
1807     int type=0;
1808     boolean interp=true; // cleared if annotation is DISCRETE
1809     // set type and other attributes from properties
1810     if (annotation.getPropertyCount() > 0)
1811     {
1812       // look for special jalview properties
1813       uk.ac.vamsas.objects.core.Property[] props = annotation
1814               .getProperty();
1815       for (int p = 0; p < props.length; p++)
1816       {
1817         if (props[p].getName().equalsIgnoreCase(DISCRETE_ANNOTATION))
1818         {
1819           type = AlignmentAnnotation.BAR_GRAPH;
1820           interp=false;
1821         } else if
1822          (props[p].getName().equalsIgnoreCase(CONTINUOUS_ANNOTATION)) {
1823           type = AlignmentAnnotation.LINE_GRAPH;
1824         } else if
1825         (props[p].getName().equalsIgnoreCase(THRESHOLD))
1826         {
1827           Float val=null;
1828           try {
1829             val = new Float(props[p].getContent());
1830           }catch (Exception e)
1831           {
1832             Cache.log.warn("Failed to parse threshold property");
1833           }
1834           if (val!=null)
1835           if (gl==null)
1836           {
1837             gl = new GraphLine(val.floatValue(), "", java.awt.Color.black);
1838           } else
1839           {
1840             gl.value = val.floatValue();
1841           }
1842         }
1843         else if (props[p].getName().equalsIgnoreCase(THRESHOLD+"Name"))
1844         {
1845           if (gl==null)
1846             gl = new GraphLine(0, "", java.awt.Color.black);
1847           gl.label = props[p].getContent();
1848         }
1849       }
1850     }
1851     jalview.datamodel.AlignmentAnnotation jan = null;
1852     if (a_label == null || a_label.length() == 0)
1853     {
1854       a_label = annotation.getType();
1855       if (a_label.length() == 0)
1856       {
1857         a_label = "Unamed annotation";
1858       }
1859     }
1860     if (a_descr == null || a_descr.length() == 0)
1861     {
1862       a_descr = "Annotation of type '" + annotation.getType() + "'";
1863     }
1864     if (parsedRangeAnnotation == null)
1865     {
1866       Cache.log
1867               .debug("Inserting empty annotation row elements for a whole-alignment annotation.");
1868     }
1869     else
1870     {
1871       if (parsedRangeAnnotation[3] != null)
1872       {
1873         Cache.log.warn("Ignoring 'After' annotation row in "
1874                 + annotation.getVorbaId());
1875       }
1876       jalview.datamodel.Annotation[] arow = (jalview.datamodel.Annotation[]) parsedRangeAnnotation[2];
1877       boolean[] has = (boolean[]) parsedRangeAnnotation[0];
1878       // VAMSAS: getGraph is only on derived annotation for alignments - in this
1879       // way its 'odd' - there is already an existing TODO about removing this
1880       // flag as being redundant
1881       /*
1882        * if
1883        * ((annotation.getClass().equals(uk.ac.vamsas.objects.core.AlignmentAnnotation.class) &&
1884        * ((uk.ac.vamsas.objects.core.AlignmentAnnotation)annotation).getGraph()) ||
1885        * (hasSequenceRef=true &&
1886        * ((uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation)annotation).getGraph())) {
1887        */
1888       if (has[HASVALS])
1889       {
1890         if (type==0)
1891         {
1892           type = jalview.datamodel.AlignmentAnnotation.BAR_GRAPH; // default type of value annotation
1893           if (has[HASHPHOB])
1894           {
1895             // no hints - so we ensure HPHOB display is like this.
1896             type = jalview.datamodel.AlignmentAnnotation.BAR_GRAPH;
1897           }
1898         }
1899         // make bounds and automatic description strings for jalview user's
1900         // benefit (these shouldn't be written back to vamsas document)
1901         boolean first = true;
1902         float min = 0, max = 1;
1903         int lastval = 0;
1904         for (int i = 0; i < arow.length; i++)
1905         {
1906           if (arow[i] != null)
1907           {
1908             if (i - lastval > 1 && interp)
1909             {
1910               // do some interpolation *between* points
1911               if (arow[lastval] != null)
1912               {
1913                 float interval = arow[i].value - arow[lastval].value;
1914                 interval /= i - lastval;
1915                 float base = arow[lastval].value;
1916                 for (int ip = lastval + 1, np = 0; ip < i; np++, ip++)
1917                 {
1918                   arow[ip] = new jalview.datamodel.Annotation("", "", ' ',
1919                           interval * np + base);
1920                   // NB - Interpolated points don't get a tooltip and
1921                   // description.
1922                 }
1923               }
1924             }
1925             lastval = i;
1926             // check range - shouldn't we have a min and max property in the
1927             // annotation object ?
1928             if (first)
1929             {
1930               min = max = arow[i].value;
1931               first = false;
1932             }
1933             else
1934             {
1935               if (arow[i].value < min)
1936               {
1937                 min = arow[i].value;
1938               }
1939               else if (arow[i].value > max)
1940               {
1941                 max = arow[i].value;
1942               }
1943             }
1944             // make tooltip and display char value
1945             if (!has[HASDESCSTR])
1946             {
1947               arow[i].description = arow[i].value + "";
1948             }
1949             if (!has[HASDC])
1950             {
1951               if (!interp)
1952                 {
1953                 if (arow[i].description!=null && arow[i].description.length()<3)
1954                 {
1955                   // copy over the description as the display char.
1956                   arow[i].displayCharacter = new String(arow[i].description);
1957                 }
1958                 } else
1959                 {
1960                   // mark the position as a point used for the interpolation.
1961                 arow[i].displayCharacter = arow[i].value + "";
1962                 }
1963             }
1964           }
1965         }
1966         jan = new jalview.datamodel.AlignmentAnnotation(a_label, a_descr,
1967                 arow, min, max, type);
1968       }
1969       else
1970       {
1971         if (annotation.getAnnotationElementCount()==0)
1972         {
1973           // empty annotation array
1974           // TODO: alignment 'features' compare rangeType spec to alignment width - if it is not complete, then mark regions on the annotation row.
1975         }
1976         jan = new jalview.datamodel.AlignmentAnnotation(a_label, a_descr,
1977                 arow);
1978         jan.setThreshold(null);
1979       }
1980       if (annotation.getLinkCount() > 0)
1981       {
1982         Cache.log.warn("Ignoring " + annotation.getLinkCount()
1983                 + "links added to AlignmentAnnotation.");
1984       }
1985       if (annotation.getModifiable() == null || annotation.getModifiable().length()==0) // TODO: USE VAMSAS LIBRARY OBJECT
1986                                               // LOCK METHODS)
1987       {
1988         jan.editable = true;
1989       }
1990       try
1991       {
1992         if (annotation.getGroup() != null
1993                 && annotation.getGroup().length() > 0)
1994         {
1995           jan.graphGroup = Integer.parseInt(annotation.getGroup()); // TODO: group similarly named annotation together ?
1996         }
1997       } catch (Exception e)
1998       {
1999         Cache.log
2000                 .info("UNIMPLEMENTED : Couldn't parse non-integer group value for setting graphGroup correctly.");
2001       }
2002       return jan;
2003
2004     }
2005
2006     return null;
2007   }
2008
2009   private SequenceFeature getJalviewSeqFeature(RangeAnnotation dseta)
2010   {
2011     int[] se = getBounds(dseta);
2012     SequenceFeature sf = new jalview.datamodel.SequenceFeature(dseta
2013             .getType(), dseta.getDescription(), dseta.getStatus(), se[0],
2014             se[1], dseta.getGroup());
2015     if (dseta.getLinkCount() > 0)
2016     {
2017       Link[] links = dseta.getLink();
2018       for (int i = 0; i < links.length; i++)
2019       {
2020         sf.addLink(links[i].getContent() + "|" + links[i].getHref());
2021       }
2022     }
2023     return sf;
2024   }
2025
2026   /**
2027    * get real bounds of a RangeType's specification. start and end are an
2028    * inclusive range within which all segments and positions lie. TODO: refactor
2029    * to vamsas utils
2030    * 
2031    * @param dseta
2032    * @return int[] { start, end}
2033    */
2034   private int[] getBounds(RangeType dseta)
2035   {
2036     if (dseta != null)
2037     {
2038       int[] se = null;
2039       if (dseta.getSegCount() > 0 && dseta.getPosCount() > 0)
2040       {
2041         throw new Error(
2042                 "Invalid vamsas RangeType - cannot resolve both lists of Pos and Seg from choice!");
2043       }
2044       if (dseta.getSegCount() > 0)
2045       {
2046         se = getSegRange(dseta.getSeg(0), true);
2047         for (int s = 1, sSize = dseta.getSegCount(); s < sSize; s++)
2048         {
2049           int nse[] = getSegRange(dseta.getSeg(s), true);
2050           if (se[0] > nse[0])
2051           {
2052             se[0] = nse[0];
2053           }
2054           if (se[1] < nse[1])
2055           {
2056             se[1] = nse[1];
2057           }
2058         }
2059       }
2060       if (dseta.getPosCount() > 0)
2061       {
2062         // could do a polarity for pos range too. and pass back indication of
2063         // discontinuities.
2064         int pos = dseta.getPos(0).getI();
2065         se = new int[]
2066         { pos, pos };
2067         for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++)
2068         {
2069           pos = dseta.getPos(p).getI();
2070           if (se[0] > pos)
2071           {
2072             se[0] = pos;
2073           }
2074           if (se[1] < pos)
2075           {
2076             se[1] = pos;
2077           }
2078         }
2079       }
2080       return se;
2081     }
2082     return null;
2083   }
2084
2085   /**
2086    * map from a rangeType's internal frame to the referenced object's coordinate
2087    * frame.
2088    * 
2089    * @param dseta
2090    * @return int [] { ref(pos)...} for all pos in rangeType's frame.
2091    */
2092   private int[] getMapping(RangeType dseta)
2093   {
2094     Vector posList = new Vector();
2095     if (dseta != null)
2096     {
2097       int[] se = null;
2098       if (dseta.getSegCount() > 0 && dseta.getPosCount() > 0)
2099       {
2100         throw new Error(
2101                 "Invalid vamsas RangeType - cannot resolve both lists of Pos and Seg from choice!");
2102       }
2103       if (dseta.getSegCount() > 0)
2104       {
2105         for (int s = 0, sSize = dseta.getSegCount(); s < sSize; s++)
2106         {
2107           se = getSegRange(dseta.getSeg(s), false);
2108           int se_end = se[1 - se[2]] + (se[2] == 0 ? 1 : -1);
2109           for (int p = se[se[2]]; p != se_end; p += se[2] == 0 ? 1 : -1)
2110           {
2111             posList.add(new Integer(p));
2112           }
2113         }
2114       }
2115       else if (dseta.getPosCount() > 0)
2116       {
2117         int pos = dseta.getPos(0).getI();
2118
2119         for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++)
2120         {
2121           pos = dseta.getPos(p).getI();
2122           posList.add(new Integer(pos));
2123         }
2124       }
2125     }
2126     if (posList != null && posList.size() > 0)
2127     {
2128       int[] range = new int[posList.size()];
2129       for (int i = 0; i < range.length; i++)
2130       {
2131         range[i] = ((Integer) posList.elementAt(i)).intValue();
2132       }
2133       posList.clear();
2134       return range;
2135     }
2136     return null;
2137   }
2138
2139   /**
2140    * 
2141    * @param maprange
2142    *          where the from range is the local mapped range, and the to range
2143    *          is the 'mapped' range in the MapRangeType
2144    * @param default
2145    *          unit for local
2146    * @param default
2147    *          unit for mapped
2148    * @return MapList
2149    */
2150   private jalview.util.MapList parsemapType(MapType maprange, int localu,
2151           int mappedu)
2152   {
2153     jalview.util.MapList ml = null;
2154     int[] localRange = getMapping(maprange.getLocal());
2155     int[] mappedRange = getMapping(maprange.getMapped());
2156     long lu = maprange.getLocal().hasUnit() ? maprange.getLocal().getUnit()
2157             : localu;
2158     long mu = maprange.getMapped().hasUnit() ? maprange.getMapped()
2159             .getUnit() : mappedu;
2160     ml = new jalview.util.MapList(localRange, mappedRange, (int) lu,
2161             (int) mu);
2162     return ml;
2163   }
2164
2165   /**
2166    * initialise a range type object from a set of start/end inclusive intervals
2167    * 
2168    * @param mrt
2169    * @param range
2170    */
2171   private void initRangeType(RangeType mrt, int[] range)
2172   {
2173     for (int i = 0; i < range.length; i += 2)
2174     {
2175       Seg vSeg = new Seg();
2176       vSeg.setStart(range[i]);
2177       vSeg.setEnd(range[i + 1]);
2178       mrt.addSeg(vSeg);
2179     }
2180   }
2181
2182   /**
2183    * initialise a MapType object from a MapList object.
2184    * 
2185    * @param maprange
2186    * @param ml
2187    * @param setUnits
2188    */
2189   private void initMapType(MapType maprange, jalview.util.MapList ml,
2190           boolean setUnits)
2191   {
2192     maprange.setLocal(new Local());
2193     maprange.setMapped(new Mapped());
2194     initRangeType(maprange.getLocal(), ml.getFromRanges());
2195     initRangeType(maprange.getMapped(), ml.getToRanges());
2196     if (setUnits)
2197     {
2198       maprange.getLocal().setUnit(ml.getFromRatio());
2199       maprange.getLocal().setUnit(ml.getToRatio());
2200     }
2201   }
2202
2203   /*
2204    * not needed now. Provenance getVamsasProvenance(jalview.datamodel.Provenance
2205    * jprov) { jalview.datamodel.ProvenanceEntry[] entries = null; // TODO: fix
2206    * App and Action here. Provenance prov = new Provenance();
2207    * org.exolab.castor.types.Date date = new org.exolab.castor.types.Date( new
2208    * java.util.Date()); Entry provEntry;
2209    * 
2210    * if (jprov != null) { entries = jprov.getEntries(); for (int i = 0; i <
2211    * entries.length; i++) { provEntry = new Entry(); try { date = new
2212    * org.exolab.castor.types.Date(entries[i].getDate()); } catch (Exception ex) {
2213    * ex.printStackTrace();
2214    * 
2215    * date = new org.exolab.castor.types.Date(entries[i].getDate()); }
2216    * provEntry.setDate(date); provEntry.setUser(entries[i].getUser());
2217    * provEntry.setAction(entries[i].getAction()); prov.addEntry(provEntry); } }
2218    * else { provEntry = new Entry(); provEntry.setDate(date);
2219    * provEntry.setUser(System.getProperty("user.name")); // TODO: ext string
2220    * provEntry.setApp("JVAPP"); // TODO: ext string provEntry.setAction(action);
2221    * prov.addEntry(provEntry); }
2222    * 
2223    * return prov; }
2224    */
2225   jalview.datamodel.Provenance getJalviewProvenance(Provenance prov)
2226   {
2227     // TODO: fix App and Action entries and check use of provenance in jalview.
2228     jalview.datamodel.Provenance jprov = new jalview.datamodel.Provenance();
2229     for (int i = 0; i < prov.getEntryCount(); i++)
2230     {
2231       jprov.addEntry(prov.getEntry(i).getUser(), prov.getEntry(i)
2232               .getAction(), prov.getEntry(i).getDate(), prov.getEntry(i)
2233               .getId());
2234     }
2235
2236     return jprov;
2237   }
2238
2239   /**
2240    * 
2241    * @return default initial provenance list for a Jalview created vamsas
2242    *         object.
2243    */
2244   Provenance dummyProvenance()
2245   {
2246     return dummyProvenance(null);
2247   }
2248
2249   Entry dummyPEntry(String action)
2250   {
2251     Entry entry = new Entry();
2252     entry.setApp(this.provEntry.getApp());
2253     if (action != null)
2254     {
2255       entry.setAction(action);
2256     }
2257     else
2258     {
2259       entry.setAction("created.");
2260     }
2261     entry.setDate(new java.util.Date());
2262     entry.setUser(this.provEntry.getUser());
2263     return entry;
2264   }
2265
2266   Provenance dummyProvenance(String action)
2267   {
2268     Provenance prov = new Provenance();
2269     prov.addEntry(dummyPEntry(action));
2270     return prov;
2271   }
2272
2273   Entry addProvenance(Provenance p, String action)
2274   {
2275     Entry dentry = dummyPEntry(action);
2276     p.addEntry(dentry);
2277     return dentry;
2278   }
2279
2280   public Entry getProvEntry()
2281   {
2282     return provEntry;
2283   }
2284
2285   public IClientDocument getClientDocument()
2286   {
2287     return cdoc;
2288   }
2289
2290   public IdentityHashMap getJvObjectBinding()
2291   {
2292     return jv2vobj;
2293   }
2294
2295   public Hashtable getVamsasObjectBinding()
2296   {
2297     return vobj2jv;
2298   }
2299
2300   public void storeSequenceMappings(AlignViewport viewport, String title)
2301           throws Exception
2302   {
2303     AlignViewport av = viewport;
2304     try
2305     {
2306       jalview.datamodel.AlignmentI jal = av.getAlignment();
2307       // /////////////////////////////////////////
2308       // SAVE THE DATASET
2309       DataSet dataset = null;
2310       if (jal.getDataset() == null)
2311       {
2312         Cache.log.warn("Creating new dataset for an alignment.");
2313         jal.setDataset(null);
2314       }
2315       dataset = (DataSet) getjv2vObj(jal.getDataset());
2316       // Store any sequence mappings.
2317       if (av.getAlignment().getCodonFrames() != null
2318               && av.getAlignment().getCodonFrames().length > 0)
2319       {
2320         jalview.datamodel.AlignedCodonFrame[] cframes = av.getAlignment()
2321                 .getCodonFrames();
2322         for (int cf = 0; cf < cframes.length; cf++)
2323         {
2324           if (cframes[cf].getdnaSeqs().length > 0)
2325           {
2326             jalview.datamodel.SequenceI[] dmps = cframes[cf].getdnaSeqs();
2327             jalview.datamodel.Mapping[] mps = cframes[cf].getProtMappings();
2328             for (int smp = 0; smp < mps.length; smp++)
2329             {
2330               uk.ac.vamsas.objects.core.SequenceType mfrom = (SequenceType) getjv2vObj(dmps[smp]);
2331               if (mfrom != null)
2332               {
2333                 new jalview.io.vamsas.Sequencemapping(this, mps[smp],
2334                         mfrom, dataset);
2335               }
2336               else
2337               {
2338                 Cache.log
2339                         .warn("NO Vamsas Binding for local sequence! NOT CREATING MAPPING FOR "
2340                                 + dmps[smp].getDisplayId(true)
2341                                 + " to "
2342                                 + mps[smp].getTo().getName());
2343               }
2344             }
2345           }
2346         }
2347       }
2348     } catch (Exception e)
2349     {
2350       throw new Exception("Couldn't store sequence mappings for " + title,
2351               e);
2352     }
2353   }
2354 }