JAL-1705 derive transcript sequences from gene sequence/GFF; handle CDS
[jalview.git] / src / jalview / datamodel / 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.datamodel;
22
23 import java.util.HashMap;
24 import java.util.Map;
25 import java.util.Vector;
26
27 /**
28  * DOCUMENT ME!
29  * 
30  * @author $author$
31  * @version $Revision$
32  */
33 public class SequenceFeature
34 {
35   private static final String STATUS = "status";
36
37   private static final String STRAND = "STRAND";
38
39   // private key for Phase designed not to conflict with real GFF data
40   private static final String PHASE = "!Phase";
41
42   private static final String ATTRIBUTES = "ATTRIBUTES";
43
44   public int begin;
45
46   public int end;
47
48   public float score;
49
50   public String type;
51
52   public String description;
53
54   public Map<String, Object> otherDetails;
55
56   public Vector<String> links;
57
58   // Feature group can be set from a features file
59   // as a group of features between STARTGROUP and ENDGROUP markers
60   public String featureGroup;
61
62   public SequenceFeature()
63   {
64   }
65
66   /**
67    * Constructs a duplicate feature. Note: Uses makes a shallow copy of the
68    * otherDetails map, so the new and original SequenceFeature may reference the
69    * same objects in the map.
70    * 
71    * @param cpy
72    */
73   public SequenceFeature(SequenceFeature cpy)
74   {
75     if (cpy != null)
76     {
77       begin = cpy.begin;
78       end = cpy.end;
79       score = cpy.score;
80       if (cpy.type != null)
81       {
82         type = new String(cpy.type);
83       }
84       if (cpy.description != null)
85       {
86         description = new String(cpy.description);
87       }
88       if (cpy.featureGroup != null)
89       {
90         featureGroup = new String(cpy.featureGroup);
91       }
92       if (cpy.otherDetails != null)
93       {
94         try
95         {
96           otherDetails = (Map<String, Object>) ((HashMap<String, Object>) cpy.otherDetails)
97                   .clone();
98         } catch (Exception e)
99         {
100           // ignore
101         }
102       }
103       if (cpy.links != null && cpy.links.size() > 0)
104       {
105         links = new Vector<String>();
106         for (int i = 0, iSize = cpy.links.size(); i < iSize; i++)
107         {
108           links.addElement(cpy.links.elementAt(i));
109         }
110       }
111     }
112   }
113
114   public SequenceFeature(String type, String desc, String status,
115           int begin, int end, String featureGroup)
116   {
117     this.type = type;
118     this.description = desc;
119     setValue(STATUS, status);
120     this.begin = begin;
121     this.end = end;
122     this.featureGroup = featureGroup;
123   }
124
125   public SequenceFeature(String type, String desc, int begin, int end,
126           float score, String featureGroup)
127   {
128     this.type = type;
129     this.description = desc;
130     this.begin = begin;
131     this.end = end;
132     this.score = score;
133     this.featureGroup = featureGroup;
134   }
135
136   public boolean equals(SequenceFeature sf)
137   {
138     if (begin != sf.begin || end != sf.end || score != sf.score)
139     {
140       return false;
141     }
142
143     if (!(type + description + featureGroup).equals(sf.type
144             + sf.description + sf.featureGroup))
145     {
146       return false;
147     }
148
149     return true;
150   }
151
152   /**
153    * DOCUMENT ME!
154    * 
155    * @return DOCUMENT ME!
156    */
157   public int getBegin()
158   {
159     return begin;
160   }
161
162   public void setBegin(int start)
163   {
164     this.begin = start;
165   }
166
167   /**
168    * DOCUMENT ME!
169    * 
170    * @return DOCUMENT ME!
171    */
172   public int getEnd()
173   {
174     return end;
175   }
176
177   public void setEnd(int end)
178   {
179     this.end = end;
180   }
181
182   /**
183    * DOCUMENT ME!
184    * 
185    * @return DOCUMENT ME!
186    */
187   public String getType()
188   {
189     return type;
190   }
191
192   public void setType(String type)
193   {
194     this.type = type;
195   }
196
197   /**
198    * DOCUMENT ME!
199    * 
200    * @return DOCUMENT ME!
201    */
202   public String getDescription()
203   {
204     return description;
205   }
206
207   public void setDescription(String desc)
208   {
209     description = desc;
210   }
211
212   public String getFeatureGroup()
213   {
214     return featureGroup;
215   }
216
217   public void setFeatureGroup(String featureGroup)
218   {
219     this.featureGroup = featureGroup;
220   }
221
222   public void addLink(String labelLink)
223   {
224     if (links == null)
225     {
226       links = new Vector<String>();
227     }
228
229     links.insertElementAt(labelLink, 0);
230   }
231
232   public float getScore()
233   {
234     return score;
235   }
236
237   public void setScore(float value)
238   {
239     score = value;
240   }
241
242   /**
243    * Used for getting values which are not in the basic set. eg STRAND, PHASE
244    * for GFF file
245    * 
246    * @param key
247    *          String
248    */
249   public Object getValue(String key)
250   {
251     if (otherDetails == null)
252     {
253       return null;
254     }
255     else
256     {
257       return otherDetails.get(key);
258     }
259   }
260
261   /**
262    * Returns a property value for the given key if known, else the specified
263    * default value
264    * 
265    * @param key
266    * @param defaultValue
267    * @return
268    */
269   public Object getValue(String key, Object defaultValue)
270   {
271     Object value = getValue(key);
272     return value == null ? defaultValue : value;
273   }
274
275   /**
276    * Used for setting values which are not in the basic set. eg STRAND, FRAME
277    * for GFF file
278    * 
279    * @param key
280    *          eg STRAND
281    * @param value
282    *          eg +
283    */
284   public void setValue(String key, Object value)
285   {
286     if (value != null)
287     {
288       if (otherDetails == null)
289       {
290         otherDetails = new HashMap<String, Object>();
291       }
292
293       otherDetails.put(key, value);
294     }
295   }
296
297   /*
298    * The following methods are added to maintain the castor Uniprot mapping file
299    * for the moment.
300    */
301   public void setStatus(String status)
302   {
303     setValue(STATUS, status);
304   }
305
306   public String getStatus()
307   {
308     return (String) getValue(STATUS);
309   }
310
311   public void setAttributes(String attr)
312   {
313     setValue(ATTRIBUTES, attr);
314   }
315
316   public String getAttributes()
317   {
318     return (String) getValue(ATTRIBUTES);
319   }
320
321   public void setPosition(int pos)
322   {
323     begin = pos;
324     end = pos;
325   }
326
327   public int getPosition()
328   {
329     return begin;
330   }
331
332   /**
333    * Return 1 for forward strand ('+' in GFF), -1 for reverse strand ('-' in
334    * GFF), and 0 for unknown or not (validly) specified
335    * 
336    * @return
337    */
338   public int getStrand()
339   {
340     int strand = 0;
341     if (otherDetails != null)
342     {
343       Object str = otherDetails.get(STRAND);
344       if ("-".equals(str))
345       {
346         strand = -1;
347       }
348       else if ("+".equals(str))
349       {
350         strand = 1;
351       }
352     }
353     return strand;
354   }
355
356   public void setStrand(String strand)
357   {
358     setValue(STRAND, strand);
359   }
360
361   public void setPhase(String phase)
362   {
363     setValue(PHASE, phase);
364   }
365
366   public String getPhase()
367   {
368     return (String) getValue(PHASE);
369   }
370
371   /**
372    * Readable representation, for debug only, not guaranteed not to change
373    * between versions
374    */
375   @Override
376   public String toString()
377   {
378     return String.format("%d %d %s %s", getBegin(), getEnd(), getType(),
379             getDescription());
380   }
381 }