PACA: Remove provider for Provence-Alpes-Côte d'Azur.

This commit is contained in:
Andreas Schildbach 2017-02-15 13:13:12 +01:00
parent e4b03df6f5
commit e92aa098a0
4 changed files with 1 additions and 963 deletions

View file

@ -1,731 +0,0 @@
/*
* Copyright 2014-2015 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
* 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.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import javax.annotation.Nullable;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import de.schildbach.pte.dto.Line;
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.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.Stop;
import de.schildbach.pte.dto.SuggestLocationsResult;
import de.schildbach.pte.dto.SuggestedLocation;
import de.schildbach.pte.dto.Trip;
import de.schildbach.pte.exception.ParserException;
import okhttp3.HttpUrl;
/**
* @author Kjell Braden <afflux@pentabarf.de>
*/
public abstract class AbstractTsiProvider extends AbstractNetworkProvider {
private static class Context implements QueryTripsContext {
private static final long serialVersionUID = -6847355540229473013L;
public final Location from;
public final Collection<Product> products;
public final Location to;
public final Location via;
public final WalkSpeed walkSpeed;
public Date earliestArrival;
public Date latestDeparture;
public Context(final Location from, final Location via, final Location to, final Collection<Product> products,
final WalkSpeed walkSpeed, final Accessibility accessibility, final Set<Option> options) {
this.from = from;
this.via = via;
this.to = to;
this.products = products;
this.walkSpeed = walkSpeed;
}
@Override
public boolean canQueryEarlier() {
return true;
}
@Override
public boolean canQueryLater() {
return true;
}
private QueryTripsResult queryMore(final AbstractTsiProvider provider, final boolean later) throws IOException {
final Date date = later ? latestDeparture : earliestArrival;
// add/remove a little bit just to be on the safe side
final Calendar c = Calendar.getInstance(provider.timeZone());
c.setTime(date);
c.add(Calendar.MINUTE, later ? 1 : -1);
return provider.queryTripsFromContext(this, c.getTime(), later);
}
private void updateEarliestArrival(final Date newTime) {
if (newTime == null)
return;
if (earliestArrival == null || newTime.before(earliestArrival))
earliestArrival = newTime;
}
private void updateLatestDeparture(final Date newTime) {
if (newTime == null)
return;
if (latestDeparture == null || newTime.after(latestDeparture))
latestDeparture = newTime;
}
}
private static final String DEFAULT_STOPFINDER_ENDPOINT = "Transport/v2";
private static final String DEFAULT_TRIP_ENDPOINT = "journeyplanner/v2";
private static final String SERVER_PRODUCT = "tsi";
private static Map<String, Product> TRANSPORT_MODES = new HashMap<>();
static {
// HIGH_SPEED_TRAIN
TRANSPORT_MODES.put("TGV", Product.HIGH_SPEED_TRAIN);
TRANSPORT_MODES.put("HST", Product.HIGH_SPEED_TRAIN);
// REGIONAL_TRAIN
TRANSPORT_MODES.put("TRAIN", Product.REGIONAL_TRAIN);
TRANSPORT_MODES.put("TER", Product.REGIONAL_TRAIN);
// SUBURBAN_TRAIN
TRANSPORT_MODES.put("LOCAL_TRAIN", Product.SUBURBAN_TRAIN);
// SUBWAY
TRANSPORT_MODES.put("METRO", Product.SUBWAY);
// TRAM
TRANSPORT_MODES.put("TRAM", Product.TRAM);
TRANSPORT_MODES.put("TRAMWAY", Product.TRAM);
// BUS
TRANSPORT_MODES.put("BUS", Product.BUS);
TRANSPORT_MODES.put("COACH", Product.BUS);
// CABLECAR
TRANSPORT_MODES.put("TROLLEY", Product.CABLECAR);
TRANSPORT_MODES.put("TROLLEY_BUS", Product.CABLECAR);
}
protected static double latLonToDouble(final int value) {
return (double) value / 1000000;
}
private final @Nullable String apiKey;
private final HttpUrl stopFinderEndpoint;
private final HttpUrl tripEndpoint;
public AbstractTsiProvider(final NetworkId network, final String apiKey, final HttpUrl apiBase) {
this(network, apiKey, apiBase, null, null);
}
public AbstractTsiProvider(final NetworkId network, final String apiKey, final HttpUrl tripEndpoint,
final HttpUrl stopFinderEndpoint) {
super(network);
this.apiKey = apiKey;
this.tripEndpoint = tripEndpoint;
this.stopFinderEndpoint = stopFinderEndpoint;
}
public AbstractTsiProvider(final NetworkId network, final String apiKey, final HttpUrl apiBase,
final String tripEndpoint, final String stopFinderEndpoint) {
this(network, apiKey,
apiBase.newBuilder().addPathSegments(tripEndpoint != null ? tripEndpoint : DEFAULT_TRIP_ENDPOINT)
.build(),
apiBase.newBuilder()
.addPathSegments(stopFinderEndpoint != null ? stopFinderEndpoint : DEFAULT_STOPFINDER_ENDPOINT)
.build());
}
@Override
protected boolean hasCapability(final Capability capability) {
if (capability == Capability.DEPARTURES)
return false;
else
return true;
}
@Override
public SuggestLocationsResult suggestLocations(final CharSequence constraint) throws IOException {
final HttpUrl.Builder url = stopFinderEndpoint.newBuilder().addPathSegments("SearchTripPoint/json");
appendCommonRequestParams(url);
url.addQueryParameter("MaxItems", "50"); // XXX good value?
url.addQueryParameter("Keywords", constraint.toString());
final CharSequence page = httpClient.get(url.build());
try {
final List<SuggestedLocation> locations = new ArrayList<>();
final JSONObject head = new JSONObject(page.toString());
final ResultHeader header = new ResultHeader(network, SERVER_PRODUCT);
final int status = head.getInt("StatusCode");
if (status != 200)
return new SuggestLocationsResult(header, SuggestLocationsResult.Status.SERVICE_DOWN);
JSONArray dataArray = head.getJSONArray("Data");
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
final Location location = parseJsonTransportLocation(data);
if (location.isIdentified()) // make sure the location is really identified
// some addresses may not contain coordinates, we ignore them
locations.add(new SuggestedLocation(location));
}
return new SuggestLocationsResult(header, locations);
} catch (final JSONException x) {
throw new ParserException(x);
}
}
private final void appendCommonRequestParams(final HttpUrl.Builder url) {
url.addQueryParameter("Key", apiKey);
}
private Line createLine(final String id, final String mode, final String number, final String name,
final String operatorCode, final String codeActivity) {
final Product product = TRANSPORT_MODES.get(mode);
if (product == null)
throw new IllegalStateException("cannot normalize mode '" + mode + "' number '" + number + "'");
final StringBuilder label = new StringBuilder();
if (number != null) {
label.append(number);
} else if (operatorCode != null) {
label.append(operatorCode);
if (codeActivity != null)
label.append(codeActivity);
} else {
label.append(name);
}
return new Line(id, operatorCode, product, label.toString());
}
private List<Location> identifyLocation(final Location location) throws IOException {
if (location.isIdentified())
return Collections.singletonList(location);
final List<Location> locations = suggestLocations(location.uniqueShortName()).getLocations();
if (locations == null)
return new ArrayList<>(0);
return locations;
}
private NearbyLocationsResult jsonCoordRequest(final int lat, final int lon, final int maxDistance,
final int maxStations) throws IOException {
final HttpUrl.Builder url = stopFinderEndpoint.newBuilder().addPathSegments("SearchTripPoint/json");
appendCommonRequestParams(url);
url.addQueryParameter("Latitude", String.format(Locale.FRENCH, "%2.6f", latLonToDouble(lat)));
url.addQueryParameter("Longitude", String.format(Locale.FRENCH, "%2.6f", latLonToDouble(lon)));
url.addQueryParameter("MaxItems", Integer.toString(maxStations != 0 ? maxStations : 50));
url.addQueryParameter("Perimeter", Integer.toString(maxDistance != 0 ? maxDistance : 1320));
url.addQueryParameter("PointTypes", "Stop_Place");
final CharSequence page = httpClient.get(url.build());
try {
final List<Location> stations = new ArrayList<>();
final JSONObject head = new JSONObject(page.toString());
final ResultHeader header = new ResultHeader(network, SERVER_PRODUCT);
final int status = head.getInt("StatusCode");
if (status != 200) {
return new NearbyLocationsResult(header, status == 300 ? NearbyLocationsResult.Status.INVALID_ID
: NearbyLocationsResult.Status.SERVICE_DOWN);
}
JSONArray dataArray = head.getJSONArray("Data");
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
stations.add(parseJsonTransportLocation(data));
}
return new NearbyLocationsResult(header, stations);
} catch (final JSONException x) {
throw new ParserException(x);
}
}
private String jsonOptString(final JSONObject json, final String key) throws JSONException {
return json.isNull(key) ? null : json.getString(key);
}
private Location jsonStationRequestCoord(final String id) throws IOException {
final HttpUrl.Builder url = stopFinderEndpoint.newBuilder().addPathSegments("GetTripPoint/json");
appendCommonRequestParams(url);
url.addQueryParameter("TripPointId", id);
url.addQueryParameter("PointType", "Stop_Place");
final CharSequence page = httpClient.get(url.build());
try {
final JSONObject head = new JSONObject(page.toString());
int status = head.getInt("StatusCode");
if (status != 200)
return null;
JSONObject data = head.getJSONObject("Data");
return parseJsonTransportLocation(data);
} catch (final JSONException x) {
throw new ParserException(x);
}
}
private Trip.Individual parseJsonJourneyplannerIndividualLeg(final JSONObject legInfo) throws JSONException {
final String transportMode = legInfo.getString("TransportMode");
final Trip.Individual.Type type;
if ("WALK".equals(transportMode)) {
type = Trip.Individual.Type.WALK;
} else {
throw new JSONException("unknown transportMode=" + transportMode);
}
final JSONObject arrInfo = legInfo.getJSONObject("Arrival");
final JSONObject depInfo = legInfo.getJSONObject("Departure");
final Location departure = parseJsonJourneyplannerLocation(depInfo.getJSONObject("Site"));
final Location arrival = parseJsonJourneyplannerLocation(arrInfo.getJSONObject("Site"));
final String arrTimeStr = arrInfo.getString("Time");
final String depTimeStr = depInfo.getString("Time");
final Date depTime, arrTime;
try {
final DateFormat fullDateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss", Locale.US);
depTime = fullDateFormat.parse(depTimeStr);
arrTime = fullDateFormat.parse(arrTimeStr);
} catch (final ParseException e) {
throw new JSONException("failed to parse trip times: " + depTimeStr + " or " + arrTimeStr);
}
final JSONArray pathLinks = legInfo.getJSONObject("pathLinks").getJSONArray("PathLink");
final List<Point> path = new ArrayList<>(pathLinks.length() + 1);
int distance = 0;
path.add(new Point(departure.lat, departure.lon));
for (int i = 0; i < pathLinks.length(); i++) {
final JSONObject pathLink = pathLinks.getJSONObject(i);
distance += pathLink.getInt("Distance");
final Location toLoc = parseJsonJourneyplannerLocation(
pathLink.getJSONObject("Arrival").getJSONObject("Site"));
path.add(new Point(toLoc.lat, toLoc.lon));
}
return new Trip.Individual(type, departure, depTime, arrival, arrTime, path, distance);
}
private Trip.Leg parseJsonJourneyplannerLeg(final JSONObject jsonObject) throws JSONException {
final JSONObject legInfo = jsonObject.getJSONObject("Leg");
final JSONObject ptrInfo = jsonObject.getJSONObject("PTRide");
if (legInfo.isNull("TransportMode") && !ptrInfo.isNull("TransportMode")) {
return parseJsonJourneyplannerPublicLeg(ptrInfo);
} else if (!legInfo.isNull("TransportMode") && ptrInfo.isNull("TransportMode")) {
return parseJsonJourneyplannerIndividualLeg(legInfo);
} else {
throw new JSONException("unknown leg type");
}
}
private Location parseJsonJourneyplannerLocation(final JSONObject data) throws JSONException {
final String locTypeStr = data.getString("Type");
final LocationType locType;
final String id;
if ("POI".equals(locTypeStr)) {
locType = LocationType.POI;
id = data.getString("id");
} else if ("BOARDING_POSITION".equals(locTypeStr)) {
locType = LocationType.STATION;
if (!data.isNull("LogicalId"))
id = data.getString("LogicalId");
else
id = data.getString("id");
} else {
id = data.optString("id");
locType = LocationType.ADDRESS;
}
final Point coord;
final JSONObject posObj = data.optJSONObject("Position");
if (posObj != null) {
final double lat = posObj.getDouble("Lat");
final double lon = posObj.getDouble("Long");
coord = Point.fromDouble(lat, lon);
} else {
coord = null;
}
final String name = data.getString("Name");
final String place = jsonOptString(data, "CityName");
return new Location(locType, id, coord, place, name);
}
private Trip.Public parseJsonJourneyplannerPublicLeg(final JSONObject ptrInfo) throws JSONException {
final DateFormat fullDateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss", Locale.US);
final Line line = parseJsonLine(ptrInfo);
final JSONObject destObj = ptrInfo.optJSONObject("Direction");
String destinationName = jsonOptString(ptrInfo, "Destination");
if (destinationName == null && destObj != null)
destinationName = destObj.optString("Name");
final Location lineDestination = new Location(LocationType.ANY, null, null, destinationName);
final Stop departureStop, arrivalStop;
final JSONObject departureInfo = ptrInfo.getJSONObject("Departure");
final JSONObject arrivalInfo = ptrInfo.getJSONObject("Arrival");
final Location departureLocation = parseJsonJourneyplannerLocation(departureInfo.getJSONObject("StopPlace"));
final Location arrivalLocation = parseJsonJourneyplannerLocation(arrivalInfo.getJSONObject("StopPlace"));
try {
final Date departureTime = fullDateFormat.parse(departureInfo.getString("Time"));
final Date arrivalTime = fullDateFormat.parse(arrivalInfo.getString("Time"));
departureStop = new Stop(departureLocation, true, departureTime, null, null, null);
arrivalStop = new Stop(arrivalLocation, false, arrivalTime, null, null, null);
} catch (final ParseException e) {
throw new JSONException(e);
}
final JSONArray stepArray = ptrInfo.getJSONObject("steps").getJSONArray("Step");
List<Stop> intermediateStops = new ArrayList<>(stepArray.length() - 1);
for (int i = 0; i < stepArray.length() - 1; i++) {
final JSONObject enterStop = stepArray.getJSONObject(i).getJSONObject("Arrival");
final JSONObject leaveStop = stepArray.getJSONObject(i + 1).getJSONObject("Departure");
final Location location = parseJsonJourneyplannerLocation(leaveStop.getJSONObject("StopPlace"));
Date enterTime;
Date leaveTime;
try {
enterTime = fullDateFormat.parse(enterStop.getString("Time"));
leaveTime = fullDateFormat.parse(leaveStop.getString("Time"));
intermediateStops.add(new Stop(location, enterTime, null, leaveTime, null));
} catch (final ParseException e) {
throw new JSONException(e);
}
}
final String message = jsonOptString(ptrInfo, "Notes");
return new Trip.Public(line, lineDestination, departureStop, arrivalStop, intermediateStops, null, message);
}
private Trip parseJsonJourneyplannerTrip(final JSONObject tripObject) throws JSONException {
final JSONObject departureInfo = tripObject.getJSONObject("Departure");
final JSONObject arrivalInfo = tripObject.getJSONObject("Arrival");
final Location from = parseJsonJourneyplannerLocation(departureInfo.getJSONObject("Site"));
final Location to = parseJsonJourneyplannerLocation(arrivalInfo.getJSONObject("Site"));
final JSONArray legArray = tripObject.getJSONObject("sections").getJSONArray("Section");
final List<Trip.Leg> legs = new ArrayList<>(legArray.length());
for (int i = 0; i < legArray.length(); i++) {
legs.add(parseJsonJourneyplannerLeg(legArray.getJSONObject(i)));
}
return new Trip(null, from, to, legs, null, null, null);
}
private Line parseJsonLine(final JSONObject ptrInfo) throws JSONException {
final JSONObject networkInfo = ptrInfo.optJSONObject("PTNetwork");
final String network;
if (networkInfo != null)
network = jsonOptString(networkInfo, "Name");
else
network = null;
final JSONObject lineInfo = ptrInfo.getJSONObject("Line");
final String id = lineInfo.getString("id");
final String transportMode = ptrInfo.getString("TransportMode");
final String lineNumber = lineInfo.optString("Number");
final String lineName = lineInfo.getString("Name");
final JSONObject operatorInfo = ptrInfo.optJSONObject("Operator");
final String operatorCode;
if (operatorInfo != null)
operatorCode = jsonOptString(operatorInfo, "Code");
else
operatorCode = null;
final String codeActivity = jsonOptString(ptrInfo, "CodeActivity");
final Line line = createLine(id, transportMode, lineNumber, lineName, operatorCode, codeActivity);
final Line styledLine = new Line(line.id, line.network, line.product, line.label,
lineStyle(network, line.product, line.label));
return styledLine;
}
private Location parseJsonTransportLocation(final JSONObject data) throws JSONException {
final String id = data.getString("Id");
final LocationType locType;
switch (data.getInt("PointType")) {
case 1:
locType = LocationType.POI;
break;
case 4:
locType = LocationType.STATION;
break;
case 3:
default:
locType = LocationType.ADDRESS;
}
final double lat = data.optDouble("Latitude", 0);
final double lon = data.optDouble("Longitude", 0);
final String name = data.getString("Name");
String place = null;
final JSONObject localityObj = data.optJSONObject("Locality");
if (localityObj != null) {
place = localityObj.getString("Name");
}
return new Location(locType, id, Point.fromDouble(lat, lon), place, name);
}
@Override
public QueryDeparturesResult queryDepartures(final String stationId, final @Nullable Date time,
final int maxDepartures, final boolean equivs) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public QueryTripsResult queryMoreTrips(final QueryTripsContext context, final boolean later) throws IOException {
return ((Context) context).queryMore(this, later);
}
@Override
public NearbyLocationsResult queryNearbyLocations(final EnumSet<LocationType> types, final Location location,
final int maxDistance, final int maxLocations) throws IOException {
Location queryLocation = location;
if (!queryLocation.hasLocation()) {
if (location.type != LocationType.STATION)
throw new IllegalArgumentException("cannot handle: " + location.type);
queryLocation = jsonStationRequestCoord(location.id);
}
if (queryLocation == null)
throw new IllegalArgumentException("null location or station not found");
return jsonCoordRequest(location.lat, location.lon, maxDistance, maxLocations);
}
@Override
public QueryTripsResult queryTrips(final Location from, final @Nullable Location via, final Location to,
final Date date, final boolean dep, final @Nullable Set<Product> products,
final @Nullable Optimize optimize, final @Nullable WalkSpeed walkSpeed,
final @Nullable Accessibility accessibility, final @Nullable Set<Option> options) throws IOException {
final ResultHeader header = new ResultHeader(network, SERVER_PRODUCT);
final List<Location> possibleFroms, possibleTos, possibleVias;
possibleFroms = identifyLocation(from);
possibleTos = identifyLocation(to);
if (via != null)
possibleVias = identifyLocation(via);
else
possibleVias = Collections.singletonList(null);
if (possibleFroms.isEmpty())
return new QueryTripsResult(header, QueryTripsResult.Status.UNKNOWN_FROM);
if (possibleTos.isEmpty())
return new QueryTripsResult(header, QueryTripsResult.Status.UNKNOWN_TO);
if (possibleVias.isEmpty())
return new QueryTripsResult(header, QueryTripsResult.Status.UNKNOWN_VIA);
if (possibleFroms.size() > 1 || possibleVias.size() > 1 || possibleTos.size() > 1)
return new QueryTripsResult(header, possibleFroms.size() > 1 ? possibleFroms : null,
possibleVias.size() > 1 ? possibleVias : null, possibleTos.size() > 1 ? possibleTos : null);
final Context context = new Context(possibleFroms.get(0), possibleVias.get(0), possibleTos.get(0), products,
walkSpeed, accessibility, options);
return queryTripsFromContext(context, date, dep);
}
protected QueryTripsResult queryTripsFromContext(final Context context, final Date date, final boolean dep)
throws IOException {
final String mode;
if (context.products != null) {
final StringBuilder modeBuilder = new StringBuilder();
for (Product p : context.products) {
final String productName = translateToLocalProduct(p);
if (productName != null)
modeBuilder.append(productName).append("|");
}
mode = modeBuilder.substring(0, modeBuilder.length() - 1);
} else {
mode = null;
}
final HttpUrl.Builder url = tripEndpoint.newBuilder().addPathSegments("PlanTrip/json");
appendCommonRequestParams(url);
url.addQueryParameter("Disruptions", "0"); // XXX what does this even mean?
url.addQueryParameter("Algorithm", "FASTEST");
url.addQueryParameter("MaxWalkDist", "1000"); // XXX good value? (in meters)
if (context.from.type == LocationType.STATION) {
url.addQueryParameter("DepType", "STOP_PLACE");
url.addQueryParameter("DepId", context.from.id + "$0");
} else if (context.from.type == LocationType.POI) {
url.addQueryParameter("DepType", "POI");
url.addQueryParameter("DepId", context.from.id + "$0");
} else {
url.addQueryParameter("DepLat", Double.toString(latLonToDouble(context.from.lat)));
url.addQueryParameter("DepLon", Double.toString(latLonToDouble(context.from.lon)));
}
if (context.to.type == LocationType.STATION) {
url.addQueryParameter("ArrType", "STOP_PLACE");
url.addQueryParameter("ArrId", context.to.id + "$0");
} else if (context.to.type == LocationType.POI) {
url.addQueryParameter("ArrType", "POI");
url.addQueryParameter("ArrId", context.to.id + "$0");
} else {
url.addQueryParameter("ArrLat", Double.toString(latLonToDouble(context.to.lat)));
url.addQueryParameter("ArrLon", Double.toString(latLonToDouble(context.to.lon)));
}
if (context.via != null) {
if (context.via.type == LocationType.STATION) {
url.addQueryParameter("ViaType", "STOP_PLACE");
url.addQueryParameter("ViaId", context.via.id + "$0");
} else if (context.via.type == LocationType.POI) {
url.addQueryParameter("ViaType", "POI");
url.addQueryParameter("ViaId", context.via.id + "$0");
} else {
url.addQueryParameter("ViaLat", Double.toString(latLonToDouble(context.via.lat)));
url.addQueryParameter("ViaLon", Double.toString(latLonToDouble(context.via.lon)));
}
}
final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
url.addQueryParameter("date", dateFormat.format(date));
final DateFormat timeFormat = new SimpleDateFormat("HH-mm", Locale.US);
url.addQueryParameter(dep ? "DepartureTime" : "ArrivalTime", timeFormat.format(date));
url.addQueryParameter("WalkSpeed", translateWalkSpeed(context.walkSpeed));
if (mode != null)
url.addQueryParameter("Modes", mode);
final CharSequence page = httpClient.get(url.build());
try {
final JSONObject head = new JSONObject(page.toString());
final ResultHeader header = new ResultHeader(network, SERVER_PRODUCT);
final JSONObject statusObj = head.optJSONObject("Status");
if (statusObj == null) {
return new QueryTripsResult(header, QueryTripsResult.Status.SERVICE_DOWN);
}
final String statusStr = statusObj.optString("Code");
if ("NO_SOLUTION_FOR_REQUEST".equals(statusStr)) {
return new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS);
}
if (!"OK".equals(statusStr)) {
return new QueryTripsResult(header, QueryTripsResult.Status.SERVICE_DOWN);
}
final JSONArray tripArray = head.getJSONObject("trips").getJSONArray("Trip");
final List<Trip> trips = new ArrayList<>(tripArray.length());
for (int i = 0; i < tripArray.length(); i++) {
final JSONObject tripObject = tripArray.getJSONObject(i);
trips.add(parseJsonJourneyplannerTrip(tripObject));
}
if (trips.size() > 0) {
context.updateEarliestArrival(trips.get(0).getLastArrivalTime());
context.updateLatestDeparture(trips.get(trips.size() - 1).getFirstDepartureTime());
}
return new QueryTripsResult(header, url.build().toString(), context.from, context.via, context.to, context,
trips);
} catch (final JSONException x) {
throw new ParserException(x);
}
}
protected TimeZone timeZone() {
return TimeZone.getTimeZone("Europe/Paris");
}
protected abstract String translateToLocalProduct(final Product p);
/**
* @param walkSpeed
* @return walk speed in km/h
*/
protected String translateWalkSpeed(final WalkSpeed walkSpeed) {
switch (walkSpeed) {
case FAST:
return "6";
case SLOW:
return "4";
case NORMAL:
default:
return "5";
}
}
}

View file

@ -34,7 +34,7 @@ public enum NetworkId {
SBB, BVB, VBL, ZVV,
// France
PACA, PARIS, FRANCESOUTHWEST, FRANCESOUTHEAST, FRANCENORTHWEST, FRANCENORTHEAST,
PARIS, FRANCESOUTHWEST, FRANCESOUTHEAST, FRANCENORTHWEST, FRANCENORTHEAST,
// Belgium
SNCB,

View file

@ -1,56 +0,0 @@
/*
* Copyright 2014-2015 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
* 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 de.schildbach.pte.dto.Product;
import okhttp3.HttpUrl;
/**
* @author Kjell Braden <afflux@pentabarf.de>
*/
public class PacaProvider extends AbstractTsiProvider {
public PacaProvider() {
super(NetworkId.PACA, "PACA", HttpUrl.parse("http://www.pacamobilite.fr/WebServices/TransinfoService/api"));
}
@Override
protected String translateToLocalProduct(final Product p) {
switch (p) {
case HIGH_SPEED_TRAIN:
return "RAPID_TRANSIT";
case REGIONAL_TRAIN:
return "TRAIN|LONG_DISTANCE_TRAIN";
case SUBURBAN_TRAIN:
return "LOCAL_TRAIN";
case SUBWAY:
return "METRO";
case TRAM:
return "TRAMWAY";
case BUS:
return "BUS|COACH";
case ON_DEMAND:
return "TOD";
case FERRY:
return "FERRY";
case CABLECAR:
default:
return null;
}
}
}

View file

@ -1,175 +0,0 @@
/*
* Copyright 2014-2015 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
* 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 org.junit.Test;
import de.schildbach.pte.NetworkProvider.Accessibility;
import de.schildbach.pte.NetworkProvider.WalkSpeed;
import de.schildbach.pte.PacaProvider;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.Product;
import de.schildbach.pte.dto.QueryTripsResult;
import de.schildbach.pte.dto.SuggestLocationsResult;
/**
* @author Kjell Braden <afflux@pentabarf.de>
*/
public class PacaProviderLiveTest extends AbstractProviderLiveTest {
public PacaProviderLiveTest() {
super(new PacaProvider());
}
@Test
public void suggestLocations() throws Exception {
final SuggestLocationsResult result = suggestLocations("aeroport");
print(result);
}
@Test
public void suggestLocationsIdentified() throws Exception {
final SuggestLocationsResult result = suggestLocations("EGANAUDE, Biot");
print(result);
}
@Test
public void suggestLocationsUmlaut() throws Exception {
final SuggestLocationsResult result = suggestLocations("Aéroport");
print(result);
}
@Test
public void shortTrip() throws Exception {
final QueryTripsResult result = queryTrips(new Location(LocationType.STATION, "61088", null, "Eganaude"), null,
new Location(LocationType.STATION, "58617", null, "Place de Gaulle"), new Date(), true, Product.ALL,
WalkSpeed.NORMAL, Accessibility.NEUTRAL);
print(result);
assertEquals(QueryTripsResult.Status.OK, result.status);
assertTrue(result.trips.size() > 0);
if (!result.context.canQueryLater())
return;
final QueryTripsResult laterResult = queryMoreTrips(result.context, true);
print(laterResult);
if (!laterResult.context.canQueryLater())
return;
final QueryTripsResult later2Result = queryMoreTrips(laterResult.context, true);
print(later2Result);
if (!later2Result.context.canQueryLater())
return;
final QueryTripsResult later3Result = queryMoreTrips(later2Result.context, true);
print(later3Result);
if (!later3Result.context.canQueryLater())
return;
final QueryTripsResult later4Result = queryMoreTrips(later3Result.context, true);
print(later4Result);
if (!later4Result.context.canQueryLater())
return;
final QueryTripsResult later5Result = queryMoreTrips(later4Result.context, true);
print(later5Result);
if (!later5Result.context.canQueryLater())
return;
final QueryTripsResult later6Result = queryMoreTrips(later5Result.context, true);
print(later6Result);
if (!result.context.canQueryEarlier())
return;
final QueryTripsResult earlierResult = queryMoreTrips(result.context, false);
print(earlierResult);
if (!earlierResult.context.canQueryEarlier())
return;
final QueryTripsResult earlier2Result = queryMoreTrips(earlierResult.context, false);
print(earlier2Result);
if (!earlier2Result.context.canQueryEarlier())
return;
final QueryTripsResult earlier3Result = queryMoreTrips(earlier2Result.context, false);
print(earlier3Result);
if (!earlier3Result.context.canQueryEarlier())
return;
final QueryTripsResult earlier4Result = queryMoreTrips(earlier3Result.context, false);
print(earlier4Result);
}
@Test
public void slowTrip() throws Exception {
final QueryTripsResult result = queryTrips(
new Location(LocationType.STATION, "68629", 43441167, 5223055, "MARSEILLE", "Aeroport Hall 3 4"), null,
new Location(LocationType.STATION, "61088", 43623140, 7057545, "BIOT", "Eganaude"), new Date(), true,
Product.ALL, WalkSpeed.NORMAL, Accessibility.BARRIER_FREE);
print(result);
assertEquals(QueryTripsResult.Status.OK, result.status);
assertTrue(result.trips.size() > 0);
if (!result.context.canQueryLater())
return;
final QueryTripsResult laterResult = queryMoreTrips(result.context, true);
print(laterResult);
}
@Test
public void shortTripByName() throws Exception {
final QueryTripsResult result = queryTrips(new Location(LocationType.ANY, null, null, "Biot, Templiers!"), null,
new Location(LocationType.ANY, null, null, "Eganaude!"), new Date(), true, Product.ALL,
WalkSpeed.NORMAL, Accessibility.NEUTRAL);
print(result);
}
@Test
public void slowTripPoi() throws Exception {
final QueryTripsResult result = queryTrips(new Location(LocationType.POI, "30455", 0, 0, "CANNES", "Cannes"),
null, new Location(LocationType.POI, "30514", 0, 0, "NICE", "Nice"), new Date(), true, Product.ALL,
WalkSpeed.NORMAL, Accessibility.NEUTRAL);
print(result);
assertEquals(QueryTripsResult.Status.OK, result.status);
assertTrue(result.trips.size() > 0);
if (!result.context.canQueryLater())
return;
final QueryTripsResult laterResult = queryMoreTrips(result.context, true);
print(laterResult);
}
}