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.Arrays;
007import java.util.Collections;
008import java.util.Iterator;
009
010import org.openstreetmap.josm.command.ChangeCommand;
011import org.openstreetmap.josm.command.Command;
012import org.openstreetmap.josm.data.osm.Node;
013import org.openstreetmap.josm.data.osm.OsmPrimitive;
014import org.openstreetmap.josm.data.osm.Way;
015import org.openstreetmap.josm.data.validation.Severity;
016import org.openstreetmap.josm.data.validation.Test;
017import org.openstreetmap.josm.data.validation.TestError;
018
019/**
020 * Checks for ways with identical consecutive nodes.
021 * @since 3669
022 */
023public class DuplicatedWayNodes extends Test {
024    protected static final int DUPLICATE_WAY_NODE = 501;
025
026    /**
027     * Constructs a new {@code DuplicatedWayNodes} test.
028     */
029    public DuplicatedWayNodes() {
030        super(tr("Duplicated way nodes"),
031                tr("Checks for ways with identical consecutive nodes."));
032    }
033
034    @Override
035    public void visit(Way w) {
036        if (!w.isUsable()) return;
037
038        Node lastN = null;
039        for (Node n : w.getNodes()) {
040            if (lastN == null) {
041                lastN = n;
042                continue;
043            }
044            if (lastN == n) {
045                errors.add(new TestError(this, Severity.ERROR, tr("Duplicated way nodes"), DUPLICATE_WAY_NODE,
046                        Arrays.asList(w), Arrays.asList(n)));
047                break;
048            }
049            lastN = n;
050        }
051    }
052
053    @Override
054    public Command fixError(TestError testError) {
055        // primitives list can be empty if all primitives have been purged
056        Iterator<? extends OsmPrimitive> it = testError.getPrimitives().iterator();
057        if (it.hasNext()) {
058            Way w = (Way) it.next();
059            Way wnew = new Way(w);
060            wnew.setNodes(null);
061            Node lastN = null;
062            for (Node n : w.getNodes()) {
063                if (lastN == null) {
064                    wnew.addNode(n);
065                } else if (n == lastN) {
066                    // Skip this node
067                } else {
068                    wnew.addNode(n);
069                }
070                lastN = n;
071            }
072            if (wnew.getNodesCount() < 2)
073                // Empty way, delete
074                return deletePrimitivesIfNeeded(Collections.singleton(w));
075            else
076                return new ChangeCommand(w, wnew);
077        }
078        return null;
079    }
080
081    @Override
082    public boolean isFixable(TestError testError) {
083        return testError.getTester() instanceof DuplicatedWayNodes;
084    }
085}