001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.validation.tests;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.util.Arrays;
007import java.util.List;
008
009import org.openstreetmap.josm.data.osm.Node;
010import org.openstreetmap.josm.data.osm.OsmPrimitive;
011import org.openstreetmap.josm.data.osm.Relation;
012import org.openstreetmap.josm.data.osm.Way;
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.mappaint.ElemStyles;
017
018/**
019 * Checks for ways connected to areas.
020 * @since 4682
021 */
022public class WayConnectedToArea extends Test {
023
024    /**
025     * Constructs a new {@code WayConnectedToArea} test.
026     */
027    public WayConnectedToArea() {
028        super(tr("Way connected to Area"), tr("Checks for ways connected to areas."));
029    }
030
031    @Override
032    public void visit(Way w) {
033        if (!w.isUsable() || w.isClosed() || !w.hasKey("highway")) {
034            return;
035        }
036
037        boolean hasway = false;
038        List<OsmPrimitive> r = w.firstNode().getReferrers();
039        for (OsmPrimitive p : r) {
040            if(p != w && p.hasKey("highway")) {
041                hasway = true;
042                break;
043            }
044        }
045        if (!hasway) {
046            for (OsmPrimitive p : r) {
047                testForError(w, w.firstNode(), p);
048            }
049        }
050        hasway = false;
051        r = w.lastNode().getReferrers();
052        for (OsmPrimitive p : r) {
053            if(p != w && p.hasKey("highway")) {
054                hasway = true;
055                break;
056            }
057        }
058        if (!hasway) {
059            for (OsmPrimitive p : r) {
060                testForError(w, w.lastNode(), p);
061            }
062        }
063    }
064
065    private void testForError(Way w, Node wayNode, OsmPrimitive p) {
066        if (isArea(p)) {
067            addError(w, wayNode, p);
068        } else {
069            for (OsmPrimitive r : p.getReferrers()) {
070                if (r instanceof Relation
071                        && r.hasTag("type", "multipolygon")
072                        && isArea(r)) {
073                    addError(w, wayNode, p);
074                    break;
075                }
076            }
077        }
078    }
079
080    private boolean isArea(OsmPrimitive p) {
081        return (p.hasKey("landuse") || p.hasKey("natural"))
082                && ElemStyles.hasAreaElemStyle(p, false);
083    }
084
085    private void addError(Way w, Node wayNode, OsmPrimitive p) {
086        errors.add(new TestError(this, Severity.WARNING,
087                tr("Way terminates on Area"), 2301,
088                Arrays.asList(w, p),
089                Arrays.asList(wayNode)));
090    }
091}