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