JAL-3253-applet feature parameter processing fixed
[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   @Override
114   public void addToDocument()
115   {
116     add(mjvmapping, from, ds);
117   }
118
119   @Override
120   public void addFromDocument()
121   {
122     add((SequenceMapping) vobj);
123   }
124
125   @Override
126   public void conflict()
127   {
128     conflict(mjvmapping, (SequenceMapping) vobj);
129
130   }
131
132   @Override
133   public void updateToDoc()
134   {
135     update(mjvmapping, (SequenceMapping) vobj);
136   }
137
138   @Override
139   public void updateFromDoc()
140   {
141     update((SequenceMapping) vobj, (jalview.datamodel.Mapping) jvobj);
142   }
143
144   private void conflict(Mapping mjvmapping, SequenceMapping sequenceMapping)
145   {
146     System.err.println("Conflict in update of sequenceMapping "
147             + sequenceMapping.getVorbaId());
148   }
149
150   private void add(Mapping mjvmapping,
151           uk.ac.vamsas.objects.core.SequenceType from, DataSet ds)
152   {
153     SequenceI jvto = mjvmapping.getTo();
154     while (jvto.getDatasetSequence() != null)
155     {
156       jvto = jvto.getDatasetSequence();
157     }
158     SequenceType to = (SequenceType) getjv2vObj(jvto);
159     if (to == null)
160     {
161       jalview.bin.Cache.log.warn(
162               "FIXME NONFATAL - do a second update: Ignoring Forward Reference to seuqence not yet bound to vamsas seuqence object");
163       return;
164     }
165     SequenceMapping sequenceMapping = new SequenceMapping();
166     sequenceMapping.setLoc(from);
167     sequenceMapping.setMap(to);
168     boolean dnaToProt = false, sense = false;
169     // ensure that we create a mapping with the correct sense
170     if (((Sequence) sequenceMapping.getLoc()).getDictionary().equals(
171             uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA))
172     {
173       if (((Sequence) sequenceMapping.getMap()).getDictionary().equals(
174               uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_AA))
175       {
176         dnaToProt = true;
177         sense = true;
178       }
179     }
180     else
181     {
182       if (((Sequence) sequenceMapping.getMap()).getDictionary().equals(
183               uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA))
184       {
185         dnaToProt = true;
186         sense = false;
187       }
188     }
189
190     if (!dnaToProt)
191     {
192       jalview.bin.Cache.log.warn(
193               "Ignoring Mapping - don't support protein to protein mapping in vamsas document yet.");
194       return;
195     }
196     if (ds == null)
197     {
198       // locate dataset for storage of SequenceMapping
199       if (sense)
200       {
201         ds = (DataSet) ((uk.ac.vamsas.client.Vobject) sequenceMapping
202                 .getLoc()).getV_parent();
203       }
204       else
205       {
206         ds = (DataSet) ((uk.ac.vamsas.client.Vobject) sequenceMapping
207                 .getMap()).getV_parent();
208       }
209     }
210     if (sense)
211     {
212       this.initMapType(sequenceMapping, mjvmapping.getMap(), true);
213     }
214     else
215     {
216       this.initMapType(sequenceMapping, mjvmapping.getMap().getInverse(),
217               true);
218     }
219     ds.addSequenceMapping(sequenceMapping);
220     sequenceMapping.setProvenance(
221             this.dummyProvenance("user defined coding region translation")); // TODO:
222     // correctly
223     // construct
224     // provenance
225     // based
226     // on
227     // source
228     // of
229     // mapping
230     bindjvvobj(mjvmapping.getMap(), sequenceMapping);
231
232     jalview.bin.Cache.log.debug(
233             "Successfully created mapping " + sequenceMapping.getVorbaId());
234   }
235
236   // private void update(jalview.util.MapList mjvmapping,
237   // SequenceMapping sequenceMapping)
238   {
239     jalview.bin.Cache.log
240             .error("Not implemented: Jalview Update Alcodon Mapping:TODO!");
241   }
242
243   private void update(SequenceMapping sequenceMapping,
244           jalview.datamodel.Mapping mjvmapping)
245   {
246     jalview.bin.Cache.log
247             .error("Not implemented: Update DBRef Mapping from Jalview");
248   }
249
250   private void update(jalview.datamodel.Mapping mjvmapping,
251           SequenceMapping sequenceMapping)
252   {
253     jalview.bin.Cache.log.error(
254             "Not implemented: Jalview Update Sequence DBRef Mapping");
255   }
256
257   /**
258    * bind a SequenceMapping to a live AlCodonFrame element limitations:
259    * Currently, jalview only deals with mappings between dataset sequences, and
260    * even then, only between those that map from DNA to Protein.
261    * 
262    * @param sequenceMapping
263    */
264   private void add(SequenceMapping sequenceMapping)
265   {
266     Object mobj;
267     SequenceI from = null, to = null;
268     boolean dnaToProt = false, sense = false;
269     Sequence sdloc = null, sdmap = null;
270     if (sequenceMapping.getLoc() instanceof AlignmentSequence)
271     {
272       sdloc = (Sequence) ((AlignmentSequence) sequenceMapping.getLoc())
273               .getRefid();
274     }
275     else
276     {
277       sdloc = ((Sequence) sequenceMapping.getLoc());
278     }
279     if (sequenceMapping.getMap() instanceof AlignmentSequence)
280     {
281       sdmap = (Sequence) ((AlignmentSequence) sequenceMapping.getMap())
282               .getRefid();
283     }
284     else
285     {
286       sdmap = ((Sequence) sequenceMapping.getMap());
287     }
288     if (sdloc == null || sdmap == null)
289     {
290       jalview.bin.Cache.log.info("Ignoring non sequence-sequence mapping");
291       return;
292     }
293     mobj = this.getvObj2jv(sdloc);
294     if (mobj instanceof SequenceI)
295     {
296       from = (SequenceI) mobj;
297     }
298     mobj = this.getvObj2jv(sdmap);
299     if (mobj instanceof SequenceI)
300     {
301       to = (SequenceI) mobj;
302     }
303     if (from == null || to == null)
304     {
305
306       jalview.bin.Cache.log.error(
307               "Probable Vamsas implementation error : unbound dataset sequences involved in a mapping are being parsed!");
308       return;
309     }
310
311     if (sdloc.getDictionary().equals(
312             uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA))
313     {
314       if (sdmap.getDictionary().equals(
315               uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_AA))
316       {
317         dnaToProt = true;
318         sense = true;
319       }
320       // else {
321
322       // }
323     }
324     else
325     {
326       if (sdmap.getDictionary().equals(
327               uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA))
328       {
329         dnaToProt = true;
330         sense = false;
331       }
332     }
333     // create mapping storage object and make each dataset alignment reference
334     // it.
335     AlignmentI dsLoc = (AlignmentI) getvObj2jv(sdloc.getV_parent());
336     AlignmentI dsMap = (AlignmentI) getvObj2jv(sdmap.getV_parent());
337     AlignedCodonFrame acf = new AlignedCodonFrame();
338
339     if (dsLoc != null && dsLoc != dsMap)
340     {
341       dsLoc.addCodonFrame(acf);
342     }
343     if (dsMap != null)
344     {
345       dsMap.addCodonFrame(acf);
346     }
347     // create and add the new mapping to (each) dataset's codonFrame
348
349     jalview.util.MapList mapping = null;
350     if (dnaToProt)
351     {
352       if (!sense)
353       {
354         mapping = this.parsemapType(sequenceMapping, 1, 3); // invert sense
355         mapping = new jalview.util.MapList(mapping.getToRanges(),
356                 mapping.getFromRanges(), mapping.getToRatio(),
357                 mapping.getFromRatio());
358         acf.addMap(to, from, mapping);
359       }
360       else
361       {
362         mapping = this.parsemapType(sequenceMapping, 3, 1); // correct sense
363         acf.addMap(from, to, mapping);
364       }
365     }
366     else
367     {
368       mapping = this.parsemapType(sequenceMapping, 1, 1); // correct sense
369       acf.addMap(from, to, mapping);
370     }
371     bindjvvobj(mapping, sequenceMapping);
372     Desktop.getInstance().getStructureSelectionManager()
373             .registerMapping(acf);
374     // Try to link up any conjugate database references in the two sequences
375     // matchConjugateDBRefs(from, to, mapping);
376     // Try to propagate any dbrefs across this mapping.
377
378   }
379
380   /**
381    * Complete any 'to' references in jalview.datamodel.Mapping objects
382    * associated with conjugate DBRefEntry under given mapping
383    * 
384    * @param from
385    *          sequence corresponding to from reference for sequence mapping
386    * @param to
387    *          sequence correspondeing to to reference for sequence mapping
388    * @param smap
389    *          maplist parsed in same sense as from and to
390    */
391   private void matchConjugateDBRefs(SequenceI from, SequenceI to,
392           jalview.util.MapList smap)
393   {
394     if (from.getDBRefs() == null && to.getDBRefs() == null)
395     {
396       if (jalview.bin.Cache.log.isDebugEnabled())
397       {
398         jalview.bin.Cache.log.debug("Not matching conjugate refs for "
399                 + from.getName() + " and " + to.getName());
400       }
401       return;
402     }
403     if (jalview.bin.Cache.log.isDebugEnabled())
404     {
405       jalview.bin.Cache.log.debug("Matching conjugate refs for "
406               + from.getName() + " and " + to.getName());
407     }
408     List<DBRefEntry> fdb = from.getDBRefs();
409     List<DBRefEntry> tdb = new ArrayList<>(to.getDBRefs());
410     int tdblen = to.getDBRefs().size();
411 //    
412 //    
413 //    YOWSER
414 //    
415 //    System.arraycopy(to.getDBRefs(), 0, tdb, 0, tdblen);
416 //    
417 //    
418 //    
419 //    
420     Vector matched = new Vector();
421     jalview.util.MapList smapI = smap.getInverse();
422     for (int f = 0, fn = fdb.size(); f < fn; f++)
423     {
424       jalview.datamodel.DBRefEntry fe = fdb.get(f);
425       jalview.datamodel.Mapping fmp = fe.getMap();
426       boolean fmpnnl = (fmp != null);
427       // if (fmpnnl && fmp.getTo()!=null)
428       // {
429       // jalview.bin.Cache.log.debug("Not overwriting existing To reference in
430       // "+fe);
431       // continue;
432       // }
433       // smap from maps from fe.local to fe.map
434       boolean smapfromlocal2fe = (fmpnnl) ? smap.equals(fmp.getMap())
435               : false;
436       // smap from maps from fe.map to fe.local.
437       boolean smapfromfemap2local = (fmpnnl) ? smapI.equals(fmp.getMap())
438               : false;
439       for (int t = 0; t < tdblen; t++)
440       {
441         jalview.datamodel.DBRefEntry te = tdb.get(t);
442         if (te != null)
443         {
444           if (fe.getSource().equals(te.getSource())
445                   && fe.getAccessionId().equals(te.getAccessionId()))
446           {
447             jalview.datamodel.Mapping tmp = te.getMap();
448             boolean tmpnnl = tmp != null;
449             if (tmpnnl && tmp.getTo() != null)
450             {
451
452             }
453             // smap to maps from te.local to te.map
454             boolean smaptolocal2tm = (tmpnnl) ? smap.equals(tmp.getMap())
455                     : false;
456             // smap to maps from te.map to te.local
457             boolean smaptotemap2local = (tmpnnl)
458                     ? smapI.equals(fmp.getMap())
459                     : false;
460             if (smapfromlocal2fe && smaptotemap2local)
461             {
462               // smap implies mapping from to to from
463               fmp.setTo(to);
464               tmp.setTo(from);
465             }
466             else if (smapfromfemap2local && smaptolocal2tm)
467             {
468               fmp.setTo(to);
469             }
470           }
471
472         }
473       }
474     }
475   }
476 }