mirror of
https://gitlab.com/oeffi/public-transport-enabler.git
synced 2025-07-15 17:10:30 +00:00
Negentwee: New provider for the Netherlands.
This commit is contained in:
parent
dd809adfd0
commit
a60313edf9
5 changed files with 1059 additions and 1 deletions
875
enabler/src/de/schildbach/pte/NegentweeProvider.java
Normal file
875
enabler/src/de/schildbach/pte/NegentweeProvider.java
Normal file
|
@ -0,0 +1,875 @@
|
|||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.schildbach.pte;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Currency;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import de.schildbach.pte.dto.Departure;
|
||||
import de.schildbach.pte.dto.Fare;
|
||||
import de.schildbach.pte.dto.Line;
|
||||
import de.schildbach.pte.dto.LineDestination;
|
||||
import de.schildbach.pte.dto.Location;
|
||||
import de.schildbach.pte.dto.LocationType;
|
||||
import de.schildbach.pte.dto.NearbyLocationsResult;
|
||||
import de.schildbach.pte.dto.Point;
|
||||
import de.schildbach.pte.dto.Position;
|
||||
import de.schildbach.pte.dto.Product;
|
||||
import de.schildbach.pte.dto.QueryDeparturesResult;
|
||||
import de.schildbach.pte.dto.QueryTripsContext;
|
||||
import de.schildbach.pte.dto.QueryTripsResult;
|
||||
import de.schildbach.pte.dto.ResultHeader;
|
||||
import de.schildbach.pte.dto.StationDepartures;
|
||||
import de.schildbach.pte.dto.Stop;
|
||||
import de.schildbach.pte.dto.SuggestLocationsResult;
|
||||
import de.schildbach.pte.dto.SuggestedLocation;
|
||||
import de.schildbach.pte.dto.Trip;
|
||||
import de.schildbach.pte.exception.InternalErrorException;
|
||||
import de.schildbach.pte.exception.NotFoundException;
|
||||
import de.schildbach.pte.util.ParserUtils;
|
||||
import de.schildbach.pte.util.WordUtils;
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
/**
|
||||
* @author full-duplex
|
||||
*/
|
||||
public class NegentweeProvider extends AbstractNetworkProvider {
|
||||
|
||||
private static final String API_BASE = "https://api.9292.nl/0.1/";
|
||||
private static final String SERVER_PRODUCT = "negentwee";
|
||||
|
||||
private static final Language DEFAULT_API_LANG = Language.NL_NL;
|
||||
private static final int DEFAULT_MAX_LOCATIONS = 50;
|
||||
|
||||
private static final SimpleDateFormat dateTimeParser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm");
|
||||
private static final SimpleDateFormat timeParser = new SimpleDateFormat("HH:mm");
|
||||
|
||||
private static final EnumSet<Product> trainProducts = EnumSet.of(Product.HIGH_SPEED_TRAIN, Product.REGIONAL_TRAIN,
|
||||
Product.SUBURBAN_TRAIN);
|
||||
|
||||
private final Language language;
|
||||
private final ResultHeader resultHeader;
|
||||
|
||||
public enum Language {
|
||||
NL_NL("nl-NL"), EN_GB("en-GB");
|
||||
|
||||
private final String lang;
|
||||
|
||||
private Language(String lang) {
|
||||
this.lang = lang;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.lang;
|
||||
}
|
||||
}
|
||||
|
||||
private enum InterchangeTime {
|
||||
STANDARD, EXTRA;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class QueryParameter implements Serializable {
|
||||
public String name, value;
|
||||
|
||||
private QueryParameter(String name, String value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name + "=" + this.value;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class TripsContext implements QueryTripsContext {
|
||||
private String url, earlier, later;
|
||||
public Location from, to, via;
|
||||
|
||||
private TripsContext(HttpUrl url, @Nullable String earlier, @Nullable String later, Location from,
|
||||
@Nullable Location via, Location to) {
|
||||
this.url = url.toString();
|
||||
this.earlier = earlier;
|
||||
this.later = later;
|
||||
this.from = from;
|
||||
this.via = via;
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
private HttpUrl getQueryEarlier() {
|
||||
return HttpUrl.parse(this.url).newBuilder(this.earlier).addQueryParameter("before", "4").build();
|
||||
}
|
||||
|
||||
private HttpUrl getQueryLater() {
|
||||
return HttpUrl.parse(this.url).newBuilder(this.later).addQueryParameter("after", "4").build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canQueryEarlier() {
|
||||
return (earlier != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canQueryLater() {
|
||||
return (later != null);
|
||||
}
|
||||
}
|
||||
|
||||
public NegentweeProvider() {
|
||||
this(DEFAULT_API_LANG);
|
||||
}
|
||||
|
||||
public NegentweeProvider(Language language) {
|
||||
super(NetworkId.NEGENTWEE);
|
||||
|
||||
this.language = language;
|
||||
this.resultHeader = new ResultHeader(network, SERVER_PRODUCT);
|
||||
}
|
||||
|
||||
private HttpUrl buildApiUrl(String action, List<QueryParameter> queries) {
|
||||
HttpUrl.Builder url = HttpUrl.parse(API_BASE).newBuilder().addPathSegments(action).addQueryParameter("lang",
|
||||
this.language.toString());
|
||||
|
||||
for (QueryParameter q : queries) {
|
||||
url.addQueryParameter(q.name, q.value);
|
||||
}
|
||||
|
||||
return url.build();
|
||||
}
|
||||
|
||||
private Location queryLocationById(String stationId) throws IOException {
|
||||
HttpUrl url = buildApiUrl("locations/" + stationId, new ArrayList<QueryParameter>());
|
||||
final CharSequence page = httpClient.get(url);
|
||||
|
||||
try {
|
||||
JSONObject head = new JSONObject(page.toString());
|
||||
JSONObject location = head.getJSONObject("location");
|
||||
|
||||
return locationFromJSONObject(location);
|
||||
} catch (final JSONException x) {
|
||||
throw new IOException("cannot parse: '" + page + "' on " + url, x);
|
||||
}
|
||||
}
|
||||
|
||||
private Location queryLocationByName(String locationName, EnumSet<LocationType> types) throws IOException {
|
||||
for (Location location : queryLocationsByName(locationName, types)) {
|
||||
if (location.name != null && location.name.equals(locationName)) {
|
||||
return location;
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("Cannot find station with name " + locationName);
|
||||
}
|
||||
|
||||
private List<Location> queryLocationsByName(String locationName, EnumSet<LocationType> types) throws IOException {
|
||||
List<QueryParameter> queryParameters = new ArrayList<>();
|
||||
queryParameters.add(new QueryParameter("q", locationName));
|
||||
|
||||
if (!types.contains(LocationType.ANY) && types.size() > 0) {
|
||||
StringBuilder typeValue = new StringBuilder();
|
||||
for (LocationType type : types) {
|
||||
for (String addition : locationStringsFromLocationType(type)) {
|
||||
if (typeValue.length() > 0)
|
||||
typeValue.append(",");
|
||||
typeValue.append(addition);
|
||||
}
|
||||
}
|
||||
queryParameters.add(new QueryParameter("type", typeValue.toString()));
|
||||
}
|
||||
|
||||
HttpUrl url = buildApiUrl("locations", queryParameters);
|
||||
final CharSequence page = httpClient.get(url);
|
||||
|
||||
try {
|
||||
JSONObject head = new JSONObject(page.toString());
|
||||
JSONArray locations = head.getJSONArray("locations");
|
||||
|
||||
Location[] foundLocations = new Location[locations.length()];
|
||||
for (int i = 0; i < locations.length(); i++) {
|
||||
foundLocations[i] = locationFromJSONObject(locations.getJSONObject(i));
|
||||
}
|
||||
|
||||
return Arrays.asList(foundLocations);
|
||||
} catch (final JSONException x) {
|
||||
throw new RuntimeException("cannot parse: '" + page + "' on " + url, x);
|
||||
}
|
||||
}
|
||||
|
||||
private Point pointFromLocation(Location location) throws JSONException {
|
||||
return new Point(location.lat, location.lon);
|
||||
}
|
||||
|
||||
private LocationType locationTypeFromTypeString(String type) throws JSONException {
|
||||
switch (type) {
|
||||
case "station":
|
||||
case "stop":
|
||||
return LocationType.STATION;
|
||||
case "address":
|
||||
case "street":
|
||||
case "streetrange":
|
||||
case "place":
|
||||
case "postcode":
|
||||
return LocationType.ADDRESS;
|
||||
case "poi":
|
||||
return LocationType.POI;
|
||||
case "latlong":
|
||||
return LocationType.COORD;
|
||||
default:
|
||||
throw new JSONException("Unsupported location type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> locationStringsFromLocationType(LocationType type) {
|
||||
switch (type) {
|
||||
case STATION:
|
||||
return Arrays.asList("station", "stop");
|
||||
case POI:
|
||||
return Arrays.asList("poi");
|
||||
case ADDRESS:
|
||||
return Arrays.asList("address", "street", "streetrange", "place", "postcode");
|
||||
case COORD:
|
||||
return Arrays.asList("latlong");
|
||||
default:
|
||||
return Arrays.asList();
|
||||
}
|
||||
}
|
||||
|
||||
private EnumSet<Product> productSetFromTypeString(String type) {
|
||||
switch (type.toLowerCase()) {
|
||||
case "train":
|
||||
return EnumSet.of(Product.HIGH_SPEED_TRAIN, Product.REGIONAL_TRAIN, Product.SUBURBAN_TRAIN);
|
||||
case "subway":
|
||||
return EnumSet.of(Product.SUBWAY);
|
||||
case "tram":
|
||||
return EnumSet.of(Product.TRAM);
|
||||
case "bus":
|
||||
return EnumSet.of(Product.BUS);
|
||||
case "ferry":
|
||||
return EnumSet.of(Product.FERRY);
|
||||
case "walk":
|
||||
return EnumSet.of(Product.ON_DEMAND);
|
||||
default:
|
||||
return EnumSet.noneOf(Product.class);
|
||||
}
|
||||
}
|
||||
|
||||
private Product productFromMode(String type, String name) {
|
||||
switch (type.toLowerCase()) {
|
||||
case "train":
|
||||
switch (name.toLowerCase()) {
|
||||
// TODO: Likely not all possible train names, add here if trains are classified incorrectly.
|
||||
case "thalys":
|
||||
case "ice":
|
||||
case "intercity direct":
|
||||
case "intercity":
|
||||
return Product.HIGH_SPEED_TRAIN;
|
||||
case "sprinter":
|
||||
default:
|
||||
return Product.REGIONAL_TRAIN;
|
||||
}
|
||||
case "tram":
|
||||
return Product.TRAM;
|
||||
case "subway":
|
||||
return Product.SUBWAY;
|
||||
case "bus":
|
||||
return Product.BUS;
|
||||
case "ferry":
|
||||
return Product.FERRY;
|
||||
case "walk":
|
||||
return Product.ON_DEMAND;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Date dateFromJSONObject(JSONObject obj, String key) throws JSONException {
|
||||
try {
|
||||
return dateTimeParser.parse(obj.getString(key));
|
||||
} catch (ParseException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Date timeFromJSONObject(JSONObject obj, String key) throws JSONException {
|
||||
try {
|
||||
return timeParser.parse(obj.getString(key));
|
||||
} catch (ParseException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Date realtimeDateFromJSONObject(JSONObject obj, String key, String realtimeKey) throws JSONException {
|
||||
return dateFromJSONObject(obj, (!obj.isNull(realtimeKey)) ? realtimeKey : key);
|
||||
}
|
||||
|
||||
private Trip tripFromJSONObject(JSONObject trip, @Nullable Location from, @Nullable Location to,
|
||||
@Nullable Map<String, JSONObject> disturbances) throws JSONException {
|
||||
JSONArray legs = trip.getJSONArray("legs");
|
||||
|
||||
Date tripDeparture = realtimeDateFromJSONObject(trip, "departure", "realtimeDeparture");
|
||||
/* Date tripArrival = */ realtimeDateFromJSONObject(trip, "arrival", "realtimeArrival");
|
||||
|
||||
// Get journey legs
|
||||
LinkedList<Trip.Leg> foundLegs = new LinkedList<>();
|
||||
for (int i = 0; i < legs.length(); i++) {
|
||||
JSONObject leg = legs.getJSONObject(i);
|
||||
|
||||
JSONArray stops = leg.getJSONArray("stops");
|
||||
JSONObject mode = leg.getJSONObject("mode");
|
||||
JSONObject operator = leg.optJSONObject("operator");
|
||||
|
||||
LinkedList<Point> foundPoints = new LinkedList<>();
|
||||
|
||||
// First stop
|
||||
Stop firstStop = stopFromJSONObject(stops.getJSONObject(0));
|
||||
foundPoints.add(pointFromLocation(firstStop.location));
|
||||
|
||||
// Intermediate stops
|
||||
LinkedList<Stop> foundStops = new LinkedList<>();
|
||||
for (int j = 1; j < stops.length() - 1; j++) {
|
||||
foundStops.add(stopFromJSONObject(stops.getJSONObject(j)));
|
||||
foundPoints.add(pointFromLocation(foundStops.getLast().location));
|
||||
}
|
||||
|
||||
// Last stop
|
||||
Stop lastStop = stopFromJSONObject(stops.getJSONObject(stops.length() - 1));
|
||||
foundPoints.add(pointFromLocation(lastStop.location));
|
||||
|
||||
switch (leg.getString("type").toLowerCase()) {
|
||||
case "scheduled":
|
||||
Product lineProduct = productFromMode(mode.getString("type"), mode.getString("name"));
|
||||
|
||||
StringBuilder legMessage = new StringBuilder();
|
||||
|
||||
// Add attributes to leg message
|
||||
JSONArray legAttributes = leg.getJSONArray("attributes");
|
||||
for (int k = 0; k < legAttributes.length(); k++) {
|
||||
JSONObject legAttribute = legAttributes.getJSONObject(k);
|
||||
|
||||
if (legMessage.length() > 0)
|
||||
legMessage.append(", ");
|
||||
legMessage.append(WordUtils.capitalizeFirst(legAttribute.getString("title")));
|
||||
}
|
||||
|
||||
// Add disturbances to leg message
|
||||
if (disturbances != null) {
|
||||
JSONArray legDisturbances = leg.getJSONArray("disturbancePlannerIds");
|
||||
for (int k = 0; k < legDisturbances.length(); k++) {
|
||||
String legDisturbanceId = legDisturbances.optString(k);
|
||||
|
||||
if (legDisturbanceId != null && disturbances.containsKey(legDisturbanceId)) {
|
||||
JSONObject legDisturbance = disturbances.get(legDisturbanceId);
|
||||
|
||||
if (legMessage.length() > 0)
|
||||
legMessage.append("<br>\n<br>\n");
|
||||
legMessage.append(legDisturbance.getString("title"));
|
||||
legMessage.append(":<br>\n");
|
||||
legMessage.append(legDisturbance.getString("effect"));
|
||||
legMessage.append(" ");
|
||||
legMessage.append(legDisturbance.getString("measure"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder lineName = new StringBuilder();
|
||||
lineName.append(mode.getString("name"));
|
||||
|
||||
// Service codes have no relevant meaning for trains
|
||||
if (!leg.isNull("service") && !trainProducts.contains(lineProduct)) {
|
||||
lineName.append(" ");
|
||||
lineName.append(leg.getString("service"));
|
||||
}
|
||||
|
||||
foundLegs.add(new Trip.Public(
|
||||
new Line(leg.getString("service"), (operator != null) ? operator.getString("name") : null,
|
||||
lineProduct, lineName.toString(), leg.optString("service"),
|
||||
Standard.STYLES.get(lineProduct), null, null),
|
||||
new Location(LocationType.STATION, null, null, leg.getString("destination")), firstStop,
|
||||
lastStop, foundStops, foundPoints, legMessage.length() > 0 ? legMessage.toString() : null));
|
||||
break;
|
||||
case "continuous":
|
||||
// Get leg time from trip or previous leg
|
||||
Date legDeparture = (i == 0) ? tripDeparture : foundLegs.getLast().getArrivalTime();
|
||||
Date legArrival = ParserUtils.addMinutes(legDeparture,
|
||||
ParserUtils.parseMinutesFromTimeString(leg.getString("duration")));
|
||||
|
||||
foundLegs.add(new Trip.Individual(Trip.Individual.Type.WALK, firstStop.location, legDeparture,
|
||||
lastStop.location, legArrival, foundPoints, -1));
|
||||
break;
|
||||
default:
|
||||
throw new JSONException("Unknown leg type: " + leg.getString("type"));
|
||||
}
|
||||
}
|
||||
|
||||
// Get journey fares
|
||||
JSONObject fareInfo = trip.getJSONObject("fareInfo");
|
||||
JSONArray fareLegs = fareInfo.getJSONArray("legs");
|
||||
|
||||
Fare[] foundFares = new Fare[fareLegs.length()];
|
||||
for (int i = 0; i < fareLegs.length(); i++) {
|
||||
foundFares[i] = fareFromJSONObject(fareLegs.getJSONObject(i));
|
||||
}
|
||||
|
||||
return new Trip(trip.getString("id"), from, to, foundLegs, Arrays.asList(foundFares), null,
|
||||
trip.getInt("numberOfChanges"));
|
||||
}
|
||||
|
||||
private Stop stopFromJSONObject(JSONObject stop) throws JSONException {
|
||||
Position plannedPlatform = positionFromJSONObject(stop, "platform");
|
||||
Position changedPlatform = positionFromJSONObject(stop, "platformChange");
|
||||
|
||||
return new Stop(locationFromJSONObject(stop.getJSONObject("location")), dateFromJSONObject(stop, "arrival"),
|
||||
dateFromJSONObject(stop, "realtimeArrival"), plannedPlatform, changedPlatform, false,
|
||||
dateFromJSONObject(stop, "departure"), dateFromJSONObject(stop, "realtimeDeparture"), plannedPlatform,
|
||||
changedPlatform, false);
|
||||
}
|
||||
|
||||
private Fare fareFromJSONObject(JSONObject fareLeg) throws JSONException {
|
||||
JSONArray fares = fareLeg.getJSONArray("fares");
|
||||
|
||||
float farePrice = 0;
|
||||
for (int j = 0; j < fares.length(); j++) {
|
||||
JSONObject fare = fares.getJSONObject(j);
|
||||
|
||||
// Always get the full non-reduced 2nd class fare price
|
||||
String fareClass = fare.getString("class");
|
||||
if (!fare.getBoolean("reduced") && (fareClass.equals("none") || fareClass.equals("second"))) {
|
||||
farePrice = (fare.getInt("eurocents") / 100);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new Fare(fareLeg.getString("operatorString"), Fare.Type.ADULT, Currency.getInstance("EUR"), farePrice,
|
||||
null, null);
|
||||
}
|
||||
|
||||
private Departure departureFromJSONObject(JSONObject departure) throws JSONException {
|
||||
JSONObject mode = departure.getJSONObject("mode");
|
||||
|
||||
/* String lineName = */ departure.optString("service");
|
||||
Product lineProduct = productFromMode(mode.getString("type"), mode.getString("name"));
|
||||
return new Departure(timeFromJSONObject(departure, "time"), timeFromJSONObject(departure, "time"),
|
||||
new Line(null, departure.getString("operatorName"), lineProduct,
|
||||
!departure.isNull("service") ? departure.getString("service") : mode.getString("name"), null,
|
||||
Standard.STYLES.get(lineProduct), null, null),
|
||||
!departure.isNull("platform") ? new Position(departure.getString("platform")) : null,
|
||||
new Location(LocationType.STATION, null, null, departure.getString("destinationName")), null,
|
||||
!departure.isNull("realtimeText") ? departure.optString("realtimeText") : null);
|
||||
}
|
||||
|
||||
private Position positionFromJSONObject(JSONObject obj, String key) throws JSONException {
|
||||
String position = obj.getString(key);
|
||||
if (position != null && !position.equals("null")) {
|
||||
return new Position(position);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Location locationFromJSONObject(JSONObject location) throws JSONException {
|
||||
return locationFromJSONObject(location, true);
|
||||
}
|
||||
|
||||
private Location locationFromJSONObject(JSONObject location, boolean addTypePrefix) throws JSONException {
|
||||
JSONObject latlon = location.getJSONObject("latLong");
|
||||
JSONObject place = location.optJSONObject("place");
|
||||
|
||||
String locationType = location.getString("type");
|
||||
String locationName = location.getString("name");
|
||||
if (addTypePrefix && !location.isNull(locationType + "Type") && !locationType.equals("poi")) {
|
||||
locationName = location.getString(locationType + "Type") + " " + locationName;
|
||||
}
|
||||
|
||||
Point locationPoint = Point.fromDouble(latlon.getDouble("lat"), latlon.getDouble("long"));
|
||||
|
||||
return new Location(locationTypeFromTypeString(locationType), location.getString("id"), locationPoint.lat,
|
||||
locationPoint.lon, !(place == null) ? place.getString("name") : null, locationName, null);
|
||||
}
|
||||
|
||||
private List<Location> solveAmbiguousLocation(Location location) throws IOException {
|
||||
if (location.hasId()) {
|
||||
return Arrays.asList(location);
|
||||
} else if (location.hasLocation()) {
|
||||
return queryNearbyLocations(EnumSet.of(location.type), location, -1, -1).locations;
|
||||
} else if (location.hasName()) {
|
||||
return queryLocationsByName(location.name, EnumSet.of(location.type));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private QueryTripsResult ambiguousQueryTrips(Location from, @Nullable Location via, Location to)
|
||||
throws IOException {
|
||||
List<Location> ambiguousFrom = solveAmbiguousLocation(from);
|
||||
if (ambiguousFrom == null || ambiguousFrom.size() <= 0)
|
||||
return new QueryTripsResult(this.resultHeader, QueryTripsResult.Status.UNKNOWN_FROM);
|
||||
|
||||
List<Location> ambiguousTo = solveAmbiguousLocation(to);
|
||||
if (ambiguousTo == null || ambiguousTo.size() <= 0)
|
||||
return new QueryTripsResult(this.resultHeader, QueryTripsResult.Status.UNKNOWN_TO);
|
||||
|
||||
List<Location> ambiguousVia = null;
|
||||
if (via != null) {
|
||||
ambiguousVia = solveAmbiguousLocation(via);
|
||||
if (ambiguousVia == null || ambiguousVia.size() <= 0)
|
||||
return new QueryTripsResult(this.resultHeader, QueryTripsResult.Status.UNKNOWN_VIA);
|
||||
}
|
||||
|
||||
return new QueryTripsResult(this.resultHeader, ambiguousFrom, ambiguousVia, ambiguousTo);
|
||||
}
|
||||
|
||||
private QueryTripsResult queryTrips(HttpUrl url, Location from, @Nullable Location via, Location to)
|
||||
throws IOException {
|
||||
final CharSequence page;
|
||||
try {
|
||||
page = httpClient.get(url);
|
||||
} catch (InternalErrorException e) {
|
||||
return new QueryTripsResult(this.resultHeader, QueryTripsResult.Status.SERVICE_DOWN);
|
||||
}
|
||||
|
||||
List<Trip> foundTrips = new ArrayList<>();
|
||||
String tripsEarlier, tripsLater;
|
||||
try {
|
||||
final JSONObject head = new JSONObject(page.toString());
|
||||
|
||||
if (head.has("error")) {
|
||||
switch (head.getString("error")) {
|
||||
case "WithinWalkingDistance":
|
||||
return new QueryTripsResult(this.resultHeader, QueryTripsResult.Status.TOO_CLOSE);
|
||||
case "DateOutOfRange":
|
||||
return new QueryTripsResult(this.resultHeader, QueryTripsResult.Status.INVALID_DATE);
|
||||
case "UnknownLocations":
|
||||
String errorDetails = head.getString("details");
|
||||
if (errorDetails.startsWith("From:")) {
|
||||
return new QueryTripsResult(this.resultHeader, QueryTripsResult.Status.UNKNOWN_FROM);
|
||||
} else if (errorDetails.startsWith("Via:")) {
|
||||
return new QueryTripsResult(this.resultHeader, QueryTripsResult.Status.UNKNOWN_VIA);
|
||||
} else if (errorDetails.startsWith("To:")) {
|
||||
return new QueryTripsResult(this.resultHeader, QueryTripsResult.Status.UNKNOWN_TO);
|
||||
} else {
|
||||
return new QueryTripsResult(this.resultHeader, QueryTripsResult.Status.UNRESOLVABLE_ADDRESS);
|
||||
}
|
||||
default:
|
||||
return new QueryTripsResult(this.resultHeader, QueryTripsResult.Status.NO_TRIPS);
|
||||
}
|
||||
}
|
||||
|
||||
if (head.has("exception")) {
|
||||
return new QueryTripsResult(this.resultHeader, QueryTripsResult.Status.NO_TRIPS);
|
||||
}
|
||||
|
||||
final JSONArray trips = head.optJSONArray("journeys");
|
||||
|
||||
final JSONArray disturbances = head.optJSONArray("disturbances");
|
||||
|
||||
// Prepare disturbances mapping for leg messages
|
||||
Map<String, JSONObject> disturbancesMap;
|
||||
if (disturbances != null && disturbances.length() > 0) {
|
||||
disturbancesMap = new HashMap<>();
|
||||
for (int i = 0; i < disturbances.length(); i++) {
|
||||
JSONObject disturbance = disturbances.getJSONObject(i);
|
||||
disturbancesMap.put(disturbance.getString("plannerDisturbanceId"), disturbance);
|
||||
}
|
||||
} else {
|
||||
disturbancesMap = null;
|
||||
}
|
||||
|
||||
tripsEarlier = head.optString("earlier");
|
||||
tripsLater = head.optString("later");
|
||||
|
||||
for (int i = 0; i < trips.length(); i++) {
|
||||
JSONObject trip = trips.getJSONObject(i);
|
||||
|
||||
// Skip impossible trips
|
||||
if (trip.getJSONObject("realtimeInfo").getString("delays").equals("fatal"))
|
||||
continue;
|
||||
|
||||
foundTrips.add(tripFromJSONObject(trip, from, to, disturbancesMap));
|
||||
}
|
||||
} catch (final JSONException x) {
|
||||
throw new RuntimeException("cannot parse: '" + page + "' on " + url, x);
|
||||
}
|
||||
|
||||
return new QueryTripsResult(null, url.toString(), from, via, to,
|
||||
new TripsContext(url, tripsEarlier, tripsLater, from, via, to), foundTrips);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Product> defaultProducts() {
|
||||
return EnumSet.of(Product.HIGH_SPEED_TRAIN, Product.REGIONAL_TRAIN, Product.SUBURBAN_TRAIN, Product.SUBWAY,
|
||||
Product.TRAM, Product.BUS, Product.FERRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasCapability(Capability capability) {
|
||||
switch (capability) {
|
||||
case SUGGEST_LOCATIONS:
|
||||
case NEARBY_LOCATIONS:
|
||||
case DEPARTURES:
|
||||
case TRIPS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NearbyLocationsResult queryNearbyLocations(EnumSet<LocationType> types, Location location, int maxDistance,
|
||||
int maxLocations) throws IOException {
|
||||
// Coordinates are required
|
||||
if (!location.hasLocation()) {
|
||||
try {
|
||||
if (location.hasId()) {
|
||||
location = queryLocationById(location.id);
|
||||
} else if (location.hasName()) {
|
||||
location = queryLocationByName(location.name, EnumSet.of(location.type));
|
||||
}
|
||||
} catch (InternalErrorException | NotFoundException | RuntimeException e) {
|
||||
return new NearbyLocationsResult(this.resultHeader, NearbyLocationsResult.Status.INVALID_ID);
|
||||
} catch (IOException e) {
|
||||
return new NearbyLocationsResult(this.resultHeader, NearbyLocationsResult.Status.SERVICE_DOWN);
|
||||
}
|
||||
|
||||
if (location == null || !location.hasLocation()) {
|
||||
return new NearbyLocationsResult(this.resultHeader, NearbyLocationsResult.Status.INVALID_ID);
|
||||
}
|
||||
}
|
||||
|
||||
// Default query options
|
||||
List<QueryParameter> queryParameters = new ArrayList<>();
|
||||
queryParameters.add(new QueryParameter("latlong", location.getLatAsDouble() + "," + location.getLonAsDouble()));
|
||||
queryParameters.add(new QueryParameter("rows",
|
||||
String.valueOf(Math.min((maxLocations <= 0) ? DEFAULT_MAX_LOCATIONS : maxLocations, 100))));
|
||||
|
||||
// Add type if specified
|
||||
if (!types.contains(LocationType.ANY) && types.size() > 0) {
|
||||
StringBuilder typeValue = new StringBuilder();
|
||||
for (LocationType type : types) {
|
||||
for (String addition : locationStringsFromLocationType(type)) {
|
||||
if (typeValue.length() > 0)
|
||||
typeValue.append(",");
|
||||
typeValue.append(addition);
|
||||
}
|
||||
}
|
||||
queryParameters.add(new QueryParameter("type", typeValue.toString()));
|
||||
}
|
||||
HttpUrl url = buildApiUrl("locations", queryParameters);
|
||||
|
||||
CharSequence page;
|
||||
try {
|
||||
page = httpClient.get(url);
|
||||
} catch (InternalErrorException e) {
|
||||
return new NearbyLocationsResult(this.resultHeader, NearbyLocationsResult.Status.SERVICE_DOWN);
|
||||
}
|
||||
|
||||
// Parse result into location list
|
||||
final List<Location> foundLocations = new ArrayList<>();
|
||||
try {
|
||||
final JSONObject head = new JSONObject(page.toString());
|
||||
final JSONArray locations = head.optJSONArray("locations");
|
||||
|
||||
for (int i = 0; i < locations.length(); i++) {
|
||||
foundLocations.add(locationFromJSONObject(locations.getJSONObject(i)));
|
||||
}
|
||||
} catch (final JSONException x) {
|
||||
throw new RuntimeException("cannot parse: '" + page + "' on " + url, x);
|
||||
}
|
||||
|
||||
return new NearbyLocationsResult(new ResultHeader(network, SERVER_PRODUCT), foundLocations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryDeparturesResult queryDepartures(String stationId, @Nullable Date time, int maxDepartures,
|
||||
boolean equivs) throws IOException {
|
||||
// The stationId does not need the / character escaped
|
||||
HttpUrl url = buildApiUrl("locations/" + stationId + "/departure-times", new ArrayList<QueryParameter>());
|
||||
final CharSequence page;
|
||||
try {
|
||||
page = httpClient.get(url);
|
||||
} catch (InternalErrorException | NotFoundException e) {
|
||||
return new QueryDeparturesResult(this.resultHeader, QueryDeparturesResult.Status.INVALID_STATION);
|
||||
} catch (Exception e) {
|
||||
return new QueryDeparturesResult(this.resultHeader, QueryDeparturesResult.Status.SERVICE_DOWN);
|
||||
}
|
||||
|
||||
QueryDeparturesResult queryDeparturesResult = new QueryDeparturesResult(this.resultHeader);
|
||||
try {
|
||||
JSONObject head = new JSONObject(page.toString());
|
||||
JSONArray tabs = head.getJSONArray("tabs");
|
||||
for (int t = 0; t < tabs.length(); t++) {
|
||||
JSONObject tab = tabs.getJSONObject(t);
|
||||
|
||||
JSONArray locations = tab.getJSONArray("locations");
|
||||
for (int l = 0; l < locations.length(); l++) {
|
||||
JSONObject location = locations.getJSONObject(l);
|
||||
|
||||
// Ignore if equivs is false and stationId is not a strict match
|
||||
if (!equivs && !location.getString("id").equals(stationId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get list of departures
|
||||
List<Departure> departuresResult = new ArrayList<>();
|
||||
List<LineDestination> lineDestinationResult = new ArrayList<>();
|
||||
|
||||
JSONArray departures = tab.getJSONArray("departures");
|
||||
for (int i = 0; i < departures.length(); i++) {
|
||||
JSONObject departure = departures.getJSONObject(i);
|
||||
JSONObject mode = departure.getJSONObject("mode");
|
||||
|
||||
departuresResult.add(departureFromJSONObject(departure));
|
||||
|
||||
Product lineProduct = productFromMode(mode.getString("type"), mode.getString("name"));
|
||||
lineDestinationResult.add(new LineDestination(
|
||||
new Line(null, departure.getString("operatorName"), lineProduct, mode.getString("name"),
|
||||
null, Standard.STYLES.get(lineProduct), null, null),
|
||||
new Location(LocationType.STATION, null, 0, 0, null,
|
||||
departure.getString("destinationName"), EnumSet.of(lineProduct))));
|
||||
}
|
||||
|
||||
// Add to result object
|
||||
queryDeparturesResult.stationDepartures.add(new StationDepartures(locationFromJSONObject(location),
|
||||
departuresResult, lineDestinationResult));
|
||||
}
|
||||
}
|
||||
|
||||
return queryDeparturesResult;
|
||||
} catch (final JSONException x) {
|
||||
throw new RuntimeException("cannot parse: '" + page + "' on " + url, x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuggestLocationsResult suggestLocations(CharSequence constraint) throws IOException {
|
||||
HttpUrl url = buildApiUrl("locations", Arrays.asList(new QueryParameter("q", constraint.toString())));
|
||||
final CharSequence page;
|
||||
try {
|
||||
page = httpClient.get(url);
|
||||
} catch (InternalErrorException e) {
|
||||
return new SuggestLocationsResult(this.resultHeader, SuggestLocationsResult.Status.SERVICE_DOWN);
|
||||
}
|
||||
|
||||
final List<SuggestedLocation> foundLocations = new ArrayList<>();
|
||||
try {
|
||||
final JSONObject head = new JSONObject(page.toString());
|
||||
final JSONArray locations = head.optJSONArray("locations");
|
||||
|
||||
if (head.has("error")) {
|
||||
return new SuggestLocationsResult(this.resultHeader, SuggestLocationsResult.Status.SERVICE_DOWN);
|
||||
}
|
||||
|
||||
for (int i = 0; i < locations.length(); i++) {
|
||||
JSONObject location = locations.getJSONObject(i);
|
||||
|
||||
foundLocations.add(new SuggestedLocation(locationFromJSONObject(location)));
|
||||
}
|
||||
} catch (final JSONException x) {
|
||||
throw new RuntimeException("cannot parse: '" + page + "' on " + url, x);
|
||||
}
|
||||
|
||||
return new SuggestLocationsResult(this.resultHeader, foundLocations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryTripsResult queryTrips(Location from, @Nullable Location via, Location to, Date date, boolean dep,
|
||||
@Nullable Set<Product> products, @Nullable Optimize optimize, @Nullable WalkSpeed walkSpeed,
|
||||
@Nullable Accessibility accessibility, @Nullable Set<Option> options) throws IOException {
|
||||
if (!from.hasId())
|
||||
return ambiguousQueryTrips(from, via, to);
|
||||
|
||||
if (!to.hasId())
|
||||
return ambiguousQueryTrips(from, via, to);
|
||||
|
||||
// Default query options
|
||||
List<QueryParameter> queryParameters = new ArrayList<>(Arrays.asList(new QueryParameter("from", from.id),
|
||||
new QueryParameter("to", to.id), new QueryParameter("searchType", dep ? "departure" : "arrival"),
|
||||
new QueryParameter("dateTime", new SimpleDateFormat("yyyy-MM-dd'T'HHmm").format(date.getTime())),
|
||||
new QueryParameter("sequence", "1"), new QueryParameter("realtime", "true"),
|
||||
new QueryParameter("before", "1"), new QueryParameter("after", "5")));
|
||||
|
||||
if (via != null) {
|
||||
if (!via.hasId())
|
||||
return ambiguousQueryTrips(from, via, to);
|
||||
|
||||
queryParameters.add(new QueryParameter("via", via.id));
|
||||
}
|
||||
|
||||
if (walkSpeed != null && walkSpeed == WalkSpeed.SLOW) {
|
||||
queryParameters.add(new QueryParameter("interchangeTime", InterchangeTime.EXTRA.toString()));
|
||||
} else {
|
||||
queryParameters.add(new QueryParameter("interchangeTime", InterchangeTime.STANDARD.toString()));
|
||||
}
|
||||
|
||||
// Add trip product options to query
|
||||
if (products == null || products.size() == 0) {
|
||||
products = defaultProducts();
|
||||
}
|
||||
|
||||
queryParameters.add(new QueryParameter("byBus", String.valueOf(products.contains(Product.BUS))));
|
||||
queryParameters.add(new QueryParameter("byTrain", String.valueOf(products.contains(Product.HIGH_SPEED_TRAIN)
|
||||
|| products.contains(Product.REGIONAL_TRAIN) || products.contains(Product.SUBURBAN_TRAIN))));
|
||||
queryParameters.add(new QueryParameter("bySubway", String.valueOf(products.contains(Product.SUBWAY))));
|
||||
queryParameters.add(new QueryParameter("byTram", String.valueOf(products.contains(Product.TRAM))));
|
||||
queryParameters.add(new QueryParameter("byFerry", String.valueOf(products.contains(Product.FERRY))));
|
||||
|
||||
return queryTrips(buildApiUrl("journeys", queryParameters), from, via, to);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryTripsResult queryMoreTrips(QueryTripsContext context, boolean later) throws IOException {
|
||||
TripsContext tripContext = (TripsContext) context;
|
||||
|
||||
HttpUrl url;
|
||||
if (later && context.canQueryLater()) {
|
||||
url = tripContext.getQueryLater();
|
||||
} else if (!later && context.canQueryEarlier()) {
|
||||
url = tripContext.getQueryEarlier();
|
||||
} else {
|
||||
return new QueryTripsResult(this.resultHeader, QueryTripsResult.Status.NO_TRIPS);
|
||||
}
|
||||
|
||||
return queryTrips(url, tripContext.from, tripContext.via, tripContext.to);
|
||||
}
|
||||
}
|
|
@ -40,7 +40,7 @@ public enum NetworkId {
|
|||
SNCB,
|
||||
|
||||
// Netherlands
|
||||
NS,
|
||||
NS, NEGENTWEE,
|
||||
|
||||
// Denmark
|
||||
DSB,
|
||||
|
|
|
@ -213,6 +213,11 @@ public final class ParserUtils {
|
|||
calendar.set(Calendar.AM_PM, m.group(4).equals("AM") ? Calendar.AM : Calendar.PM);
|
||||
}
|
||||
|
||||
public static int parseMinutesFromTimeString(final String duration) {
|
||||
final String[] durationElem = duration.split(":");
|
||||
return (Integer.parseInt(durationElem[0]) * 60) + Integer.parseInt(durationElem[1]);
|
||||
}
|
||||
|
||||
public static long timeDiff(final Date d1, final Date d2) {
|
||||
final long t1 = d1.getTime();
|
||||
final long t2 = d2.getTime();
|
||||
|
@ -226,6 +231,13 @@ public final class ParserUtils {
|
|||
return c.getTime();
|
||||
}
|
||||
|
||||
public static Date addMinutes(final Date time, final int minutes) {
|
||||
final Calendar c = new GregorianCalendar();
|
||||
c.setTime(time);
|
||||
c.add(Calendar.MINUTE, minutes);
|
||||
return c.getTime();
|
||||
}
|
||||
|
||||
public static void printGroups(final Matcher m) {
|
||||
final int groupCount = m.groupCount();
|
||||
for (int i = 1; i <= groupCount; i++)
|
||||
|
|
|
@ -74,6 +74,14 @@ public class WordUtils {
|
|||
return cs == null || cs.length() == 0;
|
||||
}
|
||||
|
||||
public static String capitalizeFirst(final String str) {
|
||||
if (str == null || str.length() <= 0)
|
||||
return str;
|
||||
if (str.length() == 1)
|
||||
return str.toUpperCase();
|
||||
return str.substring(0, 1).toUpperCase() + str.substring(1);
|
||||
}
|
||||
|
||||
// stripped:
|
||||
// public static String wrap(final String str, final int wrapLength)
|
||||
// public static String wrap(final String str, int wrapLength, String newLineStr, final boolean
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.schildbach.pte.live;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import de.schildbach.pte.NegentweeProvider;
|
||||
import de.schildbach.pte.NetworkProvider;
|
||||
import de.schildbach.pte.dto.Location;
|
||||
import de.schildbach.pte.dto.LocationType;
|
||||
import de.schildbach.pte.dto.NearbyLocationsResult;
|
||||
import de.schildbach.pte.dto.QueryDeparturesResult;
|
||||
import de.schildbach.pte.dto.QueryTripsResult;
|
||||
import de.schildbach.pte.dto.SuggestLocationsResult;
|
||||
|
||||
/**
|
||||
* @author full-duplex
|
||||
*/
|
||||
public class NegentweeProviderLiveTest extends AbstractProviderLiveTest {
|
||||
public NegentweeProviderLiveTest() {
|
||||
super(new NegentweeProvider(NegentweeProvider.Language.EN_GB));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nearbyStations() throws Exception {
|
||||
final NearbyLocationsResult result = queryNearbyStations(
|
||||
new Location(LocationType.STATION, "station-amsterdam-centraal"));
|
||||
print(result);
|
||||
assertEquals(NearbyLocationsResult.Status.OK, result.status);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nearbyStationsByCoordinate() throws Exception {
|
||||
final NearbyLocationsResult result = queryNearbyStations(Location.coord(52377548, 4901218));
|
||||
print(result);
|
||||
assertEquals(NearbyLocationsResult.Status.OK, result.status);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nearbyLocationsByCoordinate() throws Exception {
|
||||
final NearbyLocationsResult result = queryNearbyLocations(EnumSet.of(LocationType.ANY),
|
||||
Location.coord(52377548, 4901218), -1, 101);
|
||||
print(result);
|
||||
assertEquals(NearbyLocationsResult.Status.OK, result.status);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void queryDepartures() throws Exception {
|
||||
final QueryDeparturesResult result = queryDepartures("station-amsterdam-centraal", false);
|
||||
print(result);
|
||||
assertEquals(QueryDeparturesResult.Status.OK, result.status);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void queryDeparturesWithEquivalents() throws Exception {
|
||||
final QueryDeparturesResult result = queryDepartures("station-amsterdam-centraal", true);
|
||||
print(result);
|
||||
assertEquals(QueryDeparturesResult.Status.OK, result.status);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void queryDeparturesInvalidStation() throws Exception {
|
||||
final QueryDeparturesResult result = queryDepartures("999999", false);
|
||||
assertEquals(QueryDeparturesResult.Status.INVALID_STATION, result.status);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void suggestLocationsComplete() throws Exception {
|
||||
final SuggestLocationsResult result = suggestLocations("Amsterdam Centraal");
|
||||
print(result);
|
||||
assertEquals(SuggestLocationsResult.Status.OK, result.status);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void suggestLocationsStreet() throws Exception {
|
||||
final SuggestLocationsResult result = suggestLocations("Isolatorweg");
|
||||
print(result);
|
||||
assertEquals(SuggestLocationsResult.Status.OK, result.status);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void suggestLocationsIncomplete() throws Exception {
|
||||
final SuggestLocationsResult result = suggestLocations("Amsterdam");
|
||||
print(result);
|
||||
assertEquals(SuggestLocationsResult.Status.OK, result.status);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void suggestLocationsUmlaut() throws Exception {
|
||||
final SuggestLocationsResult result = suggestLocations("Brüssel");
|
||||
print(result);
|
||||
assertEquals(SuggestLocationsResult.Status.OK, result.status);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shortTrip() throws Exception {
|
||||
final QueryTripsResult result = queryTrips(
|
||||
new Location(LocationType.STATION, "station-amsterdam-centraal", null, "Amsterdam Centraal"), null,
|
||||
new Location(LocationType.STATION, "station-amsterdam-zuid", null, "Amsterdam Zuid"), new Date(), true,
|
||||
null, NetworkProvider.WalkSpeed.FAST, NetworkProvider.Accessibility.NEUTRAL);
|
||||
print(result);
|
||||
assertEquals(QueryTripsResult.Status.OK, result.status);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void earlierTrip() throws Exception {
|
||||
final QueryTripsResult result1 = queryTrips(
|
||||
new Location(LocationType.STATION, "station-amsterdam-centraal", null, "Amsterdam Centraal"), null,
|
||||
new Location(LocationType.STATION, "station-rotterdam-centraal", null, "Rotterdam Centraal"),
|
||||
new Date(), true, null, NetworkProvider.WalkSpeed.FAST, NetworkProvider.Accessibility.NEUTRAL);
|
||||
print(result1);
|
||||
|
||||
assertEquals(QueryTripsResult.Status.OK, result1.status);
|
||||
assertTrue(result1.context.canQueryLater());
|
||||
|
||||
final QueryTripsResult result2 = queryMoreTrips(result1.context, false);
|
||||
print(result2);
|
||||
|
||||
assertEquals(QueryTripsResult.Status.OK, result2.status);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ambiguousTrip() throws Exception {
|
||||
final QueryTripsResult result = queryTrips(new Location(LocationType.ANY, null, null, "Amsterdam Zuid"),
|
||||
new Location(LocationType.STATION, "station-amsterdam-centraal", null, "Amsterdam Centraal"),
|
||||
new Location(LocationType.ANY, null, null, "Rotterdam Centraal"), new Date(), true, null,
|
||||
NetworkProvider.WalkSpeed.FAST, NetworkProvider.Accessibility.NEUTRAL);
|
||||
print(result);
|
||||
assertEquals(QueryTripsResult.Status.AMBIGUOUS, result.status);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void longTrip() throws Exception {
|
||||
final QueryTripsResult result = queryTrips(
|
||||
new Location(LocationType.ADDRESS, "amsterdam/prins-hendrikkade-80e", null, "Prins Hendrikkade"), null,
|
||||
new Location(LocationType.STATION, "breda/bushalte-cornelis-florisstraat", null,
|
||||
"Cornelis Florisstraat"),
|
||||
new Date(), true, null, NetworkProvider.WalkSpeed.FAST, NetworkProvider.Accessibility.NEUTRAL);
|
||||
print(result);
|
||||
assertEquals(QueryTripsResult.Status.OK, result.status);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue