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