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.ArrayList;
007import java.util.List;
008
009import org.openstreetmap.josm.data.osm.Relation;
010import org.openstreetmap.josm.data.osm.RelationMember;
011import org.openstreetmap.josm.data.validation.Severity;
012import org.openstreetmap.josm.data.validation.Test;
013import org.openstreetmap.josm.data.validation.TestError;
014import org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType;
015import org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionTypeCalculator;
016
017/**
018 * Tests for <a href="https://wiki.openstreetmap.org/wiki/Proposed_features/Public_Transport">public transport routes</a>.
019 */
020public class PublicTransportRouteTest extends Test {
021
022    private final WayConnectionTypeCalculator connectionTypeCalculator = new WayConnectionTypeCalculator();
023
024    /**
025     * Constructs a new {@code PublicTransportRouteTest}.
026     */
027    public PublicTransportRouteTest() {
028        super(tr("Public Transport Route"));
029    }
030
031    @Override
032    public void visit(Relation r) {
033        final boolean skip = r.hasIncompleteMembers()
034                || !r.hasTag("type", "route")
035                || !r.hasKey("route")
036                || !r.hasTag("public_transport:version", "2");
037        if (skip) {
038            return;
039        }
040
041        final List<RelationMember> membersToCheck = new ArrayList<>();
042        for (RelationMember member : r.getMembers()) {
043            if (member.hasRole("forward", "backward")) {
044                errors.add(new TestError(this, Severity.WARNING, tr("Route relation contains a ''{0}'' role", "forward/backward"), 3601, r));
045                return;
046            } else if (member.hasRole("")) {
047                membersToCheck.add(member);
048            }
049        }
050        if (membersToCheck.isEmpty()) {
051            return;
052        }
053
054        final List<WayConnectionType> links = connectionTypeCalculator.updateLinks(membersToCheck);
055        for (int i = 0; i < links.size(); i++) {
056            final WayConnectionType link = links.get(i);
057            final boolean hasError = !(i == 0 || link.linkPrev)
058                    || !(i == links.size() - 1 || link.linkNext)
059                    || link.direction == null
060                    || WayConnectionType.Direction.NONE.equals(link.direction);
061            if (hasError) {
062                errors.add(new TestError(this, Severity.WARNING, tr("Route relation contains a gap"), 3602, r));
063                return;
064            }
065        }
066
067    }
068}