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