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