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