JAL-2480 test coverage / bug fixes / javadoc
[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.Arrays;
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.Map.Entry;
12 import java.util.Set;
13
14 /**
15  * A class that stores sequence features in a way that supports efficient
16  * querying by type and location (overlap). Intended for (but not limited to)
17  * storage of features for one sequence.
18  * 
19  * @author gmcarstairs
20  *
21  */
22 public class SequenceFeatures implements SequenceFeaturesI
23 {
24
25   /*
26    * map from feature type to structured store of features for that type
27    * null types are permitted (but not a good idea!)
28    */
29   private Map<String, FeatureStore> featureStore;
30
31   /**
32    * Constructor
33    */
34   public SequenceFeatures()
35   {
36     featureStore = new HashMap<String, FeatureStore>();
37   }
38
39   /**
40    * {@inheritDoc}
41    */
42   @Override
43   public boolean add(SequenceFeature sf)
44   {
45     String type = sf.getType();
46
47     if (featureStore.get(type) == null)
48     {
49       featureStore.put(type, new FeatureStore());
50     }
51     return featureStore.get(type).addFeature(sf);
52   }
53
54   /**
55    * {@inheritDoc}
56    */
57   @Override
58   public List<SequenceFeature> findFeatures(int from, int to,
59           String... type)
60   {
61     List<SequenceFeature> result = new ArrayList<SequenceFeature>();
62
63     for (String featureType : varargToTypes(type))
64     {
65       FeatureStore features = featureStore.get(featureType);
66       if (features != null)
67       {
68         result.addAll(features.findOverlappingFeatures(from, to));
69       }
70     }
71
72     return result;
73   }
74
75   /**
76    * {@inheritDoc}
77    */
78   @Override
79   public List<SequenceFeature> getAllFeatures(String... type)
80   {
81     List<SequenceFeature> result = new ArrayList<SequenceFeature>();
82
83     result.addAll(getPositionalFeatures(type));
84
85     result.addAll(getNonPositionalFeatures(type));
86
87     return result;
88   }
89
90   /**
91    * {@inheritDoc}
92    */
93   @Override
94   public int getFeatureCount(boolean positional, String... type)
95   {
96     int result = 0;
97
98     for (String featureType : varargToTypes(type))
99     {
100       FeatureStore featureSet = featureStore.get(featureType);
101       if (featureSet != null)
102       {
103         result += featureSet.getFeatureCount(positional);
104       }
105     }
106     return result;
107   }
108
109   /**
110    * {@inheritDoc}
111    */
112   @Override
113   public List<SequenceFeature> getPositionalFeatures(String... type)
114   {
115     List<SequenceFeature> result = new ArrayList<SequenceFeature>();
116
117     for (String featureType : varargToTypes(type))
118     {
119       FeatureStore featureSet = featureStore.get(featureType);
120       if (featureSet != null)
121       {
122         result.addAll(featureSet.getPositionalFeatures());
123       }
124     }
125     return result;
126   }
127
128   /**
129    * A convenience method that converts a vararg for feature types to an
130    * Iterable, replacing the value with the stored feature types if it is null
131    * or empty
132    * 
133    * @param type
134    * @return
135    */
136   protected Iterable<String> varargToTypes(String... type)
137   {
138     return type == null || type.length == 0 ? featureStore
139             .keySet() : Arrays.asList(type);
140   }
141
142   /**
143    * {@inheritDoc}
144    */
145   @Override
146   public List<SequenceFeature> getContactFeatures(String... type)
147   {
148     List<SequenceFeature> result = new ArrayList<SequenceFeature>();
149
150     for (String featureType : varargToTypes(type))
151     {
152       FeatureStore featureSet = featureStore.get(featureType);
153       if (featureSet != null)
154       {
155         result.addAll(featureSet.getContactFeatures());
156       }
157     }
158     return result;
159   }
160
161   /**
162    * {@inheritDoc}
163    */
164   @Override
165   public List<SequenceFeature> getNonPositionalFeatures(String... type)
166   {
167     List<SequenceFeature> result = new ArrayList<SequenceFeature>();
168
169     for (String featureType : varargToTypes(type))
170     {
171       FeatureStore featureSet = featureStore.get(featureType);
172       if (featureSet != null)
173       {
174         result.addAll(featureSet.getNonPositionalFeatures());
175       }
176     }
177     return result;
178   }
179
180   /**
181    * {@inheritDoc}
182    */
183   @Override
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    * {@inheritDoc}
198    */
199   @Override
200   public boolean hasFeatures()
201   {
202     for (FeatureStore featureSet : featureStore.values())
203     {
204       if (!featureSet.isEmpty())
205       {
206         return true;
207       }
208     }
209     return false;
210   }
211
212   /**
213    * {@inheritDoc}
214    */
215   @Override
216   public Set<String> getFeatureGroups(boolean positionalFeatures,
217           String... type)
218   {
219     Set<String> groups = new HashSet<String>();
220
221     Iterable<String> types = varargToTypes(type);
222
223     for (String featureType : types)
224     {
225       FeatureStore featureSet = featureStore.get(featureType);
226       if (featureSet != null)
227       {
228         groups.addAll(featureSet.getFeatureGroups(positionalFeatures));
229       }
230     }
231
232     return groups;
233   }
234
235   /**
236    * {@inheritDoc}
237    */
238   @Override
239   public Set<String> getFeatureTypesForGroups(boolean positionalFeatures,
240           String... groups)
241   {
242     Set<String> result = new HashSet<String>();
243
244     for (Entry<String, FeatureStore> featureType : featureStore.entrySet())
245     {
246       Set<String> featureGroups = featureType.getValue().getFeatureGroups(
247               positionalFeatures);
248       for (String group : groups)
249       {
250         if (featureGroups.contains(group))
251         {
252           /*
253            * yes this feature type includes one of the query groups
254            */
255           result.add(featureType.getKey());
256           break;
257         }
258       }
259     }
260
261     return result;
262   }
263
264   /**
265    * {@inheritDoc}
266    */
267   @Override
268   public Set<String> getFeatureTypes()
269   {
270     Set<String> types = new HashSet<String>();
271     for (Entry<String, FeatureStore> entry : featureStore.entrySet())
272     {
273       if (!entry.getValue().isEmpty())
274       {
275         types.add(entry.getKey());
276       }
277     }
278     return types;
279   }
280 }