merge from 2_4_Release branch
[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 public class Sequencemapping extends Rangetype
38 {
39   public Sequencemapping(VamsasAppDatastore datastore,
40           SequenceMapping sequenceMapping)
41   {
42     super(datastore);
43     Object mjvmapping = getvObj2jv(sequenceMapping);
44     if (mjvmapping == null)
45     {
46       add(sequenceMapping);
47     }
48     else
49     {
50       if (sequenceMapping.isUpdated())
51       {
52         update((jalview.util.MapList) mjvmapping, sequenceMapping);
53       }
54     }
55   }
56
57   /**
58    * create or update a vamsas sequence mapping corresponding to a jalview
59    * Mapping between two dataset sequences
60    * 
61    * @param datastore
62    * @param mjvmapping
63    * @param from
64    * @param ds
65    */
66   public Sequencemapping(VamsasAppDatastore datastore,
67           jalview.datamodel.Mapping mjvmapping,
68           uk.ac.vamsas.objects.core.SequenceType from,
69           uk.ac.vamsas.objects.core.DataSet ds)
70   {
71     super(datastore);
72     SequenceMapping sequenceMapping = (SequenceMapping) getjv2vObj(mjvmapping);
73     if (sequenceMapping == null)
74     {
75       add(mjvmapping, from, ds);
76     }
77     else
78     {
79       if (from != null && sequenceMapping.getLoc() != from)
80       {
81         jalview.bin.Cache.log.warn("Probable IMPLEMENTATION ERROR: " + from
82                 + " doesn't match the local mapping sequence.");
83       }
84       if (ds != null && sequenceMapping.is__stored_in_document()
85               && sequenceMapping.getV_parent() != ds)
86       {
87         jalview.bin.Cache.log
88                 .warn("Probable IMPLEMENTATION ERROR: "
89                         + ds
90                         + " doesn't match the parent of the bound sequence mapping object.");
91       }
92       if (sequenceMapping.isUpdated())
93       {
94         conflict(mjvmapping, sequenceMapping);
95       }
96       else
97       {
98         update(mjvmapping, sequenceMapping);
99       }
100     }
101   }
102
103   private void conflict(Mapping mjvmapping, SequenceMapping sequenceMapping)
104   {
105     System.err.println("Conflict in update of sequenceMapping "
106             + sequenceMapping.getVorbaId());
107   }
108
109   private void add(Mapping mjvmapping,
110           uk.ac.vamsas.objects.core.SequenceType from, DataSet ds)
111   {
112     SequenceI jvto = mjvmapping.getTo();
113     while (jvto.getDatasetSequence() != null)
114     {
115       jvto = jvto.getDatasetSequence();
116     }
117     SequenceType to = (SequenceType) getjv2vObj(jvto);
118     if (to == null)
119     {
120       jalview.bin.Cache.log
121               .warn("NONFATAL - do a second update: Ignoring Forward Reference to seuqence not yet bound to vamsas seuqence object");
122       return;
123     }
124     SequenceMapping sequenceMapping = new SequenceMapping();
125     sequenceMapping.setLoc(from);
126     sequenceMapping.setMap(to);
127     boolean dnaToProt = false, sense = false;
128     // ensure that we create a mapping with the correct sense
129     if (((Sequence) sequenceMapping.getLoc()).getDictionary().equals(
130             uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA))
131     {
132       if (((Sequence) sequenceMapping.getMap()).getDictionary().equals(
133               uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_AA))
134       {
135         dnaToProt = true;
136         sense = true;
137       }
138     }
139     else
140     {
141       if (((Sequence) sequenceMapping.getMap()).getDictionary().equals(
142               uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA))
143       {
144         dnaToProt = true;
145         sense = false;
146       }
147     }
148
149     if (!dnaToProt)
150     {
151       jalview.bin.Cache.log
152               .warn("Ignoring Mapping - don't support protein to protein mapping in vamsas document yet.");
153       return;
154     }
155     if (ds == null)
156     {
157       // locate dataset for storage of SequenceMapping
158       if (sense)
159       {
160         ds = (DataSet) ((uk.ac.vamsas.client.Vobject) sequenceMapping
161                 .getLoc()).getV_parent();
162       }
163       else
164       {
165         ds = (DataSet) ((uk.ac.vamsas.client.Vobject) sequenceMapping
166                 .getMap()).getV_parent();
167       }
168     }
169     if (sense)
170     {
171       this.initMapType(sequenceMapping, mjvmapping.getMap(), true);
172     }
173     else
174     {
175       this.initMapType(sequenceMapping, mjvmapping.getMap().getInverse(),
176               true);
177     }
178     ds.addSequenceMapping(sequenceMapping);
179     sequenceMapping.setProvenance(this
180             .dummyProvenance("user defined coding region translation")); // TODO:
181     // correctly
182     // construct
183     // provenance
184     // based
185     // on
186     // source
187     // of
188     // mapping
189     bindjvvobj(mjvmapping, sequenceMapping);
190
191     jalview.bin.Cache.log.debug("Successfully created mapping "
192             + sequenceMapping.getVorbaId());
193   }
194
195   private void update(jalview.util.MapList mjvmapping,
196           SequenceMapping sequenceMapping)
197   {
198     jalview.bin.Cache.log
199             .error("Not implemented: Jalview Update Alcodon Mapping:TODO!");
200   }
201
202   private void update(jalview.datamodel.Mapping mjvmapping,
203           SequenceMapping sequenceMapping)
204   {
205     jalview.bin.Cache.log
206             .error("Not implemented: Jalview Update Sequence DBRef Mapping");
207   }
208
209   /**
210    * limitations: Currently, jalview only deals with mappings between dataset
211    * sequences, and even then, only between those that map from DNA to Protein.
212    * 
213    * @param sequenceMapping
214    */
215   private void add(SequenceMapping sequenceMapping)
216   {
217     Object mobj;
218     SequenceI from = null, to = null;
219     boolean dnaToProt = false, sense = false;
220     Sequence sdloc = null, sdmap = null;
221     if (sequenceMapping.getLoc() instanceof AlignmentSequence)
222     {
223       sdloc = (Sequence) ((AlignmentSequence) sequenceMapping.getLoc())
224               .getRefid();
225     }
226     else
227     {
228       sdloc = ((Sequence) sequenceMapping.getLoc());
229     }
230     if (sequenceMapping.getMap() instanceof AlignmentSequence)
231     {
232       sdmap = (Sequence) ((AlignmentSequence) sequenceMapping.getMap())
233               .getRefid();
234     }
235     else
236     {
237       sdmap = ((Sequence) sequenceMapping.getMap());
238     }
239     if (sdloc == null || sdmap == null)
240     {
241       jalview.bin.Cache.log.info("Ignoring non sequence-sequence mapping");
242       return;
243     }
244     mobj = this.getvObj2jv((Vobject) sdloc);
245     if (mobj instanceof SequenceI)
246     {
247       from = (SequenceI) mobj;
248     }
249     mobj = this.getvObj2jv((Vobject) sdmap);
250     if (mobj instanceof SequenceI)
251     {
252       to = (SequenceI) mobj;
253     }
254     if (from == null || to == null)
255     {
256
257       jalview.bin.Cache.log
258               .error("Probable Vamsas implementation error : unbound dataset sequences involved in a mapping are being parsed!");
259       return;
260     }
261
262     if (sdloc.getDictionary().equals(
263             uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA))
264     {
265       if (sdmap.getDictionary().equals(
266               uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_AA))
267       {
268         dnaToProt = true;
269         sense = true;
270       }
271       // else {
272
273       // }
274     }
275     else
276     {
277       if (sdmap.getDictionary().equals(
278               uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA))
279       {
280         dnaToProt = true;
281         sense = false;
282       }
283     }
284     // create mapping storage object and make each dataset alignment reference
285     // it.
286     jalview.datamodel.AlignmentI dsLoc = (jalview.datamodel.AlignmentI) getvObj2jv(sdloc
287             .getV_parent());
288     jalview.datamodel.AlignmentI dsMap = (jalview.datamodel.AlignmentI) getvObj2jv(sdmap
289             .getV_parent());
290     AlignedCodonFrame afc = new AlignedCodonFrame(0);
291
292     if (dsLoc != null && dsLoc != dsMap)
293     {
294       dsLoc.addCodonFrame(afc);
295     }
296     if (dsMap != null)
297     {
298       dsMap.addCodonFrame(afc);
299     }
300     // create and add the new mapping to (each) dataset's codonFrame
301
302     jalview.util.MapList mapping = null;
303     if (!sense)
304     {
305       mapping = this.parsemapType(sequenceMapping, 1, 3); // invert sense
306       mapping = new jalview.util.MapList(mapping.getToRanges(), mapping
307               .getFromRanges(), mapping.getToRatio(), mapping
308               .getFromRatio());
309       afc.addMap(to, from, mapping);
310     }
311     else
312     {
313       mapping = this.parsemapType(sequenceMapping, 3, 1); // correct sense
314       afc.addMap(from, to, mapping);
315     }
316     bindjvvobj(mapping, sequenceMapping);
317     jalview.structure.StructureSelectionManager
318             .getStructureSelectionManager().addMappings(
319                     new AlignedCodonFrame[]
320                     { afc });
321     // Try to link up any conjugate database references in the two sequences
322     // matchConjugateDBRefs(from, to, mapping);
323     // Try to propagate any dbrefs across this mapping.
324
325   }
326
327   /**
328    * Complete any 'to' references in jalview.datamodel.Mapping objects
329    * associated with conjugate DBRefEntry under given mapping
330    * 
331    * @param from
332    *                sequence corresponding to from reference for sequence
333    *                mapping
334    * @param to
335    *                sequence correspondeing to to reference for sequence mapping
336    * @param smap
337    *                maplist parsed in same sense as from and to
338    */
339   private void matchConjugateDBRefs(SequenceI from, SequenceI to,
340           jalview.util.MapList smap)
341   {
342     if (from.getDBRef() == null && to.getDBRef() == null)
343     {
344       if (jalview.bin.Cache.log.isDebugEnabled())
345       {
346         jalview.bin.Cache.log.debug("Not matching conjugate refs for "
347                 + from.getName() + " and " + to.getName());
348       }
349       return;
350     }
351     if (jalview.bin.Cache.log.isDebugEnabled())
352     {
353       jalview.bin.Cache.log.debug("Matching conjugate refs for "
354               + from.getName() + " and " + to.getName());
355     }
356     jalview.datamodel.DBRefEntry[] fdb = from.getDBRef();
357     jalview.datamodel.DBRefEntry[] tdb = new jalview.datamodel.DBRefEntry[to
358             .getDBRef().length];
359     int tdblen = to.getDBRef().length;
360     System.arraycopy(to.getDBRef(), 0, tdb, 0, tdblen);
361     Vector matched = new Vector();
362     jalview.util.MapList smapI = smap.getInverse();
363     for (int f = 0; f < fdb.length; f++)
364     {
365       jalview.datamodel.DBRefEntry fe = fdb[f];
366       jalview.datamodel.Mapping fmp = fe.getMap();
367       boolean fmpnnl = fmp != null;
368       // if (fmpnnl && fmp.getTo()!=null)
369       // {
370       // jalview.bin.Cache.log.debug("Not overwriting existing To reference in
371       // "+fe);
372       // continue;
373       // }
374       // smap from maps from fe.local to fe.map
375       boolean smapfromlocal2fe = (fmpnnl) ? smap.equals(fmp.getMap())
376               : false;
377       // smap from maps from fe.map to fe.local.
378       boolean smapfromfemap2local = (fmpnnl) ? smapI.equals(fmp.getMap())
379               : false;
380       for (int t = 0; t < tdblen; t++)
381       {
382         jalview.datamodel.DBRefEntry te = tdb[t];
383         if (te != null)
384         {
385           if (fe.getSource().equals(te.getSource())
386                   && fe.getAccessionId().equals(te.getAccessionId()))
387           {
388             jalview.datamodel.Mapping tmp = te.getMap();
389             boolean tmpnnl = tmp != null;
390             if (tmpnnl && tmp.getTo() != null)
391             {
392
393             }
394             // smap to maps from te.local to te.map
395             boolean smaptolocal2tm = (tmpnnl) ? smap.equals(tmp.getMap())
396                     : false;
397             // smap to maps from te.map to te.local
398             boolean smaptotemap2local = (tmpnnl) ? smapI.equals(fmp
399                     .getMap()) : false;
400             if (smapfromlocal2fe && smaptotemap2local)
401             {
402               // smap implies mapping from to to from
403               fmp.setTo(to);
404               tmp.setTo(from);
405             }
406             else if (smapfromfemap2local && smaptolocal2tm)
407             {
408               fmp.setTo(to);
409             }
410           }
411
412         }
413       }
414     }
415   }
416 }