JAL-2446 added getFeatureGroups
[jalview.git] / src / jalview / datamodel / features / SequenceFeatures.java
1 package jalview.datamodel.features;
2
3 import jalview.datamodel.SequenceFeature;
4
5 import java.util.ArrayList;
6 import java.util.Collections;
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.Set;
12
13 /**
14  * A class that stores sequence features in a way that supports efficient
15  * querying by type and location (overlap). Intended for (but not limited to)
16  * storage of features for one sequence.
17  * 
18  * @author gmcarstairs
19  *
20  */
21 public class SequenceFeatures
22 {
23
24   /*
25    * map from feature type to structured store of features for that type
26    * null types are permitted (but not a good idea!)
27    */
28   private Map<String, FeatureStore> featureStore;
29
30   /**
31    * Constructor
32    */
33   public SequenceFeatures()
34   {
35     featureStore = new HashMap<String, FeatureStore>();
36   }
37
38   /**
39    * Adds one sequence feature to the store, and returns true, unless the
40    * feature is already contained in the store, in which case this method
41    * returns false. Containment is determined by SequenceFeature.equals()
42    * comparison.
43    * 
44    * @param sf
45    */
46   public boolean add(SequenceFeature sf)
47   {
48     String type = sf.getType();
49
50     if (featureStore.get(type) == null)
51     {
52       featureStore.put(type, new FeatureStore());
53     }
54     return featureStore.get(type).addFeature(sf);
55   }
56
57   /**
58    * Returns a (possibly empty) list of features of the given type which overlap
59    * the (inclusive) sequence position range
60    * 
61    * @param type
62    * @param from
63    * @param to
64    * @return
65    */
66   public List<SequenceFeature> findFeatures(String type, int from,
67           int to)
68   {
69     FeatureStore features = featureStore.get(type);
70     if (features == null)
71     {
72       return Collections.emptyList();
73     }
74     return features.findOverlappingFeatures(from, to);
75   }
76
77   /**
78    * Answers a list of all features stored (including non-positional), in no
79    * particular guaranteed order
80    * 
81    * @return
82    */
83   public List<SequenceFeature> getFeatures()
84   {
85     List<SequenceFeature> result = new ArrayList<SequenceFeature>();
86     for (FeatureStore featureSet : featureStore.values())
87     {
88       result.addAll(featureSet.getFeatures());
89     }
90     return result;
91   }
92
93   /**
94    * Answers a list of all non-positional features stored, in no particular
95    * guaranteed order
96    * 
97    * @return
98    */
99   public List<SequenceFeature> getNonPositionalFeatures()
100   {
101     List<SequenceFeature> result = new ArrayList<SequenceFeature>();
102     for (FeatureStore featureSet : featureStore.values())
103     {
104       result.addAll(featureSet.getNonPositionalFeatures());
105     }
106     return result;
107   }
108
109   /**
110    * Answers a list of all contact features stored, in no particular guaranteed
111    * order
112    * 
113    * @return
114    */
115   public List<SequenceFeature> getContactFeatures()
116   {
117     List<SequenceFeature> result = new ArrayList<SequenceFeature>();
118     for (FeatureStore featureSet : featureStore.values())
119     {
120       result.addAll(featureSet.getContactFeatures());
121     }
122     return result;
123   }
124
125   /**
126    * Answers a list of all features of the given type (including
127    * non-positional), in no particular guaranteed order
128    * 
129    * @return
130    */
131   public List<SequenceFeature> getFeatures(String type)
132   {
133     List<SequenceFeature> result = new ArrayList<SequenceFeature>();
134     FeatureStore featureSet = featureStore.get(type);
135     if (featureSet != null)
136     {
137       result.addAll(featureSet.getFeatures());
138     }
139     return result;
140   }
141
142   /**
143    * Answers a list of all contact features of the given type, in no particular
144    * guaranteed order
145    * 
146    * @return
147    */
148   public List<SequenceFeature> getContactFeatures(String type)
149   {
150     List<SequenceFeature> result = new ArrayList<SequenceFeature>();
151     FeatureStore featureSet = featureStore.get(type);
152     if (featureSet != null)
153     {
154       result.addAll(featureSet.getContactFeatures());
155     }
156     return result;
157   }
158
159   /**
160    * Answers a list of all non-positional features of the given type, in no
161    * particular guaranteed order
162    * 
163    * @return
164    */
165   public List<SequenceFeature> getNonPositionalFeatures(String type)
166   {
167     List<SequenceFeature> result = new ArrayList<SequenceFeature>();
168     FeatureStore featureSet = featureStore.get(type);
169     if (featureSet != null)
170     {
171       result.addAll(featureSet.getNonPositionalFeatures());
172     }
173     return result;
174   }
175
176   /**
177    * Deletes the given feature from the store, returning true if it was found
178    * (and deleted), else false. This method makes no assumption that the feature
179    * is in the 'expected' place in the store, in case it has been modified since
180    * it was added.
181    * 
182    * @param sf
183    */
184   public boolean delete(SequenceFeature sf)
185   {
186     for (FeatureStore featureSet : featureStore.values())
187     {
188       if (featureSet.delete(sf))
189       {
190         return true;
191       }
192     }
193     return false;
194   }
195
196   /**
197    * Answers true if this store contains at least one feature, else false
198    * 
199    * @return
200    */
201   public boolean hasFeatures()
202   {
203     for (FeatureStore featureSet : featureStore.values())
204     {
205       if (!featureSet.isEmpty())
206       {
207         return true;
208       }
209     }
210     return false;
211   }
212
213   /**
214    * Returns a set of the distinct feature groups present in the collection. The
215    * set may include null.
216    * 
217    * @return
218    */
219   public Set<String> getFeatureGroups()
220   {
221     Set<String> groups = new HashSet<String>();
222     for (FeatureStore featureSet : featureStore.values())
223     {
224       groups.addAll(featureSet.getFeatureGroups());
225     }
226     return groups;
227   }
228 }