JAL-2808 JAL-2069 record feature attributes descriptions and min-max
[jalview.git] / src / jalview / datamodel / features / FeatureAttributes.java
1 package jalview.datamodel.features;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.TreeMap;
9
10 /**
11  * A singleton class to hold the set of attributes known for each feature type
12  */
13 public class FeatureAttributes
14 {
15   private static FeatureAttributes instance = new FeatureAttributes();
16
17   private Map<String, Map<String, AttributeData>> attributes;
18
19   private class AttributeData
20   {
21     /*
22      * description(s) for this attribute, if known
23      * (different feature source might have differing descriptions)
24      */
25     List<String> description;
26
27     /*
28      * minimum value (of any numeric values recorded)
29      */
30     float min = 0f;
31
32     /*
33      * maximum value (of any numeric values recorded)
34      */
35     float max = 0f;
36
37     /**
38      * Note one instance of this attribute, recording unique, non-null names,
39      * and the min/max of any numerical values
40      * 
41      * @param desc
42      * @param value
43      */
44     void addInstance(String desc, String value)
45     {
46       if (desc != null)
47       {
48         if (description == null)
49         {
50           description = new ArrayList<>();
51         }
52         if (!description.contains(desc))
53         {
54           description.add(desc);
55         }
56         if (value != null)
57         {
58           try
59           {
60             float f = Float.valueOf(value);
61             min = Float.min(min, f);
62             max = Float.max(max, f);
63           } catch (NumberFormatException e)
64           {
65             // ok, wasn't a number
66           }
67         }
68       }
69     }
70
71     /**
72      * Answers the description of the attribute, if recorded and unique, or null if either no, or more than description is recorded
73      * @return
74      */
75     public String getDescription()
76     {
77       if (description != null && description.size() == 1)
78       {
79         return description.get(0);
80       }
81       return null;
82     }
83   }
84
85   /**
86    * Answers the singleton instance of this class
87    * 
88    * @return
89    */
90   public static FeatureAttributes getInstance()
91   {
92     return instance;
93   }
94
95   private FeatureAttributes()
96   {
97     attributes = new HashMap<>();
98   }
99
100   /**
101    * Answers the attributes known for the given feature type, in alphabetical
102    * order (not case sensitive), or an empty set if no attributes are known
103    * 
104    * @param featureType
105    * @return
106    */
107   public List<String> getAttributes(String featureType)
108   {
109     if (!attributes.containsKey(featureType))
110     {
111       return Collections.<String> emptyList();
112     }
113
114     return new ArrayList<>(attributes.get(featureType).keySet());
115   }
116
117   /**
118    * Answers true if at least one attribute is known for the given feature type,
119    * else false
120    * 
121    * @param featureType
122    * @return
123    */
124   public boolean hasAttributes(String featureType)
125   {
126     if (attributes.containsKey(featureType))
127     {
128       if (!attributes.get(featureType).isEmpty())
129       {
130         return true;
131       }
132     }
133     return false;
134   }
135
136   /**
137    * Records the given attribute name and description for the given feature
138    * type, and updates the min-max for any numeric value
139    * 
140    * @param featureType
141    * @param attName
142    * @param description
143    * @param value
144    */
145   public void addAttribute(String featureType, String attName,
146           String description, String value)
147   {
148     if (featureType == null || attName == null)
149     {
150       return;
151     }
152
153     Map<String, AttributeData> atts = attributes.get(featureType);
154     if (atts == null)
155     {
156       atts = new TreeMap<String, AttributeData>(
157               String.CASE_INSENSITIVE_ORDER);
158       attributes.put(featureType, atts);
159     }
160     AttributeData attData = atts.get(attName);
161     if (attData == null)
162     {
163       attData = new AttributeData();
164       atts.put(attName, attData);
165     }
166     attData.addInstance(description, value);
167   }
168
169   /**
170    * Answers the description of the given attribute for the given feature type,
171    * if known and unique, else null
172    * 
173    * @param featureType
174    * @param attName
175    * @return
176    */
177   public String getDescription(String featureType, String attName)
178   {
179     String desc = null;
180     Map<String, AttributeData> atts = attributes.get(featureType);
181     if (atts != null)
182     {
183       AttributeData attData = atts.get(attName);
184       if (attData != null)
185       {
186         desc = attData.getDescription();
187       }
188     }
189     return desc;
190   }
191 }