001    package org.openstreetmap.josm.data.validation.tests;
002    
003    import static org.openstreetmap.josm.tools.I18n.tr;
004    
005    import java.util.Collection;
006    import java.util.LinkedList;
007    import java.util.List;
008    
009    import org.openstreetmap.josm.command.ChangePropertyCommand;
010    import org.openstreetmap.josm.command.Command;
011    import org.openstreetmap.josm.command.SequenceCommand;
012    import org.openstreetmap.josm.data.osm.Node;
013    import org.openstreetmap.josm.data.osm.OsmPrimitive;
014    import org.openstreetmap.josm.data.osm.Relation;
015    import org.openstreetmap.josm.data.osm.Tag;
016    import org.openstreetmap.josm.data.osm.Way;
017    import org.openstreetmap.josm.data.validation.Severity;
018    import org.openstreetmap.josm.data.validation.Test;
019    import org.openstreetmap.josm.data.validation.TestError;
020    import org.openstreetmap.josm.tools.Utils;
021    
022    public class DeprecatedTags extends Test {
023    
024        private List<DeprecationCheck> checks = new LinkedList<DeprecationCheck>();
025    
026        public DeprecatedTags() {
027            super(tr("Deprecated Tags"), tr("Checks and corrects deprecated tags."));
028            checks.add(new DeprecationCheck(2101).
029                    testAndRemove("barrier", "wire_fence").
030                    add("barrier", "fence").
031                    add("fence_type", "chain"));
032            checks.add(new DeprecationCheck(2102).
033                    testAndRemove("barrier", "wood_fence").
034                    add("barrier", "fence").
035                    add("fence_type", "wood"));
036            checks.add(new DeprecationCheck(2103).
037                    testAndRemove("highway", "ford").
038                    add("ford", "yes"));
039            // from http://wiki.openstreetmap.org/wiki/Deprecated_features
040            checks.add(new DeprecationCheck(2104).
041                    test("class").
042                    alternative("highway"));
043            checks.add(new DeprecationCheck(2105).
044                    testAndRemove("highway", "stile").
045                    add("barrier", "stile"));
046            checks.add(new DeprecationCheck(2106).
047                    testAndRemove("highway", "incline").
048                    add("highway", "road").
049                    add("incline", "up"));
050            checks.add(new DeprecationCheck(2107).
051                    testAndRemove("highway", "incline_steep").
052                    add("highway", "road").
053                    add("incline", "up"));
054            checks.add(new DeprecationCheck(2108).
055                    testAndRemove("highway", "unsurfaced").
056                    add("highway", "road").
057                    add("incline", "unpaved"));
058            checks.add(new DeprecationCheck(2109).
059                    test("landuse", "wood").
060                    alternative("landuse", "forest").
061                    alternative("natural", "wood"));
062            checks.add(new DeprecationCheck(2110).
063                    testAndRemove("natural", "marsh").
064                    add("natural", "wetland").
065                    add("wetland", "marsh"));
066            checks.add(new DeprecationCheck(2111).
067                    test("highway", "byway"));
068            checks.add(new DeprecationCheck(2112).
069                    test("power_source").
070                    alternative("generator:source"));
071            checks.add(new DeprecationCheck(2113).
072                    test("power_rating").
073                    alternative("generator:output"));
074            // from http://wiki.openstreetmap.org/wiki/Tag:shop%3Dorganic
075            checks.add(new DeprecationCheck(2114).
076                    testAndRemove("shop", "organic").
077                    add("shop", "supermarket").
078                    add("organic", "only"));
079            // from http://wiki.openstreetmap.org/wiki/Key:bicycle_parking
080            checks.add(new DeprecationCheck(2115).
081                    testAndRemove("bicycle_parking", "sheffield").
082                    add("bicycle_parking", "stands"));
083        }
084    
085        public void visit(OsmPrimitive p) {
086            for (DeprecationCheck check : checks) {
087                if (check.matchesPrimitive(p)) {
088                    errors.add(new DeprecationError(p, check));
089                }
090            }
091        }
092    
093        @Override
094        public void visit(Node n) {
095            visit((OsmPrimitive) n);
096        }
097    
098        @Override
099        public void visit(Way w) {
100            visit((OsmPrimitive) w);
101        }
102    
103        @Override
104        public void visit(Relation r) {
105            visit((OsmPrimitive) r);
106        }
107    
108        private static class DeprecationCheck {
109    
110            int code;
111            List<Tag> test = new LinkedList<Tag>();
112            List<Tag> change = new LinkedList<Tag>();
113            List<Tag> alternatives = new LinkedList<Tag>();
114    
115            public DeprecationCheck(int code) {
116                this.code = code;
117            }
118    
119            DeprecationCheck test(String key, String value) {
120                test.add(new Tag(key, value));
121                return this;
122            }
123    
124            DeprecationCheck test(String key) {
125                return test(key, null);
126            }
127    
128            DeprecationCheck add(String key, String value) {
129                change.add(new Tag(key, value));
130                return this;
131            }
132    
133            DeprecationCheck remove(String key) {
134                change.add(new Tag(key));
135                return this;
136            }
137    
138            DeprecationCheck testAndRemove(String key, String value) {
139                return test(key, value).remove(key);
140            }
141    
142            DeprecationCheck testAndRemove(String key) {
143                return test(key).remove(key);
144            }
145    
146            DeprecationCheck alternative(String key, String value) {
147                alternatives.add(new Tag(key, value));
148                return this;
149            }
150    
151            DeprecationCheck alternative(String key) {
152                return alternative(key, null);
153            }
154    
155            boolean matchesPrimitive(OsmPrimitive p) {
156                for (Tag tag : test) {
157                    String key = tag.getKey();
158                    String value = tag.getValue();
159                    if (value.isEmpty() && !p.hasKey(key))
160                        return false;
161                    if (!value.isEmpty() && !value.equals(p.get(key)))
162                        return false;
163                }
164                return true;
165            }
166    
167            Command fixPrimitive(OsmPrimitive p) {
168                Collection<Command> cmds = new LinkedList<Command>();
169                for (Tag tag : change) {
170                    cmds.add(new ChangePropertyCommand(p, tag.getKey(), tag.getValue()));
171                }
172                return new SequenceCommand(tr("Deprecation fix of {0}", Utils.join(", ", test)), cmds);
173            }
174    
175            String getDescription() {
176                if (alternatives.isEmpty())
177                    return tr("{0} is deprecated", Utils.join(", ", test));
178                else
179                    return tr("{0} is deprecated, use {1} instead", Utils.join(", ", test), Utils.join(tr(" or "), alternatives));
180            }
181        }
182    
183        private class DeprecationError extends TestError {
184    
185            OsmPrimitive p;
186            DeprecationCheck check;
187    
188            DeprecationError(OsmPrimitive p, DeprecationCheck check) {
189                super(DeprecatedTags.this, Severity.WARNING, check.getDescription(), check.code, p);
190                this.p = p;
191                this.check = check;
192            }
193    
194            @Override
195            public boolean isFixable() {
196                return !check.change.isEmpty();
197            }
198    
199            @Override
200            public Command getFix() {
201                return check.fixPrimitive(p);
202            }
203        }
204    }