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