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