mirror of
https://gitlab.com/oeffi/public-transport-enabler.git
synced 2025-07-07 14:38:49 +00:00
use APIs for Frankfurt whereever possible
git-svn-id: https://public-transport-enabler.googlecode.com/svn/trunk@643 0924bc21-9374-b0fa-ee44-9ff1593b38f0
This commit is contained in:
parent
77b80edd55
commit
7c6b3d2539
3 changed files with 62 additions and 472 deletions
|
@ -20,22 +20,15 @@ package de.schildbach.pte;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import de.schildbach.pte.dto.Connection;
|
|
||||||
import de.schildbach.pte.dto.Departure;
|
import de.schildbach.pte.dto.Departure;
|
||||||
import de.schildbach.pte.dto.GetConnectionDetailsResult;
|
|
||||||
import de.schildbach.pte.dto.Line;
|
|
||||||
import de.schildbach.pte.dto.Location;
|
import de.schildbach.pte.dto.Location;
|
||||||
import de.schildbach.pte.dto.LocationType;
|
import de.schildbach.pte.dto.LocationType;
|
||||||
import de.schildbach.pte.dto.NearbyStationsResult;
|
import de.schildbach.pte.dto.NearbyStationsResult;
|
||||||
import de.schildbach.pte.dto.QueryConnectionsResult;
|
|
||||||
import de.schildbach.pte.dto.QueryDeparturesResult;
|
import de.schildbach.pte.dto.QueryDeparturesResult;
|
||||||
import de.schildbach.pte.dto.QueryDeparturesResult.Status;
|
import de.schildbach.pte.dto.QueryDeparturesResult.Status;
|
||||||
import de.schildbach.pte.dto.StationDepartures;
|
import de.schildbach.pte.dto.StationDepartures;
|
||||||
|
@ -54,7 +47,7 @@ public class RmvProvider extends AbstractHafasProvider
|
||||||
|
|
||||||
public RmvProvider()
|
public RmvProvider()
|
||||||
{
|
{
|
||||||
super(null, 17, null);
|
super(API_BASE + "query.exe/dn", 17, null, "UTF-8", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public NetworkId id()
|
public NetworkId id()
|
||||||
|
@ -84,38 +77,34 @@ public class RmvProvider extends AbstractHafasProvider
|
||||||
return super.splitNameAndPlace(name);
|
return super.splitNameAndPlace(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String NAME_URL = API_BASE + "stboard.exe/dox?input=";
|
private static final String AUTOCOMPLETE_URI = API_BASE + "ajax-getstop.exe/dn?getstop=1&REQ0JourneyStopsS0A=255&S=%s?&js=true&";
|
||||||
private static final Pattern P_SINGLE_NAME = Pattern.compile(".*<input type=\"hidden\" name=\"input\" value=\"(.+?)#(\\d+)\" />.*",
|
private static final String ENCODING = "ISO-8859-1";
|
||||||
Pattern.DOTALL);
|
|
||||||
private static final Pattern P_MULTI_NAME = Pattern.compile("<a href=\"/auskunft/bin/jp/stboard.exe/dox.*?input=(\\d+)&.*?\">\\s*(.*?)\\s*</a>",
|
|
||||||
Pattern.DOTALL);
|
|
||||||
|
|
||||||
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
|
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
|
||||||
{
|
{
|
||||||
final CharSequence page = ParserUtils.scrape(NAME_URL + ParserUtils.urlEncode(constraint.toString()));
|
final String uri = String.format(AUTOCOMPLETE_URI, ParserUtils.urlEncode(constraint.toString(), ENCODING));
|
||||||
|
|
||||||
final List<Location> results = new ArrayList<Location>();
|
return jsonGetStops(uri);
|
||||||
|
|
||||||
final Matcher mSingle = P_SINGLE_NAME.matcher(page);
|
|
||||||
if (mSingle.matches())
|
|
||||||
{
|
|
||||||
results.add(new Location(LocationType.STATION, Integer.parseInt(mSingle.group(2)), null, ParserUtils.resolveEntities(mSingle.group(1))));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
final Matcher mMulti = P_MULTI_NAME.matcher(page);
|
|
||||||
while (mMulti.find())
|
|
||||||
results.add(new Location(LocationType.STATION, Integer.parseInt(mMulti.group(1)), null, ParserUtils.resolveEntities(mMulti.group(2))));
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
|
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
|
||||||
{
|
{
|
||||||
final StringBuilder uri = new StringBuilder(API_BASE);
|
final StringBuilder uri = new StringBuilder(API_BASE);
|
||||||
|
|
||||||
if (location.type == LocationType.STATION && location.hasId())
|
if (location.hasLocation())
|
||||||
|
{
|
||||||
|
uri.append("query.exe/dny");
|
||||||
|
uri.append("?performLocating=2&tpl=stop2json");
|
||||||
|
uri.append("&look_maxno=").append(maxStations != 0 ? maxStations : 200);
|
||||||
|
uri.append("&look_maxdist=").append(maxDistance != 0 ? maxDistance : 5000);
|
||||||
|
uri.append("&look_stopclass=").append(allProductsInt());
|
||||||
|
uri.append("&look_nv=get_stopweight|yes");
|
||||||
|
uri.append("&look_x=").append(location.lon);
|
||||||
|
uri.append("&look_y=").append(location.lat);
|
||||||
|
|
||||||
|
return jsonNearbyStations(uri.toString());
|
||||||
|
}
|
||||||
|
else if (location.type == LocationType.STATION && location.hasId())
|
||||||
{
|
{
|
||||||
uri.append("stboard.exe/dn?L=vs_rmv&near=Anzeigen");
|
uri.append("stboard.exe/dn?L=vs_rmv&near=Anzeigen");
|
||||||
uri.append("&distance=").append(maxDistance != 0 ? maxDistance / 1000 : 50);
|
uri.append("&distance=").append(maxDistance != 0 ? maxDistance / 1000 : 50);
|
||||||
|
@ -129,351 +118,6 @@ public class RmvProvider extends AbstractHafasProvider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Map<WalkSpeed, String> WALKSPEED_MAP = new HashMap<WalkSpeed, String>();
|
|
||||||
static
|
|
||||||
{
|
|
||||||
WALKSPEED_MAP.put(WalkSpeed.SLOW, "115");
|
|
||||||
WALKSPEED_MAP.put(WalkSpeed.NORMAL, "100");
|
|
||||||
WALKSPEED_MAP.put(WalkSpeed.FAST, "85");
|
|
||||||
}
|
|
||||||
|
|
||||||
private String connectionsQueryUri(final Location from, final Location via, final Location to, final Date date, final boolean dep,
|
|
||||||
final String products, final WalkSpeed walkSpeed)
|
|
||||||
{
|
|
||||||
final Calendar c = new GregorianCalendar(timeZone());
|
|
||||||
c.setTime(date);
|
|
||||||
|
|
||||||
final StringBuilder uri = new StringBuilder();
|
|
||||||
|
|
||||||
uri.append(API_BASE).append("query.exe/dox");
|
|
||||||
uri.append("?REQ0HafasInitialSelection=0");
|
|
||||||
uri.append("&REQ0HafasSearchForw=").append(dep ? "1" : "0");
|
|
||||||
uri.append("&REQ0JourneyDate=").append(
|
|
||||||
String.format("%02d.%02d.%02d", c.get(Calendar.DAY_OF_MONTH), c.get(Calendar.MONTH) + 1, c.get(Calendar.YEAR) - 2000));
|
|
||||||
uri.append("&REQ0JourneyTime=").append(String.format("%02d:%02d", c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE)));
|
|
||||||
uri.append("&REQ0JourneyStopsS0ID=").append(ParserUtils.urlEncode(locationId(from)));
|
|
||||||
if (via != null)
|
|
||||||
uri.append("&REQ0JourneyStops1.0ID=").append(ParserUtils.urlEncode(locationId(via)));
|
|
||||||
uri.append("&REQ0JourneyStopsZ0ID=").append(ParserUtils.urlEncode(locationId(to)));
|
|
||||||
uri.append("&REQ0JourneyDep_Foot_speed=").append(WALKSPEED_MAP.get(walkSpeed));
|
|
||||||
|
|
||||||
for (final char p : products.toCharArray())
|
|
||||||
{
|
|
||||||
if (p == 'I')
|
|
||||||
uri.append("&REQ0JourneyProduct_prod_list_1=1000000000000000");
|
|
||||||
if (p == 'R')
|
|
||||||
uri.append("&REQ0JourneyProduct_prod_list_2=0110000000100000");
|
|
||||||
if (p == 'S')
|
|
||||||
uri.append("&REQ0JourneyProduct_prod_list_3=0001000000000000");
|
|
||||||
if (p == 'U')
|
|
||||||
uri.append("&REQ0JourneyProduct_prod_list_4=0000100000000000");
|
|
||||||
if (p == 'T')
|
|
||||||
uri.append("&REQ0JourneyProduct_prod_list_5=0000010000000000");
|
|
||||||
if (p == 'B')
|
|
||||||
uri.append("&REQ0JourneyProduct_prod_list_6=0000001100000000");
|
|
||||||
if (p == 'P')
|
|
||||||
uri.append("&REQ0JourneyProduct_prod_list_7=0000000001000000");
|
|
||||||
if (p == 'F')
|
|
||||||
uri.append("&REQ0JourneyProduct_prod_list_8=0000000010000000");
|
|
||||||
// FIXME if (p == 'C')
|
|
||||||
}
|
|
||||||
|
|
||||||
uri.append("&start=Suchen");
|
|
||||||
|
|
||||||
return uri.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Pattern P_PRE_ADDRESS = Pattern.compile("(?:Geben Sie einen (Startort|Zielort) an.*?)?Bitte wählen Sie aus der Liste",
|
|
||||||
Pattern.DOTALL);
|
|
||||||
private static final Pattern P_ADDRESSES = Pattern.compile(
|
|
||||||
"<span class=\"tplight\">.*?<a href=\"/auskunft/bin/jp/query.exe/dox.*?\">\\s*(.*?)\\s*</a>.*?</span>", Pattern.DOTALL);
|
|
||||||
private static final Pattern P_CHECK_CONNECTIONS_ERROR = Pattern.compile(
|
|
||||||
"(mehrfach vorhanden oder identisch)|(keine geeigneten Haltestellen)|(keine Verbindung gefunden)|(derzeit nur Auskünfte vom)",
|
|
||||||
Pattern.CASE_INSENSITIVE);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public QueryConnectionsResult queryConnections(final Location from, final Location via, final Location to, final Date date, final boolean dep,
|
|
||||||
final String products, final WalkSpeed walkSpeed) throws IOException
|
|
||||||
{
|
|
||||||
final String uri = connectionsQueryUri(from, via, to, date, dep, products, walkSpeed);
|
|
||||||
final CharSequence page = ParserUtils.scrape(uri);
|
|
||||||
|
|
||||||
final Matcher mError = P_CHECK_CONNECTIONS_ERROR.matcher(page);
|
|
||||||
if (mError.find())
|
|
||||||
{
|
|
||||||
if (mError.group(1) != null)
|
|
||||||
return QueryConnectionsResult.TOO_CLOSE;
|
|
||||||
if (mError.group(2) != null)
|
|
||||||
return QueryConnectionsResult.UNRESOLVABLE_ADDRESS;
|
|
||||||
if (mError.group(3) != null)
|
|
||||||
return QueryConnectionsResult.NO_CONNECTIONS;
|
|
||||||
if (mError.group(4) != null)
|
|
||||||
return QueryConnectionsResult.INVALID_DATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Location> fromAddresses = null;
|
|
||||||
List<Location> viaAddresses = null;
|
|
||||||
List<Location> toAddresses = null;
|
|
||||||
|
|
||||||
final Matcher mPreAddress = P_PRE_ADDRESS.matcher(page);
|
|
||||||
while (mPreAddress.find())
|
|
||||||
{
|
|
||||||
final String type = mPreAddress.group(1);
|
|
||||||
|
|
||||||
final Matcher mAddresses = P_ADDRESSES.matcher(page);
|
|
||||||
final List<Location> addresses = new ArrayList<Location>();
|
|
||||||
while (mAddresses.find())
|
|
||||||
{
|
|
||||||
final String address = ParserUtils.resolveEntities(mAddresses.group(1)).trim();
|
|
||||||
if (!addresses.contains(address))
|
|
||||||
addresses.add(new Location(LocationType.ANY, 0, null, address + "!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == null)
|
|
||||||
viaAddresses = addresses;
|
|
||||||
else if (type.equals("Startort"))
|
|
||||||
fromAddresses = addresses;
|
|
||||||
else if (type.equals("Zielort"))
|
|
||||||
toAddresses = addresses;
|
|
||||||
else
|
|
||||||
throw new IllegalStateException(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fromAddresses != null || viaAddresses != null || toAddresses != null)
|
|
||||||
return new QueryConnectionsResult(fromAddresses, viaAddresses, toAddresses);
|
|
||||||
else
|
|
||||||
return queryConnections(uri, page);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Pattern P_CONNECTIONS_HEAD = Pattern.compile(".*?" //
|
|
||||||
+ "Von: <b>(.*?)</b>.*?" // from
|
|
||||||
+ "Nach: <b>(.*?)</b>.*?" // to
|
|
||||||
+ "Datum: .., (\\d+\\..\\d+\\.\\d+).*?" // currentDate
|
|
||||||
+ "(?:<a href=\"(http://www.rmv.de/auskunft/bin/jp/query.exe/dox[^\"]*?REQ0HafasScrollDir=2)\".*?)?" // linkEarlier
|
|
||||||
+ "(?:<a href=\"(http://www.rmv.de/auskunft/bin/jp/query.exe/dox[^\"]*?REQ0HafasScrollDir=1)\".*?)?" // linkLater
|
|
||||||
, Pattern.DOTALL);
|
|
||||||
private static final Pattern P_CONNECTIONS_COARSE = Pattern.compile("<p class=\"con(?:L|D)\">(.+?)</p>", Pattern.DOTALL);
|
|
||||||
private static final Pattern P_CONNECTIONS_FINE = Pattern.compile(".*?" //
|
|
||||||
+ "<a href=\"(/auskunft/bin/jp/query.exe/dox[^\"]*?)\">" // link
|
|
||||||
+ "(\\d+:\\d+)-(\\d+:\\d+)</a>" // departureTime, arrivalTime
|
|
||||||
+ "(?: (.+?))?" // line
|
|
||||||
, Pattern.DOTALL);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public QueryConnectionsResult queryMoreConnections(final String uri) throws IOException
|
|
||||||
{
|
|
||||||
final CharSequence page = ParserUtils.scrape(uri);
|
|
||||||
|
|
||||||
return queryConnections(uri, page);
|
|
||||||
}
|
|
||||||
|
|
||||||
private QueryConnectionsResult queryConnections(final String uri, final CharSequence page) throws IOException
|
|
||||||
{
|
|
||||||
final Matcher mHead = P_CONNECTIONS_HEAD.matcher(page);
|
|
||||||
if (mHead.matches())
|
|
||||||
{
|
|
||||||
final Location from = new Location(LocationType.ANY, 0, null, ParserUtils.resolveEntities(mHead.group(1)));
|
|
||||||
final Location to = new Location(LocationType.ANY, 0, null, ParserUtils.resolveEntities(mHead.group(2)));
|
|
||||||
final Calendar currentDate = new GregorianCalendar(timeZone());
|
|
||||||
currentDate.clear();
|
|
||||||
ParserUtils.parseGermanDate(currentDate, mHead.group(3));
|
|
||||||
// final String linkEarlier = mHead.group(4) != null ? ParserUtils.resolveEntities(mHead.group(4)) : null;
|
|
||||||
final String linkLater = mHead.group(5) != null ? ParserUtils.resolveEntities(mHead.group(5)) : null;
|
|
||||||
final List<Connection> connections = new ArrayList<Connection>();
|
|
||||||
|
|
||||||
final Matcher mConCoarse = P_CONNECTIONS_COARSE.matcher(page);
|
|
||||||
while (mConCoarse.find())
|
|
||||||
{
|
|
||||||
final Matcher mConFine = P_CONNECTIONS_FINE.matcher(mConCoarse.group(1));
|
|
||||||
if (mConFine.matches())
|
|
||||||
{
|
|
||||||
final String link = "http://www.rmv.de" + ParserUtils.resolveEntities(mConFine.group(1));
|
|
||||||
final Calendar departureTime = new GregorianCalendar(timeZone());
|
|
||||||
departureTime.setTimeInMillis(currentDate.getTimeInMillis());
|
|
||||||
ParserUtils.parseEuropeanTime(departureTime, mConFine.group(2));
|
|
||||||
if (!connections.isEmpty())
|
|
||||||
{
|
|
||||||
final long diff = departureTime.getTimeInMillis() - connections.get(connections.size() - 1).departureTime.getTime();
|
|
||||||
if (diff > PARSER_DAY_ROLLOVER_THRESHOLD_MS)
|
|
||||||
departureTime.add(Calendar.DAY_OF_YEAR, -1);
|
|
||||||
else if (diff < -PARSER_DAY_ROLLOVER_THRESHOLD_MS)
|
|
||||||
departureTime.add(Calendar.DAY_OF_YEAR, 1);
|
|
||||||
}
|
|
||||||
final Calendar arrivalTime = new GregorianCalendar(timeZone());
|
|
||||||
arrivalTime.setTimeInMillis(currentDate.getTimeInMillis());
|
|
||||||
ParserUtils.parseEuropeanTime(arrivalTime, mConFine.group(3));
|
|
||||||
if (departureTime.after(arrivalTime))
|
|
||||||
arrivalTime.add(Calendar.DAY_OF_YEAR, 1);
|
|
||||||
final Connection connection = new Connection(extractConnectionId(link), link, departureTime.getTime(), arrivalTime.getTime(),
|
|
||||||
from, to, null, null);
|
|
||||||
connections.add(connection);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("cannot parse '" + mConCoarse.group(1) + "' on " + uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new QueryConnectionsResult(uri, from, null, to, linkLater, connections);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new IOException(page.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Pattern P_CONNECTION_DETAILS_HEAD = Pattern.compile(".*?<p class=\"details\">\n" //
|
|
||||||
+ "- <b>(.*?)</b> -.*?" // firstDeparture
|
|
||||||
+ "Abfahrt: (\\d{2}\\.\\d{2}\\.\\d{2})<br />\n"// date
|
|
||||||
+ "(?:Ankunft: \\d{2}\\.\\d{2}\\.\\d{2}<br />\n)?" //
|
|
||||||
+ "Dauer: (\\d{1,2}:\\d{2})<br />.*?" // duration
|
|
||||||
, Pattern.DOTALL);
|
|
||||||
private static final Pattern P_CONNECTION_DETAILS_COARSE = Pattern.compile("/b> -\n(.*?- <b>[^<]*)<", Pattern.DOTALL);
|
|
||||||
private static final Pattern P_CONNECTION_DETAILS_FINE = Pattern.compile("<br />\n" //
|
|
||||||
+ "(?:(.*?) nach ([^\n]*)\n" // line, destination
|
|
||||||
+ "<br />\n" //
|
|
||||||
+ "ab (\\d{1,2}:\\d{2})\n" // plannedDepartureTime
|
|
||||||
+ "(?:<span class=\"red\">\nca\\.(\\d{1,2}:\\d{2})\n</span>\n)?" // predictedDepartureTime
|
|
||||||
+ "(?:Gl\\. (.+?)\\s*\n)?" // departurePosition
|
|
||||||
+ "<br />\n" //
|
|
||||||
+ "an (\\d{1,2}:\\d{2})\n" // plannedArrivalTime
|
|
||||||
+ "(?:<span class=\"red\">ca\\.(\\d{1,2}:\\d{2})</span>\n)?" // predictedArrivalTime
|
|
||||||
+ "(?:Gl\\. (.+?)\\s*\n)?" // arrivalPosition
|
|
||||||
+ "<br />\n|" //
|
|
||||||
+ "<a href=[^>]*>\n" //
|
|
||||||
+ "Fussweg\\s*\n" //
|
|
||||||
+ "</a>\n" //
|
|
||||||
+ "(\\d+) Min.<br />\n)" // footway
|
|
||||||
+ "- <b>(.*?)" // arrival
|
|
||||||
, Pattern.DOTALL);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GetConnectionDetailsResult getConnectionDetails(final String uri) throws IOException
|
|
||||||
{
|
|
||||||
final CharSequence page = ParserUtils.scrape(uri);
|
|
||||||
|
|
||||||
final Matcher mHead = P_CONNECTION_DETAILS_HEAD.matcher(page);
|
|
||||||
if (mHead.matches())
|
|
||||||
{
|
|
||||||
final Location firstDeparture = new Location(LocationType.ANY, 0, null, ParserUtils.resolveEntities(mHead.group(1)));
|
|
||||||
final Calendar currentDate = new GregorianCalendar(timeZone());
|
|
||||||
currentDate.clear();
|
|
||||||
ParserUtils.parseGermanDate(currentDate, mHead.group(2));
|
|
||||||
|
|
||||||
final Calendar time = new GregorianCalendar(timeZone());
|
|
||||||
time.setTimeInMillis(currentDate.getTimeInMillis());
|
|
||||||
|
|
||||||
Date lastTime = time.getTime();
|
|
||||||
|
|
||||||
Date firstDepartureTime = null;
|
|
||||||
Date lastArrivalTime = null;
|
|
||||||
Location lastArrival = null;
|
|
||||||
Connection.Trip lastTrip = null;
|
|
||||||
|
|
||||||
final List<Connection.Part> parts = new ArrayList<Connection.Part>(4);
|
|
||||||
|
|
||||||
final Matcher mDetCoarse = P_CONNECTION_DETAILS_COARSE.matcher(page);
|
|
||||||
while (mDetCoarse.find())
|
|
||||||
{
|
|
||||||
final Matcher mDetFine = P_CONNECTION_DETAILS_FINE.matcher(mDetCoarse.group(1));
|
|
||||||
if (mDetFine.matches())
|
|
||||||
{
|
|
||||||
final Location departure = lastArrival != null ? lastArrival : firstDeparture;
|
|
||||||
|
|
||||||
final Location arrival = new Location(LocationType.ANY, 0, null, ParserUtils.resolveEntities(mDetFine.group(10)));
|
|
||||||
lastArrival = arrival;
|
|
||||||
|
|
||||||
final String min = mDetFine.group(9);
|
|
||||||
if (min == null)
|
|
||||||
{
|
|
||||||
final String lineStr = normalizeLine(ParserUtils.resolveEntities(mDetFine.group(1)));
|
|
||||||
final Line line = new Line(lineStr, lineColors(lineStr));
|
|
||||||
|
|
||||||
final Location destination = new Location(LocationType.ANY, 0, null, ParserUtils.resolveEntities(mDetFine.group(2)));
|
|
||||||
|
|
||||||
ParserUtils.parseEuropeanTime(time, mDetFine.group(3));
|
|
||||||
if (time.getTime().before(lastTime))
|
|
||||||
time.add(Calendar.DAY_OF_YEAR, 1);
|
|
||||||
final Date plannedDepartureTime = time.getTime();
|
|
||||||
lastTime.setTime(time.getTimeInMillis());
|
|
||||||
|
|
||||||
final Date predictedDepartureTime;
|
|
||||||
if (mDetFine.group(4) != null)
|
|
||||||
{
|
|
||||||
ParserUtils.parseEuropeanTime(time, mDetFine.group(4));
|
|
||||||
if (time.getTime().before(lastTime))
|
|
||||||
time.add(Calendar.DAY_OF_YEAR, 1);
|
|
||||||
predictedDepartureTime = time.getTime();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
predictedDepartureTime = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Date departureTime = predictedDepartureTime != null ? predictedDepartureTime : plannedDepartureTime;
|
|
||||||
|
|
||||||
final String departurePosition = ParserUtils.resolveEntities(mDetFine.group(5));
|
|
||||||
|
|
||||||
ParserUtils.parseEuropeanTime(time, mDetFine.group(6));
|
|
||||||
if (time.getTime().before(lastTime))
|
|
||||||
time.add(Calendar.DAY_OF_YEAR, 1);
|
|
||||||
final Date plannedArrivalTime = time.getTime();
|
|
||||||
lastTime.setTime(time.getTimeInMillis());
|
|
||||||
|
|
||||||
final Date predictedArrivalTime;
|
|
||||||
if (mDetFine.group(7) != null)
|
|
||||||
{
|
|
||||||
ParserUtils.parseEuropeanTime(time, mDetFine.group(7));
|
|
||||||
if (time.getTime().before(lastTime))
|
|
||||||
time.add(Calendar.DAY_OF_YEAR, 1);
|
|
||||||
predictedArrivalTime = time.getTime();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
predictedArrivalTime = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Date arrivalTime = predictedArrivalTime != null ? predictedArrivalTime : plannedArrivalTime;
|
|
||||||
|
|
||||||
final String arrivalPosition = ParserUtils.resolveEntities(mDetFine.group(8));
|
|
||||||
|
|
||||||
lastTrip = new Connection.Trip(line, destination, departureTime, departurePosition, departure, arrivalTime, arrivalPosition,
|
|
||||||
arrival, null, null);
|
|
||||||
parts.add(lastTrip);
|
|
||||||
|
|
||||||
if (firstDepartureTime == null)
|
|
||||||
firstDepartureTime = departureTime;
|
|
||||||
|
|
||||||
lastArrivalTime = arrivalTime;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (parts.size() > 0 && parts.get(parts.size() - 1) instanceof Connection.Footway)
|
|
||||||
{
|
|
||||||
final Connection.Footway lastFootway = (Connection.Footway) parts.remove(parts.size() - 1);
|
|
||||||
parts.add(new Connection.Footway(lastFootway.min + Integer.parseInt(min), lastFootway.departure, arrival, null));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parts.add(new Connection.Footway(Integer.parseInt(min), departure, arrival, null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("cannot parse '" + mDetCoarse.group(1) + "' on " + uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new GetConnectionDetailsResult(currentDate.getTime(), new Connection(extractConnectionId(uri), uri, firstDepartureTime,
|
|
||||||
lastArrivalTime, firstDeparture, lastArrival, parts, null));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new IOException(page.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String departuresQueryUri(final int stationId, final int maxDepartures)
|
private String departuresQueryUri(final int stationId, final int maxDepartures)
|
||||||
{
|
{
|
||||||
final Calendar c = new GregorianCalendar(timeZone());
|
final Calendar c = new GregorianCalendar(timeZone());
|
||||||
|
@ -507,10 +151,10 @@ public class RmvProvider extends AbstractHafasProvider
|
||||||
+ "Uhr, (\\d+\\.\\d+\\.\\d+).*?" //
|
+ "Uhr, (\\d+\\.\\d+\\.\\d+).*?" //
|
||||||
, Pattern.DOTALL);
|
, Pattern.DOTALL);
|
||||||
private static final Pattern P_DEPARTURES_COARSE = Pattern.compile("<p class=\"sq\">\n(.+?)</p>", Pattern.DOTALL);
|
private static final Pattern P_DEPARTURES_COARSE = Pattern.compile("<p class=\"sq\">\n(.+?)</p>", Pattern.DOTALL);
|
||||||
static final Pattern P_DEPARTURES_FINE = Pattern.compile("" //
|
private static final Pattern P_DEPARTURES_FINE = Pattern.compile("" //
|
||||||
+ "<b>\\s*(.*?)\\s*</b>.*?" // line
|
+ "<b>([^<]*)</b>\n" // line
|
||||||
+ ">>\n" //
|
+ ">>\n" //
|
||||||
+ "(.*?)\n" // destination
|
+ "([^\n]*)\n" // destination
|
||||||
+ "<br />\n" //
|
+ "<br />\n" //
|
||||||
+ "<b>(\\d{1,2}:\\d{2})</b>\n" // plannedTime
|
+ "<b>(\\d{1,2}:\\d{2})</b>\n" // plannedTime
|
||||||
+ "(?:keine Prognose verfügbar\n)?" //
|
+ "(?:keine Prognose verfügbar\n)?" //
|
||||||
|
@ -519,7 +163,7 @@ public class RmvProvider extends AbstractHafasProvider
|
||||||
+ "(?:(Gl\\. " + ParserUtils.P_PLATFORM + ")<br />\n)?" // position
|
+ "(?:(Gl\\. " + ParserUtils.P_PLATFORM + ")<br />\n)?" // position
|
||||||
+ "(?:<span class=\"red\">([^>]*)</span>\n)?" // message
|
+ "(?:<span class=\"red\">([^>]*)</span>\n)?" // message
|
||||||
+ "(?:<img src=\".+?\" alt=\"\" />\n<b>[^<]*</b>\n<br />\n)*" // (messages)
|
+ "(?:<img src=\".+?\" alt=\"\" />\n<b>[^<]*</b>\n<br />\n)*" // (messages)
|
||||||
, Pattern.DOTALL);
|
+ ".*?", Pattern.DOTALL);
|
||||||
|
|
||||||
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
|
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
|
||||||
{
|
{
|
||||||
|
@ -659,6 +303,10 @@ public class RmvProvider extends AbstractHafasProvider
|
||||||
return "TRT" + number;
|
return "TRT" + number;
|
||||||
if (type.startsWith("Bus"))
|
if (type.startsWith("Bus"))
|
||||||
return "B" + type.substring(3) + number;
|
return "B" + type.substring(3) + number;
|
||||||
|
if (type.equals("AS")) // Anruf-Sammel-Taxi
|
||||||
|
return "BAS" + number;
|
||||||
|
if (type.equals("ASOF-")) // Anruf-Sammel-Taxi
|
||||||
|
return "BASOF" + number;
|
||||||
if (type.startsWith("AST")) // Anruf-Sammel-Taxi
|
if (type.startsWith("AST")) // Anruf-Sammel-Taxi
|
||||||
return "BAST" + type.substring(3) + number;
|
return "BAST" + type.substring(3) + number;
|
||||||
if (type.startsWith("ALT")) // Anruf-Linien-Taxi
|
if (type.startsWith("ALT")) // Anruf-Linien-Taxi
|
||||||
|
@ -684,6 +332,15 @@ public class RmvProvider extends AbstractHafasProvider
|
||||||
@Override
|
@Override
|
||||||
protected char normalizeType(final String type)
|
protected char normalizeType(final String type)
|
||||||
{
|
{
|
||||||
throw new UnsupportedOperationException();
|
final String ucType = type.toUpperCase();
|
||||||
|
|
||||||
|
if ("U-BAHN".equals(ucType))
|
||||||
|
return 'U';
|
||||||
|
|
||||||
|
final char t = super.normalizeType(type);
|
||||||
|
if (t != 0)
|
||||||
|
return t;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2010, 2011 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 static junit.framework.Assert.assertNotNull;
|
|
||||||
import static junit.framework.Assert.assertTrue;
|
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andreas Schildbach
|
|
||||||
*/
|
|
||||||
public class RmvProviderTest
|
|
||||||
{
|
|
||||||
@Test
|
|
||||||
public void departureWithNoPrognosisMessage()
|
|
||||||
{
|
|
||||||
final Matcher m = assertFineDepartures("<b>Bus 42 </b>\n" //
|
|
||||||
+ ">>\n" //
|
|
||||||
+ "Frankfurt (Main) Enkheim\n" //
|
|
||||||
+ "<br />\n" //
|
|
||||||
+ "<b>20:21</b>\n" //
|
|
||||||
+ "keine Prognose verfügbar\n" //
|
|
||||||
+ "<span class=\"red\">heute Gl. Enkheim</span><br />\n");
|
|
||||||
|
|
||||||
assertNotNull(m.group(5)); // predictedPosition
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void departureWithMessage()
|
|
||||||
{
|
|
||||||
final Matcher m = assertFineDepartures("<b>Bus 274 </b>\n" //
|
|
||||||
+ ">>\n" //
|
|
||||||
+ "Bad Schwalbach Kurhaus\n" //
|
|
||||||
+ "<br />\n" //
|
|
||||||
+ "<b>15:47</b>\n" //
|
|
||||||
+ "<span class=\"red\">Zug fällt aus</span>\n");
|
|
||||||
|
|
||||||
assertNotNull(m.group(7)); // message
|
|
||||||
}
|
|
||||||
|
|
||||||
private Matcher assertFineDepartures(String s)
|
|
||||||
{
|
|
||||||
Matcher m = RmvProvider.P_DEPARTURES_FINE.matcher(s);
|
|
||||||
assertTrue(m.matches());
|
|
||||||
|
|
||||||
// ParserUtils.printGroups(m);
|
|
||||||
|
|
||||||
assertNotNull(m.group(1)); // line
|
|
||||||
assertNotNull(m.group(2)); // destination
|
|
||||||
assertNotNull(m.group(3)); // time
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -24,7 +24,6 @@ import org.junit.Test;
|
||||||
|
|
||||||
import de.schildbach.pte.NetworkProvider.WalkSpeed;
|
import de.schildbach.pte.NetworkProvider.WalkSpeed;
|
||||||
import de.schildbach.pte.RmvProvider;
|
import de.schildbach.pte.RmvProvider;
|
||||||
import de.schildbach.pte.dto.Connection;
|
|
||||||
import de.schildbach.pte.dto.Location;
|
import de.schildbach.pte.dto.Location;
|
||||||
import de.schildbach.pte.dto.LocationType;
|
import de.schildbach.pte.dto.LocationType;
|
||||||
import de.schildbach.pte.dto.NearbyStationsResult;
|
import de.schildbach.pte.dto.NearbyStationsResult;
|
||||||
|
@ -39,6 +38,30 @@ public class RmvProviderLiveTest
|
||||||
private final RmvProvider provider = new RmvProvider();
|
private final RmvProvider provider = new RmvProvider();
|
||||||
protected static final String ALL_PRODUCTS = "IRSUTBFC";
|
protected static final String ALL_PRODUCTS = "IRSUTBFC";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nearbyStations() throws Exception
|
||||||
|
{
|
||||||
|
final NearbyStationsResult result = provider.queryNearbyStations(new Location(LocationType.STATION, 3000001), 0, 0);
|
||||||
|
|
||||||
|
System.out.println(result.stations.size() + " " + result.stations);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nearbyStationsByCoordinate() throws Exception
|
||||||
|
{
|
||||||
|
final NearbyStationsResult result = provider.queryNearbyStations(new Location(LocationType.ADDRESS, 50108625, 8669604), 0, 0);
|
||||||
|
|
||||||
|
System.out.println(result.stations.size() + " " + result.stations);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void queryDepartures() throws Exception
|
||||||
|
{
|
||||||
|
final QueryDeparturesResult result = provider.queryDepartures(3000408, 0, false);
|
||||||
|
|
||||||
|
System.out.println(result.stationDepartures);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void autocomplete() throws Exception
|
public void autocomplete() throws Exception
|
||||||
{
|
{
|
||||||
|
@ -55,22 +78,6 @@ public class RmvProviderLiveTest
|
||||||
System.out.println();
|
System.out.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void nearbyStations() throws Exception
|
|
||||||
{
|
|
||||||
final NearbyStationsResult result = provider.queryNearbyStations(new Location(LocationType.STATION, 3000001), 0, 0);
|
|
||||||
|
|
||||||
System.out.println(result.stations.size() + " " + result.stations);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void queryDepartures() throws Exception
|
|
||||||
{
|
|
||||||
final QueryDeparturesResult result = provider.queryDepartures(3000001, 0, false);
|
|
||||||
|
|
||||||
System.out.println(result.stationDepartures);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shortConnection() throws Exception
|
public void shortConnection() throws Exception
|
||||||
{
|
{
|
||||||
|
@ -78,11 +85,9 @@ public class RmvProviderLiveTest
|
||||||
new Location(LocationType.ANY, 0, null, "Frankfurt Hauptbahnhof!"), new Date(), true, ALL_PRODUCTS, WalkSpeed.NORMAL);
|
new Location(LocationType.ANY, 0, null, "Frankfurt Hauptbahnhof!"), new Date(), true, ALL_PRODUCTS, WalkSpeed.NORMAL);
|
||||||
System.out.println(result);
|
System.out.println(result);
|
||||||
final QueryConnectionsResult moreResult = provider.queryMoreConnections(result.context);
|
final QueryConnectionsResult moreResult = provider.queryMoreConnections(result.context);
|
||||||
for (final Connection connection : result.connections)
|
|
||||||
provider.getConnectionDetails(connection.link);
|
|
||||||
System.out.println(moreResult);
|
System.out.println(moreResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shortConnectionByName() throws Exception
|
public void shortConnectionByName() throws Exception
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue