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