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