Jalview 2.6 source licence
[jalview.git] / src / jalview / io / vamsas / Sequencemapping.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
3  * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
10  * 
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.io.vamsas;
19
20 import java.util.Vector;
21
22 import jalview.datamodel.AlignedCodonFrame;
23 import jalview.datamodel.Mapping;
24 import jalview.datamodel.SequenceI;
25 import jalview.io.VamsasAppDatastore;
26 import uk.ac.vamsas.client.Vobject;
27 import uk.ac.vamsas.objects.core.AlignmentSequence;
28 import uk.ac.vamsas.objects.core.DataSet;
29 import uk.ac.vamsas.objects.core.Local;
30 import uk.ac.vamsas.objects.core.RangeType;
31 import uk.ac.vamsas.objects.core.Seg;
32 import uk.ac.vamsas.objects.core.Sequence;
33 import uk.ac.vamsas.objects.core.SequenceMapping;
34 import uk.ac.vamsas.objects.core.SequenceType;
35
36 /**
37  * binds a vamsas sequence mapping object from the vamsas document to a maplist
38  * object associated with a mapping in the Jalview model. We use the maplist
39  * object because these are referred to both in the Mapping object associated
40  * with a jalview.datamodel.DBRefEntry and in the array of
41  * jalview.datamodel.AlCodonFrame objects that Jalview uses to propagate
42  * sequence mapping position highlighting across the views.
43  * 
44  * @author JimP
45  * 
46  */
47 public class Sequencemapping extends Rangetype
48 {
49   public Sequencemapping(VamsasAppDatastore datastore,
50           SequenceMapping sequenceMapping)
51   {
52     super(datastore, sequenceMapping, jalview.util.MapList.class);
53     doJvUpdate();
54   }
55
56   private SequenceType from;
57
58   private DataSet ds;
59
60   private Mapping mjvmapping;
61
62   /**
63    * create or update a vamsas sequence mapping corresponding to a jalview
64    * Mapping between two dataset sequences
65    * 
66    * @param datastore
67    * @param mjvmapping
68    * @param from
69    * @param ds
70    */
71   public Sequencemapping(VamsasAppDatastore datastore,
72           jalview.datamodel.Mapping mjvmapping,
73           uk.ac.vamsas.objects.core.SequenceType from,
74           uk.ac.vamsas.objects.core.DataSet ds)
75   {
76     super(datastore, mjvmapping.getMap(), SequenceMapping.class);
77     this.from = from;
78     this.ds = ds;
79     this.mjvmapping = mjvmapping;
80     validate();
81     doSync();
82   }
83
84   /**
85    * local check that extant mapping context is valid
86    */
87   public void validate()
88   {
89
90     SequenceMapping sequenceMapping = (SequenceMapping) vobj;
91     if (sequenceMapping == null)
92     {
93       return;
94     }
95     if (from != null && sequenceMapping.getLoc() != from)
96     {
97       jalview.bin.Cache.log.warn("Probable IMPLEMENTATION ERROR: " + from
98               + " doesn't match the local mapping sequence.");
99     }
100     if (ds != null && sequenceMapping.is__stored_in_document()
101             && sequenceMapping.getV_parent() != ds)
102     {
103       jalview.bin.Cache.log
104               .warn("Probable IMPLEMENTATION ERROR: "
105                       + ds
106                       + " doesn't match the parent of the bound sequence mapping object.");
107     }
108   }
109
110   public void addToDocument()
111   {
112     add(mjvmapping, from, ds);
113   }
114
115   public void addFromDocument()
116   {
117     add((SequenceMapping) vobj);
118   }
119
120   public void conflict()
121   {
122     conflict(mjvmapping, (SequenceMapping) vobj);
123
124   }
125
126   public void updateToDoc()
127   {
128     update(mjvmapping, (SequenceMapping) vobj);
129   }
130
131   public void updateFromDoc()
132   {
133     update((SequenceMapping) vobj, (jalview.datamodel.Mapping) jvobj);
134   }
135
136   private void conflict(Mapping mjvmapping, SequenceMapping sequenceMapping)
137   {
138     System.err.println("Conflict in update of sequenceMapping "
139             + sequenceMapping.getVorbaId());
140   }
141
142   private void add(Mapping mjvmapping,
143           uk.ac.vamsas.objects.core.SequenceType from, DataSet ds)
144   {
145     SequenceI jvto = mjvmapping.getTo();
146     while (jvto.getDatasetSequence() != null)
147     {
148       jvto = jvto.getDatasetSequence();
149     }
150     SequenceType to = (SequenceType) getjv2vObj(jvto);
151     if (to == null)
152     {
153       jalview.bin.Cache.log
154               .warn("FIXME NONFATAL - do a second update: Ignoring Forward Reference to seuqence not yet bound to vamsas seuqence object");
155       return;
156     }
157     SequenceMapping sequenceMapping = new SequenceMapping();
158     sequenceMapping.setLoc(from);
159     sequenceMapping.setMap(to);
160     boolean dnaToProt = false, sense = false;
161     // ensure that we create a mapping with the correct sense
162     if (((Sequence) sequenceMapping.getLoc()).getDictionary().equals(
163             uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA))
164     {
165       if (((Sequence) sequenceMapping.getMap()).getDictionary().equals(
166               uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_AA))
167       {
168         dnaToProt = true;
169         sense = true;
170       }
171     }
172     else
173     {
174       if (((Sequence) sequenceMapping.getMap()).getDictionary().equals(
175               uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA))
176       {
177         dnaToProt = true;
178         sense = false;
179       }
180     }
181
182     if (!dnaToProt)
183     {
184       jalview.bin.Cache.log
185               .warn("Ignoring Mapping - don't support protein to protein mapping in vamsas document yet.");
186       return;
187     }
188     if (ds == null)
189     {
190       // locate dataset for storage of SequenceMapping
191       if (sense)
192       {
193         ds = (DataSet) ((uk.ac.vamsas.client.Vobject) sequenceMapping
194                 .getLoc()).getV_parent();
195       }
196       else
197       {
198         ds = (DataSet) ((uk.ac.vamsas.client.Vobject) sequenceMapping
199                 .getMap()).getV_parent();
200       }
201     }
202     if (sense)
203     {
204       this.initMapType(sequenceMapping, mjvmapping.getMap(), true);
205     }
206     else
207     {
208       this.initMapType(sequenceMapping, mjvmapping.getMap().getInverse(),
209               true);
210     }
211     ds.addSequenceMapping(sequenceMapping);
212     sequenceMapping.setProvenance(this
213             .dummyProvenance("user defined coding region translation")); // TODO:
214     // correctly
215     // construct
216     // provenance
217     // based
218     // on
219     // source
220     // of
221     // mapping
222     bindjvvobj(mjvmapping.getMap(), sequenceMapping);
223
224     jalview.bin.Cache.log.debug("Successfully created mapping "
225             + sequenceMapping.getVorbaId());
226   }
227
228   // private void update(jalview.util.MapList mjvmapping,
229   // SequenceMapping sequenceMapping)
230   {
231     jalview.bin.Cache.log
232             .error("Not implemented: Jalview Update Alcodon Mapping:TODO!");
233   }
234
235   private void update(SequenceMapping sequenceMapping,
236           jalview.datamodel.Mapping mjvmapping)
237   {
238     jalview.bin.Cache.log
239             .error("Not implemented: Update DBRef Mapping from Jalview");
240   }
241
242   private void update(jalview.datamodel.Mapping mjvmapping,
243           SequenceMapping sequenceMapping)
244   {
245     jalview.bin.Cache.log
246             .error("Not implemented: Jalview Update Sequence DBRef Mapping");
247   }
248
249   /**
250    * bind a SequenceMapping to a live AlCodonFrame element limitations:
251    * Currently, jalview only deals with mappings between dataset sequences, and
252    * even then, only between those that map from DNA to Protein.
253    * 
254    * @param sequenceMapping
255    */
256   private void add(SequenceMapping sequenceMapping)
257   {
258     Object mobj;
259     SequenceI from = null, to = null;
260     boolean dnaToProt = false, sense = false;
261     Sequence sdloc = null, sdmap = null;
262     if (sequenceMapping.getLoc() instanceof AlignmentSequence)
263     {
264       sdloc = (Sequence) ((AlignmentSequence) sequenceMapping.getLoc())
265               .getRefid();
266     }
267     else
268     {
269       sdloc = ((Sequence) sequenceMapping.getLoc());
270     }
271     if (sequenceMapping.getMap() instanceof AlignmentSequence)
272     {
273       sdmap = (Sequence) ((AlignmentSequence) sequenceMapping.getMap())
274               .getRefid();
275     }
276     else
277     {
278       sdmap = ((Sequence) sequenceMapping.getMap());
279     }
280     if (sdloc == null || sdmap == null)
281     {
282       jalview.bin.Cache.log.info("Ignoring non sequence-sequence mapping");
283       return;
284     }
285     mobj = this.getvObj2jv((Vobject) sdloc);
286     if (mobj instanceof SequenceI)
287     {
288       from = (SequenceI) mobj;
289     }
290     mobj = this.getvObj2jv((Vobject) sdmap);
291     if (mobj instanceof SequenceI)
292     {
293       to = (SequenceI) mobj;
294     }
295     if (from == null || to == null)
296     {
297
298       jalview.bin.Cache.log
299               .error("Probable Vamsas implementation error : unbound dataset sequences involved in a mapping are being parsed!");
300       return;
301     }
302
303     if (sdloc.getDictionary().equals(
304             uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA))
305     {
306       if (sdmap.getDictionary().equals(
307               uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_AA))
308       {
309         dnaToProt = true;
310         sense = true;
311       }
312       // else {
313
314       // }
315     }
316     else
317     {
318       if (sdmap.getDictionary().equals(
319               uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA))
320       {
321         dnaToProt = true;
322         sense = false;
323       }
324     }
325     // create mapping storage object and make each dataset alignment reference
326     // it.
327     jalview.datamodel.AlignmentI dsLoc = (jalview.datamodel.AlignmentI) getvObj2jv(sdloc
328             .getV_parent());
329     jalview.datamodel.AlignmentI dsMap = (jalview.datamodel.AlignmentI) getvObj2jv(sdmap
330             .getV_parent());
331     AlignedCodonFrame afc = new AlignedCodonFrame(0);
332
333     if (dsLoc != null && dsLoc != dsMap)
334     {
335       dsLoc.addCodonFrame(afc);
336     }
337     if (dsMap != null)
338     {
339       dsMap.addCodonFrame(afc);
340     }
341     // create and add the new mapping to (each) dataset's codonFrame
342
343     jalview.util.MapList mapping = null;
344     if (dnaToProt)
345     {
346       if (!sense)
347       {
348         mapping = this.parsemapType(sequenceMapping, 1, 3); // invert sense
349         mapping = new jalview.util.MapList(mapping.getToRanges(), mapping
350                 .getFromRanges(), mapping.getToRatio(), mapping
351                 .getFromRatio());
352         afc.addMap(to, from, mapping);
353       }
354       else
355       {
356         mapping = this.parsemapType(sequenceMapping, 3, 1); // correct sense
357         afc.addMap(from, to, mapping);
358       }
359     }
360     else
361     {
362       mapping = this.parsemapType(sequenceMapping, 1, 1); // correct sense
363       afc.addMap(from, to, mapping);
364     }
365     bindjvvobj(mapping, sequenceMapping);
366     jalview.structure.StructureSelectionManager
367             .getStructureSelectionManager().addMappings(
368                     new AlignedCodonFrame[]
369                     { afc });
370     // Try to link up any conjugate database references in the two sequences
371     // matchConjugateDBRefs(from, to, mapping);
372     // Try to propagate any dbrefs across this mapping.
373
374   }
375
376   /**
377    * Complete any 'to' references in jalview.datamodel.Mapping objects
378    * associated with conjugate DBRefEntry under given mapping
379    * 
380    * @param from
381    *          sequence corresponding to from reference for sequence mapping
382    * @param to
383    *          sequence correspondeing to to reference for sequence mapping
384    * @param smap
385    *          maplist parsed in same sense as from and to
386    */
387   private void matchConjugateDBRefs(SequenceI from, SequenceI to,
388           jalview.util.MapList smap)
389   {
390     if (from.getDBRef() == null && to.getDBRef() == null)
391     {
392       if (jalview.bin.Cache.log.isDebugEnabled())
393       {
394         jalview.bin.Cache.log.debug("Not matching conjugate refs for "
395                 + from.getName() + " and " + to.getName());
396       }
397       return;
398     }
399     if (jalview.bin.Cache.log.isDebugEnabled())
400     {
401       jalview.bin.Cache.log.debug("Matching conjugate refs for "
402               + from.getName() + " and " + to.getName());
403     }
404     jalview.datamodel.DBRefEntry[] fdb = from.getDBRef();
405     jalview.datamodel.DBRefEntry[] tdb = new jalview.datamodel.DBRefEntry[to
406             .getDBRef().length];
407     int tdblen = to.getDBRef().length;
408     System.arraycopy(to.getDBRef(), 0, tdb, 0, tdblen);
409     Vector matched = new Vector();
410     jalview.util.MapList smapI = smap.getInverse();
411     for (int f = 0; f < fdb.length; f++)
412     {
413       jalview.datamodel.DBRefEntry fe = fdb[f];
414       jalview.datamodel.Mapping fmp = fe.getMap();
415       boolean fmpnnl = fmp != null;
416       // if (fmpnnl && fmp.getTo()!=null)
417       // {
418       // jalview.bin.Cache.log.debug("Not overwriting existing To reference in
419       // "+fe);
420       // continue;
421       // }
422       // smap from maps from fe.local to fe.map
423       boolean smapfromlocal2fe = (fmpnnl) ? smap.equals(fmp.getMap())
424               : false;
425       // smap from maps from fe.map to fe.local.
426       boolean smapfromfemap2local = (fmpnnl) ? smapI.equals(fmp.getMap())
427               : false;
428       for (int t = 0; t < tdblen; t++)
429       {
430         jalview.datamodel.DBRefEntry te = tdb[t];
431         if (te != null)
432         {
433           if (fe.getSource().equals(te.getSource())
434                   && fe.getAccessionId().equals(te.getAccessionId()))
435           {
436             jalview.datamodel.Mapping tmp = te.getMap();
437             boolean tmpnnl = tmp != null;
438             if (tmpnnl && tmp.getTo() != null)
439             {
440
441             }
442             // smap to maps from te.local to te.map
443             boolean smaptolocal2tm = (tmpnnl) ? smap.equals(tmp.getMap())
444                     : false;
445             // smap to maps from te.map to te.local
446             boolean smaptotemap2local = (tmpnnl) ? smapI.equals(fmp
447                     .getMap()) : false;
448             if (smapfromlocal2fe && smaptotemap2local)
449             {
450               // smap implies mapping from to to from
451               fmp.setTo(to);
452               tmp.setTo(from);
453             }
454             else if (smapfromfemap2local && smaptolocal2tm)
455             {
456               fmp.setTo(to);
457             }
458           }
459
460         }
461       }
462     }
463   }
464 }