001// License: GPL. See LICENSE file for details.
002package org.openstreetmap.josm.data.validation.tests;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.util.ArrayList;
007import java.util.HashMap;
008import java.util.HashSet;
009import java.util.List;
010import java.util.Map;
011
012import org.openstreetmap.josm.data.osm.Node;
013import org.openstreetmap.josm.data.validation.Severity;
014import org.openstreetmap.josm.data.validation.Test;
015import org.openstreetmap.josm.data.validation.TestError;
016import org.openstreetmap.josm.gui.progress.ProgressMonitor;
017
018/**
019 * Finds nodes that have the same name (might be duplicates)
020 * @since 3669
021 */
022public class NodesWithSameName extends Test {
023    protected static final int SAME_NAME = 801;
024
025    private Map<String, List<Node>> namesToNodes;
026
027    /**
028     * Constructs a new {@code NodesWithSameName} test.
029     */
030    public NodesWithSameName() {
031        super(tr("Nodes with same name"),
032                tr("This test finds nodes that have the same name (might be duplicates)."));
033    }
034
035    @Override
036    public void startTest(ProgressMonitor monitor) {
037        super.startTest(monitor);
038        namesToNodes = new HashMap<String, List<Node>>();
039    }
040
041    @Override
042    public void visit(Node n) {
043        if (!n.isUsable()) return;
044
045        String name = n.get("name");
046        String sign = n.get("traffic_sign");
047        String highway = n.get("highway");
048        if (name == null || ("city_limit".equals(sign)) || ("bus_stop".equals(highway)))
049            return;
050
051        List<Node> nodes = namesToNodes.get(name);
052        if (nodes == null) {
053            namesToNodes.put(name, nodes = new ArrayList<Node>());
054        }
055
056        nodes.add(n);
057    }
058
059    @Override
060    public void endTest() {
061        for (List<Node> nodes : namesToNodes.values()) {
062            if (nodes.size() > 1) {
063                // Report the same-name nodes, unless each has a unique ref=*.
064                HashSet<String> refs = new HashSet<String>();
065
066                for (Node n : nodes) {
067                    String ref = n.get("ref");
068                    if (ref == null || !refs.add(ref)) {
069                        errors.add(new TestError(this, Severity.OTHER,
070                                tr("Nodes with same name"), SAME_NAME, nodes));
071                        break;
072                    }
073                }
074            }
075        }
076        super.endTest();
077        namesToNodes = null;
078    }
079}