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