All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opentripplanner.api.parameter.QualifiedModeSet Maven / Gradle / Ivy

package org.opentripplanner.api.parameter;

import com.beust.jcommander.internal.Sets;
import org.opentripplanner.model.modes.AllowedTransitMode;
import org.opentripplanner.routing.api.request.RequestModes;
import org.opentripplanner.routing.api.request.StreetMode;

import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.function.Predicate;

/**
 * A set of qualified modes. The original intent was to allow a sequence of mode sets, but the shift to "long distance
 * mode" routing means that it will make more sense to specify access, egress, and transit modes in separate parameters. 
 * So now this only contains one mode set rather than a sequence of them.
 *  
 * This class and QualifiedMode are clearly somewhat inefficient and allow nonsensical combinations like
 * renting and parking a subway. They are not intended for use in routing. Rather, they simply parse the
 * language of mode specifications that may be given in the mode query parameter. They are then converted
 * into more efficient and useful representation in the routing request.
 */
public class QualifiedModeSet implements Serializable {
    private static final long serialVersionUID = 1L;
    
    public Set qModes = Sets.newHashSet();

    public QualifiedModeSet(String s) {
        for (String qMode : s.split(",")) {
            qModes.add(new QualifiedMode(qMode));
        }
    }

    public RequestModes getRequestModes() {
        StreetMode accessMode = null;
        StreetMode egressMode = null;
        StreetMode directMode = null;
        StreetMode transferMode = null;

        // Set transit modes
        Set transitModes = qModes
            .stream()
            .flatMap(q -> q.mode.getTransitModes().stream())
            .collect(Collectors.toSet());

        //  This is a best effort at mapping QualifiedModes to access/egress/direct StreetModes.
        //  It was unclear what exactly each combination of QualifiedModes should mean.
        //  TODO OTP2 This should either be updated with missing modes or the REST API should be
        //   redesigned to better reflect the mode structure used in RequestModes.
        //   Also, some StreetModes are implied by combination of QualifiedModes and are not covered
        //   in this mapping.
        QualifiedMode requestMode = null;

        List filteredModes = qModes.stream()
                .filter(m ->
                        m.mode == ApiRequestMode.WALK ||
                        m.mode == ApiRequestMode.BICYCLE ||
                        m.mode == ApiRequestMode.SCOOTER ||
                        m.mode == ApiRequestMode.CAR)
                .collect(Collectors.toList());

        if (filteredModes.size() > 1) {
            List filteredModesWithoutWalk = filteredModes.stream()
                    .filter(Predicate.not(m -> m.mode == ApiRequestMode.WALK))
                    .collect(Collectors.toList());
            if (filteredModesWithoutWalk.size() > 1) {
                throw new IllegalStateException("Multiple non-walk modes provided " + filteredModesWithoutWalk);
            } else if (filteredModesWithoutWalk.isEmpty()) {
                requestMode = filteredModes.get(0);
            } else {
                requestMode = filteredModesWithoutWalk.get(0);
            }
        } else if (!filteredModes.isEmpty()) {
            requestMode = filteredModes.get(0);
        }

        if(requestMode != null) {
            switch (requestMode.mode) {
                case WALK:
                    accessMode = StreetMode.WALK;
                    transferMode = StreetMode.WALK;
                    egressMode = StreetMode.WALK;
                    directMode = StreetMode.WALK;
                    break;
                case BICYCLE:
                    if (requestMode.qualifiers.contains(Qualifier.RENT)) {
                        accessMode = StreetMode.BIKE_RENTAL;
                        transferMode = StreetMode.BIKE_RENTAL;
                        egressMode = StreetMode.BIKE_RENTAL;
                        directMode = StreetMode.BIKE_RENTAL;
                    } else if (requestMode.qualifiers.contains(Qualifier.PARK)) {
                        accessMode = StreetMode.BIKE_TO_PARK;
                        transferMode = StreetMode.WALK;
                        egressMode = StreetMode.WALK;
                        directMode = StreetMode.BIKE_TO_PARK;
                    } else {
                        accessMode = StreetMode.BIKE;
                        transferMode = StreetMode.BIKE;
                        egressMode = StreetMode.BIKE;
                        directMode = StreetMode.BIKE;
                    }
                    break;
                case SCOOTER:
                    if (requestMode.qualifiers.contains(Qualifier.RENT)) {
                        accessMode = StreetMode.SCOOTER_RENTAL;
                        transferMode = StreetMode.SCOOTER_RENTAL;
                        egressMode = StreetMode.SCOOTER_RENTAL;
                        directMode = StreetMode.SCOOTER_RENTAL;
                    } else {
                        // Only supported as rental mode
                        throw new IllegalArgumentException();
                    }
                    break;
                case CAR:
                    if (requestMode.qualifiers.contains(Qualifier.RENT)) {
                        accessMode = StreetMode.CAR_RENTAL;
                        transferMode = StreetMode.CAR_RENTAL;
                        egressMode = StreetMode.CAR_RENTAL;
                        directMode = StreetMode.CAR_RENTAL;
                    } else if (requestMode.qualifiers.contains(Qualifier.PARK)) {
                        accessMode = StreetMode.CAR_TO_PARK;
                        transferMode = StreetMode.WALK;
                        egressMode = StreetMode.WALK;
                        directMode = StreetMode.CAR_TO_PARK;
                    } else if (requestMode.qualifiers.contains(Qualifier.PICKUP)) {
                        accessMode = StreetMode.WALK;
                        transferMode = StreetMode.WALK;
                        egressMode = StreetMode.CAR_PICKUP;
                        directMode = StreetMode.CAR_PICKUP;
                    } else if (requestMode.qualifiers.contains(Qualifier.DROPOFF)) {
                        accessMode = StreetMode.CAR_PICKUP;
                        transferMode = StreetMode.WALK;
                        egressMode = StreetMode.WALK;
                        directMode = StreetMode.CAR_PICKUP;
                    } else {
                        accessMode = StreetMode.WALK;
                        transferMode = StreetMode.WALK;
                        egressMode = StreetMode.WALK;
                        directMode = StreetMode.CAR;
                    }
                    break;
            }
        }

        // These modes are set last in order to take precedence over other modes
        for (QualifiedMode qMode : qModes) {
            if (qMode.mode.equals(ApiRequestMode.FLEX)) {
                if (qMode.qualifiers.contains(Qualifier.ACCESS)) {
                    accessMode = StreetMode.FLEXIBLE;
                } else if (qMode.qualifiers.contains(Qualifier.EGRESS)) {
                    egressMode = StreetMode.FLEXIBLE;
                } else if (qMode.qualifiers.contains(Qualifier.DIRECT)) {
                    directMode = StreetMode.FLEXIBLE;
                }
            }
        }

        // If we search eg. Transit + flex access and egress, fallback to walking transfers
        if (transferMode == null) {
            transferMode = StreetMode.WALK;
        }

        return new RequestModes(
            accessMode,
            transferMode,
            egressMode,
            directMode,
            transitModes
        );
    }
    
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (QualifiedMode qm : qModes) {
            sb.append(qm.toString());
            sb.append(" ");
        }
        return sb.toString();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy