commit ca1b0013680e30cc419f726fab6282f488084531
Author: Simon Legner <Simon.Legner@gmail.com>
Date:   Fri Jan 11 17:43:05 2019 +0100

    v1

diff --git a/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java b/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
index 31d9438b8..9d70b60da 100644
--- a/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
+++ b/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
@@ -41,6 +41,7 @@
 import org.openstreetmap.josm.data.osm.OsmUtils;
 import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.Tag;
+import org.openstreetmap.josm.data.osm.Tagged;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.preferences.sources.SourceEntry;
 import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
@@ -49,7 +50,6 @@
 import org.openstreetmap.josm.data.validation.Test;
 import org.openstreetmap.josm.data.validation.TestError;
 import org.openstreetmap.josm.gui.mappaint.Environment;
-import org.openstreetmap.josm.gui.mappaint.Keyword;
 import org.openstreetmap.josm.gui.mappaint.MultiCascade;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Condition;
 import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.ClassCondition;
@@ -286,7 +286,7 @@ public ParseResult(List<TagCheck> parseChecks, Collection<Throwable> parseErrors
         protected final GroupedMapCSSRule rule;
         /** Commands to apply in order to fix a matching primitive */
         protected final List<FixCommand> fixCommands = new ArrayList<>();
-        /** Tags (or arbitraty strings) of alternatives to be presented to the user */
+        /** Tags (or arbitrary strings) of alternatives to be presented to the user */
         protected final List<String> alternatives = new ArrayList<>();
         /** An {@link org.openstreetmap.josm.gui.mappaint.mapcss.Instruction.AssignmentInstruction}-{@link Severity} pair.
          * Is evaluated on the matching primitive to give the error message. Map is checked to contain exactly one element. */
@@ -329,13 +329,7 @@ static TagCheck ofMapCSSRule(final GroupedMapCSSRule rule) throws IllegalDataExc
                         continue;
                     }
                     try {
-                        final String val = ai.val instanceof Expression
-                                ? Optional.ofNullable(((Expression) ai.val).evaluate(new Environment())).map(Object::toString).orElse(null)
-                                : ai.val instanceof String
-                                ? (String) ai.val
-                                : ai.val instanceof Keyword
-                                ? ((Keyword) ai.val).val
-                                : null;
+                        final String val = ai.getValAsString();
                         if (ai.key.startsWith("throw")) {
                             try {
                                 check.errors.put(ai, Severity.valueOf(ai.key.substring("throw".length()).toUpperCase(Locale.ENGLISH)));
@@ -445,14 +439,14 @@ Selector whichSelectorMatchesEnvironment(Environment env) {
          * @param matchingSelector matching selector
          * @param index index
          * @param type selector type ("key", "value" or "tag")
-         * @param p OSM primitive
+         * @param p a tagged object
          * @return argument value, can be {@code null}
          */
-        static String determineArgument(OptimizedGeneralSelector matchingSelector, int index, String type, OsmPrimitive p) {
+        static String determineArgument(OptimizedGeneralSelector matchingSelector, int index, String type, Tagged p) {
             try {
                 final Condition c = matchingSelector.getConditions().get(index);
-                final Tag tag = c instanceof Condition.ToTagConvertable
-                        ? ((Condition.ToTagConvertable) c).asTag(p)
+                final Tag tag = c instanceof Condition.TagCondition
+                        ? ((Condition.TagCondition) c).asTag(p)
                         : null;
                 if (tag == null) {
                     return null;
@@ -474,10 +468,10 @@ static String determineArgument(OptimizedGeneralSelector matchingSelector, int i
          * key/value/tag of the {@code index}-th {@link Condition} of {@code matchingSelector}.
          * @param matchingSelector matching selector
          * @param s any string
-         * @param p OSM primitive
+         * @param p a tagged object
          * @return string with arguments inserted
          */
-        static String insertArguments(Selector matchingSelector, String s, OsmPrimitive p) {
+        static String insertArguments(Selector matchingSelector, String s, Tagged p) {
             if (s != null && matchingSelector instanceof Selector.ChildOrParentSelector) {
                 return insertArguments(((Selector.ChildOrParentSelector) matchingSelector).right, s, p);
             } else if (s == null || !(matchingSelector instanceof Selector.OptimizedGeneralSelector)) {
diff --git a/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java b/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java
index f0eab71e3..d10aa1be9 100644
--- a/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java
+++ b/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java
@@ -3,7 +3,9 @@
 
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Tag;
+import org.openstreetmap.josm.data.osm.Tagged;
 import org.openstreetmap.josm.gui.mappaint.Environment;
+import org.openstreetmap.josm.tools.Utils;
 
 /**
  * This is a condition that needs to be fulfilled in order to apply a MapCSS style.
@@ -38,13 +40,25 @@
      * @author Michael Zangl
      * @since 10674
      */
-    @FunctionalInterface
-    interface ToTagConvertable {
+    interface TagCondition extends Condition {
+
+        @Override
+        default boolean applies(Environment e) {
+            return applies(e.osm);
+        }
+
+        /**
+         * Checks if the condition applies in the given {@link Tagged} element.
+         * @param tagged The tagged to check.
+         * @return <code>true</code> if the condition applies.
+         */
+        boolean applies(Tagged tagged);
+
         /**
          * Converts the current condition to a tag
-         * @param primitive A primitive to use as context. May be ignored.
+         * @param tagged A tagged object to use as context. May be ignored.
          * @return A tag with the key/value of this condition.
          */
-        Tag asTag(OsmPrimitive primitive);
+        Tag asTag(Tagged tagged);
     }
 }
diff --git a/src/org/openstreetmap/josm/gui/mappaint/mapcss/ConditionFactory.java b/src/org/openstreetmap/josm/gui/mappaint/mapcss/ConditionFactory.java
index e0cc01b46..29d6ce2a1 100644
--- a/src/org/openstreetmap/josm/gui/mappaint/mapcss/ConditionFactory.java
+++ b/src/org/openstreetmap/josm/gui/mappaint/mapcss/ConditionFactory.java
@@ -23,6 +23,7 @@
 import org.openstreetmap.josm.data.osm.OsmUtils;
 import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.Tag;
+import org.openstreetmap.josm.data.osm.Tagged;
 import org.openstreetmap.josm.data.osm.search.SearchCompiler.InDataSourceArea;
 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
 import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
@@ -30,7 +31,7 @@
 import org.openstreetmap.josm.gui.mappaint.ElemStyles;
 import org.openstreetmap.josm.gui.mappaint.Environment;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context;
-import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.ToTagConvertable;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.TagCondition;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 import org.openstreetmap.josm.tools.JosmRuntimeException;
 import org.openstreetmap.josm.tools.Utils;
@@ -243,7 +244,7 @@ public boolean eval(String testString, String prototypeString) {
      *
      * Extra class for performance reasons.
      */
-    public static class SimpleKeyValueCondition implements Condition, ToTagConvertable {
+    public static class SimpleKeyValueCondition implements TagCondition {
         /**
          * The key to search for.
          */
@@ -264,12 +265,12 @@ public SimpleKeyValueCondition(String k, String v) {
         }
 
         @Override
-        public boolean applies(Environment e) {
-            return v.equals(e.osm.get(k));
+        public boolean applies(Tagged tagged) {
+            return v.equals(tagged.get(k));
         }
 
         @Override
-        public Tag asTag(OsmPrimitive primitive) {
+        public Tag asTag(Tagged tagged) {
             return new Tag(k, v);
         }
 
@@ -284,7 +285,7 @@ public String toString() {
      * <p>Represents a key/value condition which is either applied to a primitive.</p>
      *
      */
-    public static class KeyValueCondition implements Condition, ToTagConvertable {
+    public static class KeyValueCondition implements TagCondition {
         /**
          * The key to search for.
          */
@@ -327,12 +328,12 @@ public boolean requiresExactKeyMatch() {
         }
 
         @Override
-        public boolean applies(Environment env) {
-            return op.eval(env.osm.get(k), considerValAsKey ? env.osm.get(v) : v);
+        public boolean applies(Tagged tagged) {
+            return op.eval(tagged.get(k), considerValAsKey ? tagged.get(v) : v);
         }
 
         @Override
-        public Tag asTag(OsmPrimitive primitive) {
+        public Tag asTag(Tagged tagged) {
             return new Tag(k, v);
         }
 
@@ -512,7 +513,7 @@ public boolean applies(Environment env) {
      *                   LINK:       not supported
      * </pre>
      */
-    public static class KeyCondition implements Condition, ToTagConvertable {
+    public static class KeyCondition implements TagCondition {
 
         /**
          * The key name.
@@ -550,21 +551,26 @@ public KeyCondition(String label, boolean negateResult, KeyMatchType matchType)
         @Override
         public boolean applies(Environment e) {
             switch(e.getContext()) {
-            case PRIMITIVE:
-                switch (matchType) {
+                case PRIMITIVE:
+                    return applies(e.osm);
+                case LINK:
+                    Utils.ensure(false, "Illegal state: {0} not supported in LINK context", getClass());
+                    return false;
+                default: throw new AssertionError();
+            }
+        }
+
+        @Override
+        public boolean applies(Tagged tagged) {
+            switch (matchType) {
                 case TRUE:
-                    return e.osm.isKeyTrue(label) ^ negateResult;
+                    return tagged.isKeyTrue(label) ^ negateResult;
                 case FALSE:
-                    return e.osm.isKeyFalse(label) ^ negateResult;
+                    return tagged.isKeyFalse(label) ^ negateResult;
                 case REGEX:
-                    return e.osm.keySet().stream().anyMatch(containsPattern) ^ negateResult;
+                    return tagged.keySet().stream().anyMatch(containsPattern) ^ negateResult;
                 default:
-                    return e.osm.hasKey(label) ^ negateResult;
-                }
-            case LINK:
-                Utils.ensure(false, "Illegal state: KeyCondition not supported in LINK context");
-                return false;
-            default: throw new AssertionError();
+                    return tagged.hasKey(label) ^ negateResult;
             }
         }
 
@@ -578,7 +584,7 @@ public boolean applies(Environment e) {
          * @return The tag.
          */
         @Override
-        public Tag asTag(OsmPrimitive p) {
+        public Tag asTag(Tagged p) {
             String key = label;
             if (KeyMatchType.REGEX == matchType) {
                 key = p.keySet().stream().filter(containsPattern).findAny().orElse(key);
diff --git a/src/org/openstreetmap/josm/gui/mappaint/mapcss/Instruction.java b/src/org/openstreetmap/josm/gui/mappaint/mapcss/Instruction.java
index 793b85eaa..58b4082d8 100644
--- a/src/org/openstreetmap/josm/gui/mappaint/mapcss/Instruction.java
+++ b/src/org/openstreetmap/josm/gui/mappaint/mapcss/Instruction.java
@@ -2,6 +2,7 @@
 package org.openstreetmap.josm.gui.mappaint.mapcss;
 
 import java.util.Arrays;
+import java.util.Optional;
 
 import org.openstreetmap.josm.gui.mappaint.Cascade;
 import org.openstreetmap.josm.gui.mappaint.Environment;
@@ -102,6 +103,16 @@ public void execute(Environment env) {
             env.mc.getOrCreateCascade(env.layer).putOrClear(key, value);
         }
 
+        public String getValAsString() {
+            return this.val instanceof Expression
+                    ? Optional.ofNullable(((Expression) this.val).evaluate(new Environment())).map(Object::toString).orElse(null)
+                    : this.val instanceof String
+                    ? (String) this.val
+                    : this.val instanceof Keyword
+                    ? ((Keyword) this.val).val
+                    : null;
+        }
+
         @Override
         public String toString() {
             return key + ": " + (val instanceof float[] ? Arrays.toString((float[]) val) :
diff --git a/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSRule.java b/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSRule.java
index fca2760f4..511fd351c 100644
--- a/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSRule.java
+++ b/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSRule.java
@@ -43,7 +43,7 @@
 
         /**
          * Create a new {@link Declaration}
-         * @param instructions The instructions for this dectlaration
+         * @param instructions The instructions for this declaration
          * @param idx The index in the {@link StyleSource}
          */
         public Declaration(List<Instruction> instructions, int idx) {
diff --git a/src/org/openstreetmap/josm/tools/Tag2Link.java b/src/org/openstreetmap/josm/tools/Tag2Link.java
new file mode 100644
index 000000000..e9490c14b
--- /dev/null
+++ b/src/org/openstreetmap/josm/tools/Tag2Link.java
@@ -0,0 +1,28 @@
+package org.openstreetmap.josm.tools;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openstreetmap.josm.data.osm.Tag;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Condition;
+import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSRule;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
+
+public final class Tag2Link {
+
+    final List<MapCSSRule> rules = new ArrayList<>();
+
+    private Tag2Link() {
+    }
+
+    public Iterable<URL> getLinksForTag(Tag tag) {
+        for (MapCSSRule rule : rules) {
+            for (Condition condition : ((Selector.AbstractSelector) rule.selector).getConditions()) {
+                if (((Condition.TagCondition) condition).applies(tag)) {
+
+                }
+            }
+        }
+    }
+}
diff --git a/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ConditionTest.java b/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ConditionTest.java
index 4fefb417e..890f311ba 100644
--- a/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ConditionTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ConditionTest.java
@@ -12,7 +12,7 @@
 import org.openstreetmap.josm.data.osm.OsmUtils;
 import org.openstreetmap.josm.gui.mappaint.Environment;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context;
-import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.ToTagConvertable;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.TagCondition;
 import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.Op;
 import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.SimpleKeyValueCondition;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
@@ -62,8 +62,8 @@ public void testKeyValueEq() {
 
         assertTrue(op instanceof SimpleKeyValueCondition);
         assertEquals("[k1=v1]", op.toString());
-        assertEquals("k1", ((ToTagConvertable) op).asTag(null).getKey());
-        assertEquals("v1", ((ToTagConvertable) op).asTag(null).getValue());
+        assertEquals("k1", ((TagCondition) op).asTag(null).getKey());
+        assertEquals("v1", ((TagCondition) op).asTag(null).getValue());
     }
 
     /**
@@ -78,8 +78,8 @@ public void testKeyValueEqAsKey() {
         assertFalse(op.applies(genEnv(node3)));
         assertFalse(op.applies(genEnv(node4)));
 
-        assertEquals("k1", ((ToTagConvertable) op).asTag(null).getKey());
-        assertEquals("k2", ((ToTagConvertable) op).asTag(null).getValue());
+        assertEquals("k1", ((TagCondition) op).asTag(null).getKey());
+        assertEquals("k2", ((TagCondition) op).asTag(null).getValue());
     }
 
     /**
