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