--- /dev/null
+package jalview.util.matcher;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Function;
+
+public class KeyedMatcherSet implements KeyedMatcherSetI
+{
+ List<KeyedMatcherI> matchConditions;
+
+ boolean andConditions;
+
+ /**
+ * Constructor
+ */
+ public KeyedMatcherSet()
+ {
+ matchConditions = new ArrayList<>();
+ }
+
+ @Override
+ public boolean matches(Function<String, String> valueProvider)
+ {
+ /*
+ * no conditions matches anything
+ */
+ if (matchConditions.isEmpty())
+ {
+ return true;
+ }
+
+ /*
+ * AND until failure
+ */
+ if (andConditions)
+ {
+ for (KeyedMatcherI m : matchConditions)
+ {
+ if (!m.matches(valueProvider))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*
+ * OR until match
+ */
+ for (KeyedMatcherI m : matchConditions)
+ {
+ if (m.matches(valueProvider))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public KeyedMatcherSetI and(KeyedMatcherI m)
+ {
+ if (!andConditions && matchConditions.size() > 1)
+ {
+ throw new IllegalStateException("Can't add an AND to OR conditions");
+ }
+ matchConditions.add(m);
+ andConditions = true;
+
+ return this;
+ }
+
+ @Override
+ public KeyedMatcherSetI or(KeyedMatcherI m)
+ {
+ if (andConditions && matchConditions.size() > 1)
+ {
+ throw new IllegalStateException("Can't add an OR to AND conditions");
+ }
+ matchConditions.add(m);
+ andConditions = false;
+
+ return this;
+ }
+
+ @Override
+ public boolean isAnded()
+ {
+ return andConditions;
+ }
+
+ @Override
+ public Iterator<KeyedMatcherI> getMatchers()
+ {
+ return matchConditions.iterator();
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for (KeyedMatcherI matcher : matchConditions)
+ {
+ if (!first)
+ {
+ sb.append(andConditions ? " AND " : " OR ");
+ }
+ first = false;
+ sb.append("(").append(matcher.toString()).append(")");
+ }
+ return sb.toString();
+ }
+
+}