// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.plugins.turnlanes.gui; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.openstreetmap.josm.plugins.turnlanes.gui.RoadGui.ViaConnector; import org.openstreetmap.josm.plugins.turnlanes.model.Junction; import org.openstreetmap.josm.plugins.turnlanes.model.Lane; import org.openstreetmap.josm.plugins.turnlanes.model.Road; abstract class State { static class AllTurns extends State { private final State wrapped; AllTurns(State wrapped) { this.wrapped = wrapped; } public State unwrap() { return wrapped; } @Override State carryOver(GuiContainer newContainer) { return new AllTurns(wrapped.carryOver(newContainer)); } } static class Connecting extends State { private final Lane lane; private final List<RoadGui.ViaConnector> vias; Connecting(Lane lane) { this(lane, Collections.<RoadGui.ViaConnector>emptyList()); } Connecting(Lane lane, List<ViaConnector> vias) { this.lane = lane; this.vias = vias; } public Connecting next(RoadGui.ViaConnector via) { if (vias.isEmpty()) { return new Connecting(lane, Collections.unmodifiableList(Arrays.asList(via))); } final List<RoadGui.ViaConnector> tmp = new ArrayList<>(vias.size() + 1); final boolean even = (vias.size() & 1) == 0; final RoadGui.ViaConnector last = vias.get(vias.size() - 1); if (last.equals(via) || !even && last.getRoadEnd().getJunction().equals(via.getRoadEnd().getJunction())) { return pop().next(via); } if (vias.size() >= 2) { if (lane.getOutgoingJunction().equals(via.getRoadEnd().getJunction())) { return new Connecting(lane); } else if (via.equals(getBacktrackViaConnector())) { return new Connecting(lane, vias.subList(0, vias.size() - 1)); } } for (RoadGui.ViaConnector v : vias) { tmp.add(v); if (!(even && v.equals(last)) && v.getRoadEnd().getJunction().equals(via.getRoadEnd().getJunction())) { return new Connecting(lane, Collections.unmodifiableList(tmp)); } } tmp.add(via); return new Connecting(lane, Collections.unmodifiableList(tmp)); } public Junction getJunction() { return vias.isEmpty() ? lane.getOutgoingJunction() : vias.get(vias.size() - 1).getRoadEnd().getJunction(); } public RoadGui.ViaConnector getBacktrackViaConnector() { return vias.size() < 2 ? null : vias.get(vias.size() - 2); } public List<RoadGui.ViaConnector> getViaConnectors() { return vias; } public Lane getLane() { return lane; } public Connecting pop() { return new Connecting(lane, vias.subList(0, vias.size() - 1)); } } static class Invalid extends State { private final State wrapped; Invalid(State wrapped) { this.wrapped = wrapped; } public State unwrap() { return wrapped; } } static class Dirty extends State { private final State wrapped; Dirty(State wrapped) { this.wrapped = wrapped; } public State unwrap() { return wrapped; } @Override State carryOver(GuiContainer newContainer) { return new Dirty(wrapped.carryOver(newContainer)); } } static class Default extends State { Default() {} } static class IncomingActive extends State { private final Road.End roadEnd; IncomingActive(Road.End roadEnd) { this.roadEnd = roadEnd; } public Road.End getRoadEnd() { return roadEnd; } @Override State carryOver(GuiContainer newContainer) { if (newContainer.getModel().equals(roadEnd.getRoad().getContainer())) { return this; } final Junction newJunction = newContainer.getModel().getJunction(roadEnd.getJunction().getNode()); for (Road.End e : newJunction.getRoadEnds()) { if (e.isToEnd() && e.getWay().equals(roadEnd.getWay())) { return new IncomingActive(e); } } return new Default(); } } static class OutgoingActive extends State { private final LaneGui lane; OutgoingActive(LaneGui lane) { this.lane = lane; } public LaneGui getLane() { return lane; } @Override State delete() { if (!lane.getModel().isExtra()) { return this; } lane.getModel().remove(); return new Invalid(this); } @Override State carryOver(GuiContainer newContainer) { if (newContainer.equals(lane.getContainer())) { return this; } final Lane model = lane.getModel(); final Junction newJunction = newContainer.getModel().getJunction(model.getOutgoingJunction().getNode()); for (Road.End e : newJunction.getRoadEnds()) { if (e.isToEnd() && e.getWay().equals(model.getOutgoingRoadEnd().getWay())) { for (Lane l : e.getLanes()) { // e.getLane(...) can fail on lane removal if (l.getKind() == model.getKind() && l.getIndex() == model.getIndex()) { return new OutgoingActive(newContainer.getGui(l)); } } break; } } return new Default(); } } State delete() { return this; } State carryOver(GuiContainer newContainer) { return this; } }