f02fe3ef7ab000fdb582deb3c08301d97b9c4416
[jalview.git] / src / jalview / io / vamsas / Sequencefeature.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3  * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
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 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.io.vamsas;
19
20 import java.util.Enumeration;
21 import java.util.Vector;
22
23 import uk.ac.vamsas.objects.core.DataSet;
24 import uk.ac.vamsas.objects.core.DataSetAnnotations;
25 import uk.ac.vamsas.objects.core.Link;
26 import uk.ac.vamsas.objects.core.Property;
27 import uk.ac.vamsas.objects.core.Provenance;
28 import uk.ac.vamsas.objects.core.RangeAnnotation;
29 import uk.ac.vamsas.objects.core.Score;
30 import uk.ac.vamsas.objects.core.Seg;
31 import uk.ac.vamsas.objects.core.Sequence;
32 import uk.ac.vamsas.objects.utils.Properties;
33 import jalview.bin.Cache;
34 import jalview.datamodel.SequenceFeature;
35 import jalview.datamodel.SequenceI;
36 import jalview.io.VamsasAppDatastore;
37 import jalview.util.UrlLink;
38
39 /**
40  * @author JimP
41  * 
42  */
43 public class Sequencefeature extends Rangetype
44 {
45
46   uk.ac.vamsas.objects.core.DataSet dataset;
47
48   uk.ac.vamsas.objects.core.Sequence sequence;
49
50   private SequenceI dsSeq;
51
52   public Sequencefeature(VamsasAppDatastore vamsasAppDatastore,
53           SequenceFeature sequenceFeature,
54           uk.ac.vamsas.objects.core.DataSet dataset,
55           uk.ac.vamsas.objects.core.Sequence sequence)
56   {
57     super(vamsasAppDatastore, sequenceFeature, DataSetAnnotations.class);
58     this.dataset = dataset;
59     this.sequence = sequence;
60     doSync();
61   }
62
63   public Sequencefeature(VamsasAppDatastore vamsasAppDatastore,
64           DataSetAnnotations dseta, SequenceI dsSeq)
65   {
66     super(vamsasAppDatastore, dseta,
67             jalview.datamodel.SequenceFeature.class);
68     this.dsSeq = dsSeq;
69     doJvUpdate();
70   }
71
72   public void addToDocument()
73   {
74     DataSetAnnotations dsa = (DataSetAnnotations) vobj;
75     jalview.datamodel.SequenceFeature feature = (jalview.datamodel.SequenceFeature) jvobj;
76     dsa = (DataSetAnnotations) getDSAnnotationFromJalview(
77             new DataSetAnnotations(), feature);
78     if (dsa.getProvenance() == null)
79     {
80       dsa.setProvenance(new Provenance());
81     }
82     addProvenance(dsa.getProvenance(), "created"); // JBPNote - need
83     // to update
84     dsa.addSeqRef(sequence); // we have just created this annotation
85     // - so safe to use this
86     bindjvvobj(feature, dsa);
87     dataset.addDataSetAnnotations(dsa);
88   }
89
90   public void addFromDocument()
91   {
92     DataSetAnnotations dsa = (DataSetAnnotations) vobj;
93     if (dsa.getSeqRefCount() != 1)
94     {
95       Cache.log
96               .warn("Not binding "
97                       + dsa.getVorbaId()
98                       + " to Sequence Feature - has multiple dataset sequence references.");
99       return;
100     }
101     jalview.datamodel.SequenceFeature sf = (jalview.datamodel.SequenceFeature) jvobj;
102     dsSeq.addSequenceFeature(sf = getJalviewSeqFeature(dsa));
103     jvobj = sf;
104     bindjvvobj(sf, dsa);
105   }
106
107   public void conflict()
108   {
109     log.warn("Untested sequencefeature conflict code");
110     DataSetAnnotations dsa = (DataSetAnnotations) vobj;
111     jalview.datamodel.SequenceFeature feature = (jalview.datamodel.SequenceFeature) jvobj;
112     jalview.datamodel.SequenceFeature sf = getJalviewSeqFeature(dsa);
113     replaceJvObjMapping(feature, sf); // switch binding of dsa from old feature
114                                       // to newly created feature
115     dsSeq.addSequenceFeature(sf); // add new imported feature
116     addToDocument(); // and create a new feature in the document
117   }
118
119   public void updateToDoc()
120   {
121     DataSetAnnotations dsa = (DataSetAnnotations) vobj;
122     jalview.datamodel.SequenceFeature feature = (jalview.datamodel.SequenceFeature) jvobj;
123     if (dsa.getSeqRefCount() != 1)
124     {
125       replaceJvObjMapping(feature, null);
126       Cache.log
127               .warn("Binding of annotation to jalview feature has changed. Removing binding and recreating.");
128       doSync(); // re-verify bindings.
129     }
130     else
131     {
132       // Sync the features from Jalview
133       long oldref = dsa.get__last_hash();
134       getDSAnnotationFromJalview(dsa, feature);
135       if (oldref != dsa.hashCode())
136       {
137         Cache.log
138                 .debug("Updated dataset sequence annotation from feature.");
139         addProvenance(dsa.getProvenance(), "modified");
140       }
141     }
142
143   }
144
145   public void updateFromDoc()
146   {
147     DataSetAnnotations dsa = (DataSetAnnotations) vobj;
148     jalview.datamodel.SequenceFeature feature = (jalview.datamodel.SequenceFeature) jvobj;
149     if (dsa.getSeqRefCount() != 1)
150     {
151       // conflicting update from document - we cannot map this feature anymore.
152       replaceJvObjMapping(feature, null);
153       Cache.log
154               .warn("annotation ("
155                       + dsa.getVorbaId()
156                       + " bound to jalview feature cannot be mapped. Removing binding, deleting feature, and deleting feature.");
157       // - consider deleting the feature ?
158       dsSeq.deleteFeature(feature);
159       // doSync();
160     }
161     else
162     {
163       // Sync the features to Jalview - easiest to delete and add the feature
164       // again
165       jalview.datamodel.SequenceFeature newsf = getJalviewSeqFeature(dsa);
166       dsSeq.deleteFeature(feature);
167       replaceJvObjMapping(feature, newsf);
168       dsSeq.addSequenceFeature(newsf);
169       if (feature.otherDetails != null)
170       {
171         // TODO later: leave this to finalise method ?
172         feature.otherDetails.clear();
173       }
174     }
175   }
176
177   /**
178    * correctly create/update a RangeAnnotation from a jalview sequence feature
179    * TODO: refactor to a method in jalview.io.vamsas.RangeAnnotation class
180    * 
181    * @param dsa
182    *          (typically DataSetAnnotations or AlignmentSequenceAnnotation)
183    * @param feature
184    *          (the feature to be mapped from)
185    * @return
186    */
187   private RangeAnnotation getDSAnnotationFromJalview(RangeAnnotation dsa,
188           jalview.datamodel.SequenceFeature feature)
189   {
190     dsa.setType(feature.getType());
191     Seg vSeg = new Seg();
192     vSeg.setStart(feature.getBegin());
193     vSeg.setEnd(feature.getEnd());
194     vSeg.setInclusive(true);
195     if (dsa.getSegCount() > 1)
196     {
197       Cache.log
198               .debug("About to destroy complex annotation in vamsas document mapped to sequence feature ("
199                       + dsa.getVorbaId() + ")");
200     }
201     dsa.setSeg(new Seg[]
202     { vSeg });
203     dsa.setDescription(feature.getDescription());
204     dsa.setStatus(feature.getStatus());
205     if (feature.links != null && feature.links.size() > 0)
206     {
207       for (int i = 0, iSize = feature.links.size(); i < iSize; i++)
208       {
209         String link = (String) feature.links.elementAt(i);
210         UrlLink ulink = new UrlLink(link);
211         if (ulink.isValid())
212         {
213           // We only add static links to the document.
214           Link vLink = new Link();
215           vLink.setContent(ulink.getLabel());
216           vLink.setHref(ulink.getTarget());
217           dsa.addLink(vLink);
218         }
219       }
220     }
221     dsa.setGroup(feature.getFeatureGroup());
222     if (feature.getScore() != Float.NaN)
223     {
224       Score fscore = new Score();
225       dsa.setScore(new Score[]
226       { fscore });
227       fscore.setContent(feature.getScore());
228       fscore.setName(feature.getType());
229     }
230     if (feature.otherDetails != null)
231     {
232       Enumeration iter = feature.otherDetails.keys();
233       Vector props = dsa.getPropertyAsReference();
234       while (iter.hasMoreElements())
235       {
236         String key = (String) iter.nextElement();
237         if (!key.equalsIgnoreCase("score")
238                 && !key.equalsIgnoreCase("status"))
239         {
240           Property nprop = new Property();
241           nprop.setName(key);
242           Object vlu = feature.getValue(key);
243           nprop.setContent(feature.getValue(key).toString());
244           boolean valid = false;
245           if (vlu instanceof String)
246           {
247             nprop.setType(uk.ac.vamsas.objects.utils.Properties.STRINGTYPE);
248             valid = true;
249           }
250           else if (vlu instanceof Integer)
251           {
252             valid = true;
253             nprop.setType(uk.ac.vamsas.objects.utils.Properties.INTEGERTYPE);
254           }
255           else if (vlu instanceof Float)
256           {
257             nprop.setType(uk.ac.vamsas.objects.utils.Properties.FLOATTYPE);
258             valid = true;
259           }
260           if (valid)
261           {
262             if (props != null)
263             {
264               uk.ac.vamsas.objects.utils.Properties.addOrReplace(props,
265                       nprop);
266             }
267             else
268             {
269               dsa.addProperty(nprop);
270             }
271           }
272         }
273       }
274     }
275     return dsa;
276   }
277
278   private SequenceFeature getJalviewSeqFeature(RangeAnnotation dseta)
279   {
280     int[] se = getBounds(dseta);
281     SequenceFeature sf = new jalview.datamodel.SequenceFeature(
282             dseta.getType(), dseta.getDescription(), dseta.getStatus(),
283             se[0], se[1], dseta.getGroup());
284     if (dseta.getLinkCount() > 0)
285     {
286       Link[] links = dseta.getLink();
287       for (int i = 0; i < links.length; i++)
288       {
289         // TODO: use URLLink parsing/validation here.
290         sf.addLink(links[i].getContent() + "|" + links[i].getHref());
291       }
292     }
293     if (dseta.getScoreCount() > 0)
294     {
295       Enumeration scr = dseta.enumerateScore();
296       while (scr.hasMoreElements())
297       {
298         Score score = (Score) scr.nextElement();
299         if (score.getName().equals(sf.getType()))
300         {
301           sf.setScore(score.getContent());
302         }
303         else
304         {
305           sf.setValue(score.getName(), "" + score.getContent());
306         }
307       }
308     }
309     // other details
310     Enumeration props = dseta.enumerateProperty();
311     while (props.hasMoreElements())
312     {
313       Property p = (Property) props.nextElement();
314       Object val = null;
315       if (Properties.isValid(p))
316       {
317         if (Properties.isString(p))
318         {
319           val = p.getContent();
320         }
321         if (Properties.isBoolean(p))
322         {
323           try
324           {
325             val = new Boolean(p.getContent());
326           } catch (Exception e)
327           {
328           }
329         }
330         if (Properties.isFloat(p))
331         {
332           try
333           {
334             val = new Float(p.getContent());
335
336           } catch (Exception e)
337           {
338           }
339         }
340         if (Properties.isInteger(p))
341         {
342           try
343           {
344             val = new Integer(p.getContent());
345           } catch (Exception e)
346           {
347           }
348         }
349         if (val != null)
350         {
351           sf.setValue(p.getName(), val);
352         }
353       }
354     }
355
356     return sf;
357   }
358
359 }