Index: /trunk/data/validator/deprecated.mapcss
===================================================================
--- /trunk/data/validator/deprecated.mapcss	(revision 6506)
+++ /trunk/data/validator/deprecated.mapcss	(revision 6506)
@@ -0,0 +1,193 @@
+*[barrier=wire_fence] {
+  throwWarning: tr("{0}={1} is deprecated", "barrier", "wire_fence");
+  fixRemove: "barrier";
+  fixAdd: "barrier=fence";
+  fixAdd: "fence_type=chain_link";
+}
+  
+*[barrier=wood_fence] {
+  throwWarning: tr("{0}={1} is deprecated", "barrier", "wood_fence");
+  fixRemove: "barrier";
+  fixAdd: "barrier=fence";
+  fixAdd: "fence_type=wood";
+}
+  
+*[highway=ford] {
+  throwWarning: tr("{0}={1} is deprecated", "highway", "ford");
+  fixRemove: "highway";
+  fixAdd: "ford=yes";
+}
+  
+*[class] {
+  /* from http://wiki.openstreetmap.org/wiki/Deprecated_features */
+  throwWarning: tr("{0} is deprecated", "class");
+  suggestAlternative: "highway";
+}
+  
+*[highway=stile] {
+  /* from http://wiki.openstreetmap.org/wiki/Deprecated_features */
+  throwWarning: tr("{0}={1} is deprecated", "highway", "stile");
+  fixRemove: "highway";
+  fixAdd: "barrier=stile";
+}
+  
+*[highway=incline] {
+  /* from http://wiki.openstreetmap.org/wiki/Deprecated_features */
+  throwWarning: tr("{0}={1} is deprecated", "highway", "incline");
+  suggestAlternative: "incline";
+}
+  
+*[highway=incline_steep] {
+  /* from http://wiki.openstreetmap.org/wiki/Deprecated_features */
+  throwWarning: tr("{0}={1} is deprecated", "highway", "incline");
+  suggestAlternative: "incline";
+}
+  
+*[highway=unsurfaced] {
+  /* from http://wiki.openstreetmap.org/wiki/Deprecated_features */
+  throwWarning: tr("{0}={1} is deprecated", "highway", "unsurfaced");
+  fixRemove: "highway";
+  fixAdd: "highway=road";
+  fixAdd: "incline=unpaved";
+}
+  
+*[landuse=wood] {
+  /* from http://wiki.openstreetmap.org/wiki/Deprecated_features */
+  throwWarning: tr("{0}={1} is deprecated", "landuse", "wood");
+  suggestAlternative: "landuse=forest";
+  suggestAlternative: "natural=wood";
+}
+  
+*[natural=marsh] {
+  /* from http://wiki.openstreetmap.org/wiki/Deprecated_features */
+  throwWarning: tr("{0}={1} is deprecated", "natural", "marsh");
+  fixRemove: "natural";
+  fixAdd: "natural=wetland";
+  fixAdd: "wetland=marsh";
+}
+  
+*[highway=byway] {
+  /* from http://wiki.openstreetmap.org/wiki/Deprecated_features */
+  throwWarning: tr("{0}={1} is deprecated", "highway", "byway");
+}
+  
+*[power_source] {
+  /* from http://wiki.openstreetmap.org/wiki/Deprecated_features */
+  throwWarning: tr("{0} is deprecated", "power_source");
+  suggestAlternative: "generator:source";
+}
+  
+*[power_rating] {
+  /* from http://wiki.openstreetmap.org/wiki/Deprecated_features */
+  throwWarning: tr("{0} is deprecated", "power_rating");
+  suggestAlternative: "generator:output";
+}
+  
+*[shop=organic] {
+  /* from http://wiki.openstreetmap.org/wiki/Tag:shop=organic */
+  throwWarning: tr("{0}={1} is deprecated", "shop", "organic");
+  fixRemove: "shop";
+  fixAdd: "shop=supermarket";
+  fixAdd: "organic=only";
+}
+  
+*[bicycle_parking=sheffield] {
+  /* from http://wiki.openstreetmap.org/wiki/Key:bicycle_parking */
+  throwWarning: tr("{0}={1} is deprecated", "bicycle_parking", "sheffield");
+  fixRemove: "bicycle_parking";
+  fixAdd: "bicycle_parking=stands";
+}
+  
+*[amenity=emergency_phone] {
+  /* http://wiki.openstreetmap.org/wiki/Tag:emergency=phone */
+  throwWarning: tr("{0}={1} is deprecated", "amenity", "emergency_phone");
+  fixRemove: "amenity";
+  fixAdd: "emergency=phone";
+}
+  
+*[sport=gaelic_football] {
+  /* fix #8132 - http://wiki.openstreetmap.org/wiki/Tag:sport=gaelic_football */
+  throwWarning: tr("{0}={1} is deprecated", "sport", "gaelic_football");
+  fixRemove: "sport";
+  fixAdd: "sport=gaelic_games";
+}
+  
+*[power=station] {
+  /* see #8847 / #8961 - http://wiki.openstreetmap.org/wiki/Tag:power=station */
+  throwWarning: tr("{0}={1} is deprecated", "power", "station");
+  suggestAlternative: "power=plant";
+  suggestAlternative: "power=sub_station";
+}
+  
+*[generator:method=dam] {
+  throwWarning: tr("{0}={1} is deprecated", "generator:method", "dam");
+  fixRemove: "generator:method";
+  fixAdd: "generator:method=water-storage";
+}
+  
+*[generator:method=pumped-storage] {
+  throwWarning: tr("{0}={1} is deprecated", "generator:method", "pumped-storage");
+  fixRemove: "generator:method";
+  fixAdd: "generator:method=water-pumped-storage";
+}
+  
+*[generator:method=pumping] {
+  throwWarning: tr("{0}={1} is deprecated", "generator:method", "pumping");
+  fixRemove: "generator:method";
+  fixAdd: "generator:method=water-pumped-storage";
+}
+  
+*[fence_type=chain] {
+  /* see #8962 - http://wiki.openstreetmap.org/wiki/Key:fence_type */
+  throwWarning: tr("{0}={1} is deprecated", "fence_type", "chain");
+  suggestAlternative: "barrier=chain";
+  suggestAlternative: "fence_type=chain_link";
+}
+
+*[building=entrance] {
+  /* see #9000 - http://wiki.openstreetmap.org/wiki/Key:entrance */
+  throwWarning: tr("{0}={1} is deprecated", "building", "entrance");
+  suggestAlternative: "entrance";
+}
+  
+*[board_type=board] {
+  /* see #9213 - Useless tag proposed in internal preset for years */
+  throwWarning: tr("{0}={1} is deprecated", "board_type", "board");
+  fixRemove: "board_type";
+}
+  
+*[man_made=measurement_station] {
+  /* see #8434 - http://wiki.openstreetmap.org/wiki/Proposed_features/monitoring_station */
+  throwWarning: tr("{0}={1} is deprecated", "man_made", "measurement_station");
+  fixRemove: "man_made";
+  fixAdd: "man_made=monitoring_station";
+}
+  
+*[measurement=water_level] {
+  throwWarning: tr("{0}={1} is deprecated", "measurement", "water_level");
+  fixRemove: "measurement";
+  fixAdd: "monitoring:water_level=yes";
+}
+  
+*[measurement=weather] {
+  throwWarning: tr("{0}={1} is deprecated", "measurement", "weather");
+  fixRemove: "measurement";
+  fixAdd: "monitoring:weather=yes";
+}
+  
+*[measurement=seismic] {
+  throwWarning: tr("{0}={1} is deprecated", "measurement", "seismic");
+  fixRemove: "measurement";
+  fixAdd: "monitoring:seismic_activity=yes";
+}
+
+*[monitoring:river_level] {
+  throwWarning: tr("{0} is deprecated", "monitoring:river_level");
+  fixChangeKey: "monitoring:river_level => monitoring:water_level";
+}
+
+*[layer=0] {
+  /* see #9365 - Useless tag layer=0 */
+  throwWarning: tr("{0}={1} is unnecessary", "layer", "0");
+  fixRemove: "layer";
+}
Index: /trunk/src/org/openstreetmap/josm/data/osm/Tag.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/Tag.java	(revision 6505)
+++ /trunk/src/org/openstreetmap/josm/data/osm/Tag.java	(revision 6506)
@@ -1,4 +1,6 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.data.osm;
+
+import org.openstreetmap.josm.tools.CheckParameterUtil;
 
 /**
@@ -97,4 +99,14 @@
     }
 
+    public static Tag ofString(String s) {
+        CheckParameterUtil.ensureParameterNotNull(s, "s");
+        final String[] x = s.split("=", 2);
+        if (x.length == 2) {
+            return new Tag(x[0], x[1]);
+        } else {
+            throw new IllegalArgumentException("String does not contain '='");
+        }
+    }
+
     @Override
     public String toString() {
Index: /trunk/src/org/openstreetmap/josm/data/validation/OsmValidator.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/validation/OsmValidator.java	(revision 6505)
+++ /trunk/src/org/openstreetmap/josm/data/validation/OsmValidator.java	(revision 6506)
@@ -35,4 +35,5 @@
 import org.openstreetmap.josm.data.validation.tests.DuplicatedWayNodes;
 import org.openstreetmap.josm.data.validation.tests.Highways;
+import org.openstreetmap.josm.data.validation.tests.MapCSSTagChecker;
 import org.openstreetmap.josm.data.validation.tests.MultipolygonTest;
 import org.openstreetmap.josm.data.validation.tests.NameMismatch;
@@ -106,5 +107,5 @@
         DuplicateRelation.class, // ID 1901 .. 1999
         BuildingInBuilding.class, // ID 2001 .. 2099
-        DeprecatedTags.class, // ID 2101 .. 2199
+        //DeprecatedTags.class, // ID 2101 .. 2199
         OverlappingAreas.class, // ID 2201 .. 2299
         WayConnectedToArea.class, // ID 2301 .. 2399
@@ -114,5 +115,6 @@
         Highways.class, // ID 2701 .. 2799
         BarriersEntrances.class, // ID 2801 .. 2899
-        OpeningHourTest.class // 2901 .. 2999
+        OpeningHourTest.class, // 2901 .. 2999
+        MapCSSTagChecker.class, // 3000 .. 3099
     };
     
Index: /trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java	(revision 6506)
+++ /trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java	(revision 6506)
@@ -0,0 +1,213 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.validation.tests;
+
+import org.openstreetmap.josm.command.ChangePropertyCommand;
+import org.openstreetmap.josm.command.ChangePropertyKeyCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.Tag;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.validation.FixableTestError;
+import org.openstreetmap.josm.data.validation.Severity;
+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.mapcss.ExpressionFactory;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Instruction;
+import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSRule;
+import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
+import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.MapCSSParser;
+import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.ParseException;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+import org.openstreetmap.josm.tools.Predicate;
+import org.openstreetmap.josm.tools.Utils;
+
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+public class MapCSSTagChecker extends Test {
+
+    public MapCSSTagChecker() {
+        super(tr("Tag checker (new)"), tr("This test checks for errors in tag keys and values."));
+    }
+
+    final List<TagCheck> checks = new ArrayList<TagCheck>();
+
+    static class TagCheck implements Predicate<OsmPrimitive> {
+        protected final List<Selector> selector;
+        protected final List<Tag> change = new ArrayList<Tag>();
+        protected final Map<String, String> keyChange = new LinkedHashMap<String, String>();
+        protected final List<Tag> alternatives = new ArrayList<Tag>();
+        protected final Map<String, Severity> errors = new HashMap<String, Severity>();
+
+        TagCheck(List<Selector> selector) {
+            this.selector = selector;
+        }
+
+        static TagCheck ofMapCSSRule(final MapCSSRule rule) {
+            final TagCheck check = new TagCheck(rule.selectors);
+            for (Instruction i : rule.declaration) {
+                if (i instanceof Instruction.AssignmentInstruction) {
+                    final Instruction.AssignmentInstruction ai = (Instruction.AssignmentInstruction) i;
+                    final String val = ai.val instanceof ExpressionFactory.ArrayFunction
+                            ? (String) ((ExpressionFactory.ArrayFunction) ai.val).evaluate(new Environment())
+                            : ai.val instanceof String
+                            ? (String) ai.val
+                            : null;
+                    if (ai.key.startsWith("throw")) {
+                        final Severity severity = Severity.valueOf(ai.key.substring("throw".length()).toUpperCase());
+                        check.errors.put(val, severity);
+                    } else if ("fixAdd".equals(ai.key) && val != null) {
+                        check.change.add(Tag.ofString(val));
+                    } else if ("fixRemove".equals(ai.key) && val != null) {
+                        CheckParameterUtil.ensureThat(!val.contains("="), "Unexpected '='. Please only specify the key to remove!");
+                        check.change.add(new Tag(val));
+                    } else if ("fixChangeKey".equals(ai.key) && val != null) {
+                        CheckParameterUtil.ensureThat(val.contains("=>"), "Separate old from new key by '=>'!");
+                        final String[] x = val.split("=>", 2);
+                        check.keyChange.put(x[0].trim(), x[1].trim());
+                    } else if ("suggestAlternative".equals(ai.key) && val != null) {
+                        check.alternatives.add(val.contains("=") ? Tag.ofString(val) : new Tag(val));
+                    } else {
+                        throw new RuntimeException("Cannot add instruction " + ai.key + ": " + ai.val + "!");
+                    }
+                }
+            }
+            if (check.errors.isEmpty()) {
+                throw new RuntimeException("No throwError/throwWarning/throwOther given! You should specify a validation error message for " + rule.selectors);
+            } else if (check.errors.size() > 1) {
+                throw new RuntimeException("More than one throwError/throwWarning/throwOther given! You should specify a single validation error message for " + rule.selectors);
+            }
+            return check;
+        }
+
+        static List<TagCheck> readMapCSS(Reader css) throws ParseException {
+            CheckParameterUtil.ensureParameterNotNull(css, "css");
+            return readMapCSS(new MapCSSParser(css));
+        }
+
+        static List<TagCheck> readMapCSS(MapCSSParser css) throws ParseException {
+            CheckParameterUtil.ensureParameterNotNull(css, "css");
+            final MapCSSStyleSource source = new MapCSSStyleSource("");
+            css.sheet(source);
+            assert source.getErrors().isEmpty();
+            return new ArrayList<TagCheck>(Utils.transform(source.rules, new Utils.Function<MapCSSRule, TagCheck>() {
+                @Override
+                public TagCheck apply(MapCSSRule x) {
+                    return TagCheck.ofMapCSSRule(x);
+                }
+            }));
+        }
+
+        @Override
+        public boolean evaluate(OsmPrimitive primitive) {
+            return matchesPrimitive(primitive);
+        }
+
+        /**
+         * Tests whether the {@link OsmPrimitive} contains a deprecated tag which is represented by this {@code MapCSSTagChecker}.
+         *
+         * @param primitive the primitive to test
+         * @return true when the primitive contains a deprecated tag
+         */
+        boolean matchesPrimitive(OsmPrimitive primitive) {
+            final Environment env = new Environment().withPrimitive(primitive);
+            for (Selector i : selector) {
+                if (i.matches(env)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Constructs a fix in terms of a {@link org.openstreetmap.josm.command.Command} for the {@link OsmPrimitive}
+         * if the error is fixable, or {@code null} otherwise.
+         *
+         * @param p the primitive to construct the fix for
+         * @return the fix or {@code null}
+         */
+        Command fixPrimitive(OsmPrimitive p) {
+            if (change.isEmpty() && keyChange.isEmpty()) {
+                return null;
+            }
+            Collection<Command> cmds = new LinkedList<Command>();
+            for (Tag tag : change) {
+                cmds.add(new ChangePropertyCommand(p, tag.getKey(), tag.getValue()));
+            }
+            for (Map.Entry<String, String> i : keyChange.entrySet()) {
+                cmds.add(new ChangePropertyKeyCommand(p, i.getKey(), i.getValue()));
+            }
+            return new SequenceCommand(tr("Fix of {0}", getDescription()), cmds);
+        }
+
+        /**
+         * Constructs a (localized) description for this deprecation check.
+         *
+         * @return a description
+         */
+        String getDescription() {
+            return errors.keySet().iterator().next();
+        }
+
+        Severity getSeverity() {
+            return errors.values().iterator().next();
+        }
+
+    }
+
+    /**
+     * Visiting call for primitives.
+     *
+     * @param p The primitive to inspect.
+     */
+    public void visit(OsmPrimitive p) {
+        for (TagCheck check : checks) {
+            if (check.matchesPrimitive(p)) {
+                final Command fix = check.fixPrimitive(p);
+                if (fix != null) {
+                    errors.add(new FixableTestError(this, check.getSeverity(), check.getDescription(), 3000, p, fix));
+                } else {
+                    errors.add(new TestError(this, check.getSeverity(), check.getDescription(), 3000, p));
+                }
+            }
+        }
+    }
+
+    @Override
+    public void visit(Node n) {
+        visit((OsmPrimitive) n);
+    }
+
+    @Override
+    public void visit(Way w) {
+        visit((OsmPrimitive) w);
+    }
+
+    @Override
+    public void visit(Relation r) {
+        visit((OsmPrimitive) r);
+    }
+
+    public void addMapCSS(Reader css) throws ParseException {
+        checks.addAll(TagCheck.readMapCSS(css));
+    }
+
+    @Override
+    public void initialize() throws Exception {
+        addMapCSS(new InputStreamReader(getClass().getResourceAsStream("/data/validator/deprecated.mapcss"), "UTF-8"));
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java	(revision 6505)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java	(revision 6506)
@@ -359,4 +359,10 @@
             return env.osm.getUniqueId();
         }
+
+        public static String tr(String... args) {
+            final String text = args[0];
+            System.arraycopy(args, 1, args, 0, args.length - 1);
+            return org.openstreetmap.josm.tools.I18n.tr(text, args);
+        }
     }
 
Index: /trunk/src/org/openstreetmap/josm/tools/CheckParameterUtil.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/tools/CheckParameterUtil.java	(revision 6505)
+++ /trunk/src/org/openstreetmap/josm/tools/CheckParameterUtil.java	(revision 6506)
@@ -92,4 +92,14 @@
 
     /**
+     * Ensures that the condition {@code condition} holds.
+     * @param condition The condition to check
+     * @throws IllegalArgumentException if the condition does not hold
+     */
+    public static void ensureThat(boolean condition, String message) throws IllegalArgumentException {
+        if (!condition)
+            throw new IllegalArgumentException(message);
+    }
+
+    /**
      * Ensures that <code>id</code> is non-null primitive id of type {@link OsmPrimitiveType#NODE}
      *
Index: /trunk/test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java	(revision 6506)
+++ /trunk/test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java	(revision 6506)
@@ -0,0 +1,56 @@
+package org.openstreetmap.josm.data.validation.tests;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Preferences;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.Tag;
+
+import java.io.StringReader;
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+public class MapCSSTagCheckerTest {
+
+    @Before
+    public void setUp() throws Exception {
+        Main.pref = new Preferences();
+    }
+
+    @Test
+    public void testNaturalMarsh() throws Exception {
+
+        final List<MapCSSTagChecker.TagCheck> checks = MapCSSTagChecker.TagCheck.readMapCSS(new StringReader("" +
+                "*[natural=marsh] {\n" +
+                "   throwWarning: tr(\"{0} is deprecated\", \"natural=marsh\");\n" +
+                "   fixRemove: \"natural\";\n" +
+                "   fixAdd: \"natural=wetland\";\n" +
+                "   fixAdd: \"wetland=marsh\";\n" +
+                "}"));
+        assertThat(checks.size(), is(1));
+        final MapCSSTagChecker.TagCheck check = checks.get(0);
+        assertThat(check, notNullValue());
+        assertThat(check.change.get(0), is(new Tag("natural")));
+        assertThat(check.change.get(1), is(new Tag("natural", "wetland")));
+        assertThat(check.change.get(2), is(new Tag("wetland", "marsh")));
+        assertThat(check.errors.keySet().iterator().next(), is("natural=marsh is deprecated"));
+        final Node n1 = new Node();
+        n1.put("natural", "marsh");
+        assertTrue(check.matchesPrimitive(n1));
+        final Node n2 = new Node();
+        n2.put("natural", "wood");
+        assertFalse(check.matchesPrimitive(n2));
+    }
+
+    @Test
+    public void testInit() throws Exception {
+        final MapCSSTagChecker c = new MapCSSTagChecker();
+        c.initialize();
+    }
+}
