JAL-2808 update spike to latest (filter range tooltip, Present condition)
[jalview.git] / src / jalview / datamodel / features / FeatureMatcher.java
1 package jalview.datamodel.features;
2
3 import jalview.datamodel.SequenceFeature;
4 import jalview.util.matcher.Condition;
5 import jalview.util.matcher.Matcher;
6 import jalview.util.matcher.MatcherI;
7
8 /**
9  * An immutable class that models one or more match conditions, each of which is
10  * applied to the value obtained by lookup given the match key.
11  * <p>
12  * For example, the value provider could be a SequenceFeature's attributes map,
13  * and the conditions might be
14  * <ul>
15  * <li>CSQ contains "pathological"</li>
16  * <li>AND</li>
17  * <li>AF <= 1.0e-5</li>
18  * </ul>
19  * 
20  * @author gmcarstairs
21  *
22  */
23 public class FeatureMatcher implements FeatureMatcherI
24 {
25   private static final String COLON = ":";
26
27   /*
28    * if true, match is against feature description
29    */
30   final private boolean byLabel;
31
32   /*
33    * if true, match is against feature score
34    */
35   final private boolean byScore;
36
37   /*
38    * if not null, match is against feature attribute [sub-attribute]
39    */
40   final private String[] key;
41
42   final private MatcherI matcher;
43
44   /**
45    * A factory constructor method for a matcher that applies its match condition
46    * to the feature label (description)
47    * 
48    * @param cond
49    * @param pattern
50    * @return
51    */
52   public static FeatureMatcher byLabel(Condition cond, String pattern)
53   {
54     return new FeatureMatcher(new Matcher(cond, pattern), true, false,
55             null);
56   }
57
58   /**
59    * A factory constructor method for a matcher that applies its match condition
60    * to the feature score
61    * 
62    * @param cond
63    * @param pattern
64    * @return
65    */
66   public static FeatureMatcher byScore(Condition cond, String pattern)
67   {
68     return new FeatureMatcher(new Matcher(cond, pattern), false, true,
69             null);
70   }
71
72   /**
73    * A factory constructor method for a matcher that applies its match condition
74    * to the named feature attribute [and optional sub-attribute]
75    * 
76    * @param cond
77    * @param pattern
78    * @param attName
79    * @return
80    */
81   public static FeatureMatcher byAttribute(Condition cond, String pattern,
82           String... attName)
83   {
84     return new FeatureMatcher(new Matcher(cond, pattern), false, false,
85             attName);
86   }
87
88   private FeatureMatcher(Matcher m, boolean forLabel, boolean forScore,
89           String[] theKey)
90   {
91     key = theKey;
92     matcher = m;
93     byLabel = forLabel;
94     byScore = forScore;
95   }
96   @Override
97   public boolean matches(SequenceFeature feature)
98   {
99     String value = byLabel ? feature.getDescription()
100             : (byScore ? String.valueOf(feature.getScore())
101                     : feature.getValueAsString(key));
102     return matcher.matches(value);
103   }
104
105   @Override
106   public String[] getKey()
107   {
108     return key;
109   }
110
111   @Override
112   public MatcherI getMatcher()
113   {
114     return matcher;
115   }
116
117   /**
118    * Answers a string description of this matcher, suitable for display, debugging
119    * or logging. The format may change in future.
120    */
121   @Override
122   public String toString()
123   {
124     StringBuilder sb = new StringBuilder();
125     sb.append(String.join(COLON, key)).append(" ")
126             .append(matcher.getCondition().toString());
127     Condition condition = matcher.getCondition();
128     if (condition.isNumeric())
129     {
130       sb.append(" ").append(matcher.getPattern());
131     }
132     else if (condition.needsAPattern())
133     {
134       sb.append(" '").append(matcher.getPattern()).append("'");
135     }
136
137     return sb.toString();
138   }
139 }