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