diff --git a/src/de/schildbach/pte/BvgProvider.java b/src/de/schildbach/pte/BvgProvider.java
index 7a0ae5f4..77192857 100644
--- a/src/de/schildbach/pte/BvgProvider.java
+++ b/src/de/schildbach/pte/BvgProvider.java
@@ -19,6 +19,7 @@ package de.schildbach.pte;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
@@ -54,9 +55,9 @@ public final class BvgProvider extends AbstractHafasProvider
public static final String OLD_NETWORK_ID = "mobil.bvg.de";
private static final long PARSER_DAY_ROLLOVER_THRESHOLD_MS = 12 * 60 * 60 * 1000;
- private static final long PARSER_DAY_ROLLDOWN_THRESHOLD_MS = 6 * 60 * 60 * 1000;
- private static final String BVG_BASE_URL = "http://mobil.bvg.de";
+ private static final String BVG_MOBIL_BASE_URL = "http://mobil.bvg.de";
+ private static final String BVG_BASE_URL = "http://www.fahrinfo-berlin.de";
private static final String API_BASE = "http://mobil.bvg.de/Fahrinfo/bin/";
public BvgProvider()
@@ -78,7 +79,7 @@ public final class BvgProvider extends AbstractHafasProvider
return true;
}
- private static final String AUTOCOMPLETE_NAME_URL = "http://mobil.bvg.de/Fahrinfo/bin/stboard.bin/dox/dox?input=%s";
+ private static final String AUTOCOMPLETE_NAME_URL = API_BASE + "stboard.bin/dox/dox?input=%s";
private static final Pattern P_SINGLE_NAME = Pattern.compile(".*?Haltestelleninfo.*?(.*?).*?input=(\\d+)&.*?", Pattern.DOTALL);
private static final Pattern P_MULTI_NAME = Pattern.compile("\\s*(.*?)\\s*",
Pattern.DOTALL);
@@ -201,8 +202,6 @@ public final class BvgProvider extends AbstractHafasProvider
return super.splitNameAndPlace(name);
}
- public static final String STATION_URL_CONNECTION = "http://mobil.bvg.de/Fahrinfo/bin/query.bin/dox";
-
private String connectionsQueryUri(final Location from, final Location via, final Location to, final Date date, final boolean dep,
final String products)
{
@@ -211,7 +210,7 @@ public final class BvgProvider extends AbstractHafasProvider
final StringBuilder uri = new StringBuilder();
- uri.append("http://mobil.bvg.de/Fahrinfo/bin/query.bin/dox");
+ uri.append(API_BASE).append("query.bin/dn");
uri.append("?REQ0HafasInitialSelection=0");
appendLocationBvg(uri, from, "S0", "SID");
@@ -227,24 +226,53 @@ public final class BvgProvider extends AbstractHafasProvider
for (final char p : products.toCharArray())
{
if (p == 'I')
- uri.append("&vw=5");
+ {
+ uri.append("&REQ0JourneyProduct_prod_section_0_5=1");
+ if (via != null)
+ uri.append("&REQ0JourneyProduct_prod_section_1_5=1");
+ }
if (p == 'R')
- uri.append("&vw=6");
+ {
+ uri.append("&REQ0JourneyProduct_prod_section_0_6=1");
+ if (via != null)
+ uri.append("&REQ0JourneyProduct_prod_section_1_6=1");
+ }
if (p == 'S')
- uri.append("&vw=0");
+ {
+ uri.append("&REQ0JourneyProduct_prod_section_0_0=1");
+ if (via != null)
+ uri.append("&REQ0JourneyProduct_prod_section_1_0=1");
+ }
if (p == 'U')
- uri.append("&vw=1");
+ {
+ uri.append("&REQ0JourneyProduct_prod_section_0_1=1");
+ if (via != null)
+ uri.append("&REQ0JourneyProduct_prod_section_1_1=1");
+ }
if (p == 'T')
- uri.append("&vw=2");
+ {
+ uri.append("&REQ0JourneyProduct_prod_section_0_2=1");
+ if (via != null)
+ uri.append("&REQ0JourneyProduct_prod_section_1_2=1");
+ }
if (p == 'B')
- uri.append("&vw=3");
+ {
+ uri.append("&REQ0JourneyProduct_prod_section_0_3=1");
+ if (via != null)
+ uri.append("&REQ0JourneyProduct_prod_section_1_3=1");
+ }
if (p == 'F')
- uri.append("&vw=4");
+ {
+ uri.append("&REQ0JourneyProduct_prod_section_0_4=1");
+ if (via != null)
+ uri.append("&REQ0JourneyProduct_prod_section_1_4=1");
+ }
// FIXME if (p == 'C')
- // TODO Ruftaxi wäre wohl &vw=7
+ // TODO Ruftaxi wäre wohl &REQ0JourneyProduct_prod_section_0_7=1
}
uri.append("&start=Suchen");
+
return uri.toString();
}
@@ -252,7 +280,9 @@ public final class BvgProvider extends AbstractHafasProvider
{
if (location.type == LocationType.ADDRESS && location.hasLocation() && paramWgs != null)
{
- uri.append("&").append(paramWgs).append("=").append(ParserUtils.urlEncode("A=16@X=" + location.lon + "@Y=" + location.lat));
+ final String v = ParserUtils.urlEncode("A=16@X=" + location.lon + "@Y=" + location.lat
+ + (location.name != null ? "@O=" + location.name : ""));
+ uri.append("&").append(paramWgs).append("=").append(v);
}
else
{
@@ -304,7 +334,7 @@ public final class BvgProvider extends AbstractHafasProvider
if (addresses.isEmpty())
{
- return queryConnections(uri, page, from, to);
+ return queryConnections(uri, page);
}
else if (P_CHECK_FROM.matcher(page).find())
{
@@ -323,46 +353,84 @@ public final class BvgProvider extends AbstractHafasProvider
public QueryConnectionsResult queryMoreConnections(final String uri) throws IOException
{
final CharSequence page = ParserUtils.scrape(uri);
- return queryConnections(uri, page, null, null);
+ return queryConnections(uri, page);
}
- private static final Pattern P_LOCATION_ADDRESS = Pattern.compile("\\d{5}.*?,.*");
-
- private Location location(final String str, final Location originalLocation)
+ private Location location(final String typeStr, final String idStr, final String latStr, final String lonStr, final String nameStr)
{
- if (P_LOCATION_ADDRESS.matcher(str).matches())
- return new Location(LocationType.ADDRESS, 0, null, str);
- else if (originalLocation != null && str.equals(originalLocation.name))
- return originalLocation;
- else if (originalLocation != null && originalLocation.type == LocationType.ADDRESS && str.length() == 0)
- return originalLocation;
- else if (str.length() > 0)
- return new Location(LocationType.ANY, 0, null, str);
+ final int id = idStr != null ? Integer.parseInt(idStr) : 0;
+ final int lat = latStr != null ? (int) (Float.parseFloat(latStr) * 1E6) : 0;
+ final int lon = lonStr != null ? (int) (Float.parseFloat(lonStr) * 1E6) : 0;
+ final String[] placeAndName = splitNameAndPlace(nameStr);
+
+ final LocationType type;
+ if (typeStr == null)
+ type = LocationType.ANY;
+ else if ("HST".equals(typeStr))
+ type = LocationType.STATION;
+ else if ("ADR".equals(typeStr))
+ type = LocationType.ADDRESS;
else
- return null;
+ throw new IllegalArgumentException("cannot handle: " + typeStr);
+
+ return new Location(type, id, lat, lon, placeAndName[0], placeAndName[1]);
}
+ private Location location(final String[] track)
+ {
+ final int id = track[4].length() > 0 ? Integer.parseInt(track[4]) : 0;
+ final int lat = Integer.parseInt(track[6]);
+ final int lon = Integer.parseInt(track[5]);
+ final String[] placeAndName = splitNameAndPlace(ParserUtils.resolveEntities(track[9]));
+ final String typeStr = track[1];
+
+ final LocationType type;
+ if ("STATION".equals(typeStr))
+ type = LocationType.STATION;
+ else if ("ADDRESS".equals(typeStr))
+ type = LocationType.ADDRESS;
+ else
+ throw new IllegalArgumentException("cannot handle: " + Arrays.toString(track));
+
+ return new Location(type, id, lat, lon, placeAndName[0], placeAndName[1]);
+ }
+
+ private static final Pattern P_CONNECTIONS_ALL_DETAILS = Pattern.compile("]*>Details für alle");
private static final Pattern P_CONNECTIONS_HEAD = Pattern.compile(".*?" //
- + "Von: (.*?).*?" // from
- + "Nach: (.*?).*?" // to
- + "Datum: .., (.*?)
.*?" // currentDate
- + "(?:.*?)?" // linkEarlier
- + "(?:.*?)?" // linkLater
+ + "
]*>\n" //
+ + "([^\n]*)\n" // from name
+ + "]*>\n" //
+ + "([^\n]*)<.*?)?" // via name
+ + " | ]*>\n" //
+ + "([^\n]*)\n" // to name
+ + "]*>.., (\\d{2}\\.\\d{2}\\.\\d{2}) \\d{1,2}:\\d{2} | .*?" // date
+ + "(?:]*?>.*?)?" // linkEarlier
+ + "(?:]*?>.*?)?" // linkLater
, Pattern.DOTALL);
- private static final Pattern P_CONNECTIONS_COARSE = Pattern.compile("(.+?)
", Pattern.DOTALL);
+ private static final Pattern P_CONNECTIONS_COARSE = Pattern
+ .compile("", Pattern.DOTALL);
private static final Pattern P_CONNECTIONS_FINE = Pattern.compile(".*?" //
- + "" // link
- + "(\\d\\d:\\d\\d)-(\\d\\d:\\d\\d) " // departureTime, arrivalTime
- + "(?:\\d+ Umst\\.|([\\w\\d ]+)).*?" // line
+ + "Verbindungen - Detailansicht - Abfahrt: am (\\d{2}\\.\\d{2}\\.\\d{2}) um \\d{1,2}:\\d{2}.*?" // date
+ + "guiVCtrl_connection_detailsOut_setStatus_([^_]+)_allHalts=yes.*?" // id
+ + "" // track
+ + ".*?", Pattern.DOTALL);
+ private static final Pattern P_CONNECTION_DETAILS = Pattern.compile("" //
+ + "]*headers=\"hafasDTL\\d+_Platform\"[^>]*>\n\\s*([^\\s\n]*?)\\s*\n | .*?" // departure platform
+ + "(?:\nRichtung: ([^\n]*)\n.*?)?" // destination
+ + "]*headers=\"hafasDTL\\d+_Platform\"[^>]*>\n\\s*([^\\s\n]*?)\\s*\n | " // arrival platform
, Pattern.DOTALL);
+
private static final Pattern P_CHECK_CONNECTIONS_ERROR = Pattern.compile("(zu dicht beieinander|mehrfach vorhanden oder identisch)|"
+ "(keine geeigneten Haltestellen)|(keine Verbindung gefunden)|"
+ "(derzeit nur Auskünfte vom)|(zwischenzeitlich nicht mehr gespeichert)|(http-equiv=\"refresh\")", Pattern.CASE_INSENSITIVE);
- private QueryConnectionsResult queryConnections(final String uri, final CharSequence page, final Location originalFrom, final Location originalTo)
- throws IOException
+ private QueryConnectionsResult queryConnections(final String firstUri, CharSequence firstPage) throws IOException
{
- final Matcher mError = P_CHECK_CONNECTIONS_ERROR.matcher(page);
+ final Matcher mError = P_CHECK_CONNECTIONS_ERROR.matcher(firstPage);
if (mError.find())
{
if (mError.group(1) != null)
@@ -379,257 +447,154 @@ public final class BvgProvider extends AbstractHafasProvider
throw new IOException("connected to private wlan");
}
+ final Matcher mAllDetailsAction = P_CONNECTIONS_ALL_DETAILS.matcher(firstPage);
+ if (!mAllDetailsAction.find())
+ throw new IOException("cannot find all details link in '" + firstPage + "' on " + firstUri);
+
+ final String allDetailsUri = BVG_BASE_URL + ParserUtils.resolveEntities(mAllDetailsAction.group(1));
+ final CharSequence page = ParserUtils.scrape(allDetailsUri);
+
final Matcher mHead = P_CONNECTIONS_HEAD.matcher(page);
if (mHead.matches())
{
- final Location from = location(ParserUtils.resolveEntities(mHead.group(1)), originalFrom);
- final Location to = location(ParserUtils.resolveEntities(mHead.group(2)), originalTo);
+ final Location from = location(mHead.group(3), mHead.group(2), mHead.group(5), mHead.group(4),
+ ParserUtils.resolveEntities(mHead.group(1)));
+ final Location via = mHead.group(6) != null ? location(null, null, null, null, ParserUtils.resolveEntities(mHead.group(6))) : null;
+ final Location to = location(mHead.group(9), mHead.group(8), mHead.group(11), mHead.group(10),
+ ParserUtils.resolveEntities(mHead.group(7)));
final Calendar currentDate = new GregorianCalendar(timeZone());
currentDate.clear();
- ParserUtils.parseGermanDate(currentDate, mHead.group(3));
- // final String linkEarlier = mHead.group(4) != null ? BVG_BASE_URL +
- // ParserUtils.resolveEntities(mHead.group(4)) : null;
- final String linkLater = mHead.group(5) != null ? BVG_BASE_URL + ParserUtils.resolveEntities(mHead.group(5)) : null;
+ ParserUtils.parseGermanDate(currentDate, mHead.group(12));
+ // final String linkEarlier = mHead.group(13) != null ? BVG_BASE_URL +
+ // ParserUtils.resolveEntities(mHead.group(13)) : null;
+ final String linkLater = mHead.group(14) != null ? BVG_BASE_URL + ParserUtils.resolveEntities(mHead.group(14)) : null;
final List connections = new ArrayList();
final Matcher mConCoarse = P_CONNECTIONS_COARSE.matcher(page);
+ int iCon = 0;
while (mConCoarse.find())
{
- final Matcher mConFine = P_CONNECTIONS_FINE.matcher(mConCoarse.group(1));
+ if (++iCon != Integer.parseInt(mConCoarse.group(1)))
+ throw new IllegalStateException("missing connection: " + iCon);
+ final Matcher mConFine = P_CONNECTIONS_FINE.matcher(mConCoarse.group(2));
if (mConFine.matches())
{
- final String link = BVG_BASE_URL + 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 Calendar time = new GregorianCalendar(timeZone());
+ time.clear();
+ ParserUtils.parseGermanDate(time, mConFine.group(1));
+ Date lastTime = null;
+
+ Date firstDepartureTime = null;
+ Date lastArrivalTime = null;
+
+ final String id = mConFine.group(2);
+
+ final String[] trackParts = mConFine.group(3).split("\\*");
+
+ final List> tracks = new ArrayList>();
+ for (final String trackPart : trackParts)
{
- 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_ROLLDOWN_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(AbstractHafasProvider.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(".*(?:Datum|Abfahrt): (\\d\\d\\.\\d\\d\\.\\d\\d).*", Pattern.DOTALL);
- private static final Pattern P_CONNECTION_DETAILS_COARSE = Pattern.compile("\n(.+?)
", Pattern.DOTALL);
- static final Pattern P_CONNECTION_DETAILS_FINE = Pattern.compile("" //
- + "(?:" //
- + "(?:\n)?" // departureId
- + "(.+?)(?:\n)?" // departureName
- + "|" //
- + "([^<]*)" // departureLat,departureLon,departureName
- + ")?.*?" //
- + "(?:" //
- + "ab (\\d{1,2}:\\d{2})\n" // departureTime
- + "(?:Gl\\. (.+?))?.*?" // departurePosition
- + "\\s*(.*?)\\s*.*?" // line
- + "Ri\\. (.*?)[\n\\.]*<.*?\n" // destination
- + "(.*?)\n" // intermediates
- + "an (\\d{1,2}:\\d{2})\n" // arrivalTime
- + "(?:Gl\\. (.+?))?.*?" // arrivalPosition
- + "\n" // arrivalId
- + "([^<]*)" // arrivalName
- + "|" //
- + "(\\d+) Min\\.\n" // footway
- + "(?:Fussweg|Übergang)\n" //
- + "
\n" //
- + "(?:\n" // arrivalId
- + "([^<]*)|([^<]*)|([^<]*)).*?" // arrivalName,arrivalLat,arrivalLon,arrivalName,arrivalName
- + ").*?", Pattern.DOTALL);
- private static final Pattern P_CONNECTION_DETAILS_INTERMEDIATES_ACTION = Pattern.compile("Zwischenhalte anzeigen",
- Pattern.DOTALL);
- private static final Pattern P_CONNECTION_DETAILS_INTERMEDIATES = Pattern.compile("-\n" //
- + "\n" //
- + "([^\n]*)\n" //
- + "\n" //
- + " (\\d{1,2}:\\d{2}) \n", Pattern.DOTALL);
- private static final Pattern P_CONNECTION_DETAILS_ERROR = Pattern.compile("(zwischenzeitlich nicht mehr gespeichert)", Pattern.CASE_INSENSITIVE);
-
- @Override
- public GetConnectionDetailsResult getConnectionDetails(final String uri) throws IOException
- {
- // fetch page without intermediate stops
- CharSequence page = ParserUtils.scrape(uri);
-
- // fetch page with intermediate stops
- final Matcher mIntermediatesAction = P_CONNECTION_DETAILS_INTERMEDIATES_ACTION.matcher(page);
- if (mIntermediatesAction.find())
- {
- try
- {
- page = ParserUtils.scrape(BVG_BASE_URL + ParserUtils.resolveEntities(mIntermediatesAction.group(1)));
- }
- catch (final IOException x)
- {
- // swallow
- }
- }
-
- final Matcher mError = P_CONNECTION_DETAILS_ERROR.matcher(page);
- if (mError.find())
- throw new SessionExpiredException();
-
- final Matcher mHead = P_CONNECTION_DETAILS_HEAD.matcher(page);
- if (mHead.matches())
- {
- final Calendar currentDate = new GregorianCalendar(timeZone());
- currentDate.clear();
- ParserUtils.parseGermanDate(currentDate, mHead.group(1));
- final List parts = new ArrayList(4);
-
- Date firstDepartureTime = null;
- Location firstDeparture = null;
- Date lastArrivalTime = null;
- Location lastArrival = null;
- Date lastTime = null;
- final Calendar time = new GregorianCalendar(timeZone());
- time.setTimeInMillis(currentDate.getTimeInMillis());
-
- 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 String departureName = ParserUtils.resolveEntities(ParserUtils.selectNotNull(mDetFine.group(2), mDetFine.group(5)));
-
- final int departureId = mDetFine.group(1) != null ? Integer.parseInt(mDetFine.group(1)) : 0;
- final int departureLon = mDetFine.group(3) != null ? Integer.parseInt(mDetFine.group(3)) : 0;
- final int departureLat = mDetFine.group(4) != null ? Integer.parseInt(mDetFine.group(4)) : 0;
-
- final Location departure;
- if (departureName != null)
- {
- final String[] placeAndName = splitNameAndPlace(departureName);
- departure = new Location(departureId != 0 ? LocationType.STATION : LocationType.ANY, departureId, departureLat, departureLon,
- placeAndName[0], placeAndName[1]);
- }
- else
- {
- departure = lastArrival;
+ final String[] partElements = trackPart.split("\\|");
+ if (partElements.length != 10)
+ throw new IllegalStateException("cannot parse: '" + trackPart + "'");
+ final int i = Integer.parseInt(partElements[0]);
+ if (i >= tracks.size())
+ tracks.add(new ArrayList());
+ tracks.get(i).add(partElements);
}
- if (departure != null && firstDeparture == null)
- firstDeparture = departure;
+ final Matcher mDetails = P_CONNECTION_DETAILS.matcher(mConCoarse.group(2));
- final String min = mDetFine.group(15);
- if (min == null)
+ final List parts = new ArrayList(tracks.size());
+ for (int iTrack = 0; iTrack < tracks.size(); iTrack++)
{
- ParserUtils.parseEuropeanTime(time, mDetFine.group(6));
+ mDetails.find();
+
+ final List track = tracks.get(iTrack);
+ final String[] tDep = track.get(0);
+ final String[] tArr = track.get(track.size() - 1);
+
+ final Location departure = location(tDep);
+
+ ParserUtils.parseEuropeanTime(time, tDep[8]);
if (lastTime != null && time.getTime().before(lastTime))
time.add(Calendar.DAY_OF_YEAR, 1);
lastTime = time.getTime();
final Date departureTime = time.getTime();
-
- final String departurePosition = mDetFine.group(7);
-
- final String lineStr = normalizeLine(ParserUtils.resolveEntities(mDetFine.group(8)));
- final Line line = new Line(lineStr, lineColors(lineStr));
-
- final String[] destinationPlaceAndName = splitNameAndPlace(ParserUtils.resolveEntities(mDetFine.group(9)));
-
- final Location destination = new Location(LocationType.ANY, 0, destinationPlaceAndName[0], destinationPlaceAndName[1]);
-
- final List intermediateStops = new LinkedList();
- final Matcher mIntermediates = P_CONNECTION_DETAILS_INTERMEDIATES.matcher(mDetFine.group(10));
- while (mIntermediates.find())
- {
- final int id = Integer.parseInt(mIntermediates.group(1));
-
- final String[] placeAndName = splitNameAndPlace(ParserUtils.resolveEntities(mIntermediates.group(2)));
-
- ParserUtils.parseEuropeanTime(time, mIntermediates.group(3));
- if (lastTime != null && time.getTime().before(lastTime))
- time.add(Calendar.DAY_OF_YEAR, 1);
- lastTime = time.getTime();
-
- final Stop stop = new Stop(new Location(LocationType.STATION, id, placeAndName[0], placeAndName[1]), null, time.getTime());
- intermediateStops.add(stop);
- }
-
- ParserUtils.parseEuropeanTime(time, mDetFine.group(11));
- if (lastTime.after(time.getTime()))
- time.add(Calendar.DAY_OF_YEAR, 1);
- lastTime = time.getTime();
- final Date arrivalTime = time.getTime();
-
- final String arrivalPosition = mDetFine.group(12);
-
- final int arrivalId = Integer.parseInt(mDetFine.group(13));
-
- final String[] arrivalPlaceAndName = splitNameAndPlace(ParserUtils.resolveEntities(mDetFine.group(14)));
-
- final Location arrival = new Location(LocationType.STATION, arrivalId, arrivalPlaceAndName[0], arrivalPlaceAndName[1]);
-
- parts.add(new Connection.Trip(line, destination, departureTime, departurePosition, departure, arrivalTime, arrivalPosition,
- arrival, intermediateStops, null));
-
if (firstDepartureTime == null)
firstDepartureTime = departureTime;
- lastArrival = arrival;
- lastArrivalTime = arrivalTime;
- }
- else
- {
- final int arrivalId = mDetFine.group(16) != null ? Integer.parseInt(mDetFine.group(16)) : 0;
+ final String departurePosition = !mDetails.group(1).equals(" ") ? ParserUtils.resolveEntities(mDetails.group(1)) : null;
- final int arrivalLon = mDetFine.group(18) != null ? Integer.parseInt(mDetFine.group(18)) : 0;
- final int arrivalLat = mDetFine.group(19) != null ? Integer.parseInt(mDetFine.group(19)) : 0;
-
- final String[] arrivalPlaceAndName = splitNameAndPlace(ParserUtils.resolveEntities(ParserUtils.selectNotNull(
- mDetFine.group(17), mDetFine.group(20), mDetFine.group(21))));
-
- final Location arrival = new Location(arrivalId != 0 ? LocationType.STATION : LocationType.ANY, arrivalId, arrivalLat,
- arrivalLon, arrivalPlaceAndName[0], arrivalPlaceAndName[1]);
-
- if (parts.size() > 0 && parts.get(parts.size() - 1) instanceof Connection.Footway)
+ if (tArr[2].equals("walk"))
{
- 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));
+ final String[] tArr2 = track.size() > 1 ? tArr : tracks.get(iTrack + 1).get(0);
+
+ final Location arrival = location(tArr2);
+
+ ParserUtils.parseEuropeanTime(time, tArr2[7]);
+ if (lastTime != null && time.getTime().before(lastTime))
+ time.add(Calendar.DAY_OF_YEAR, 1);
+ lastTime = time.getTime();
+ final Date arrivalTime = time.getTime();
+ lastArrivalTime = arrivalTime;
+
+ final int mins = (int) ((arrivalTime.getTime() - departureTime.getTime()) / 1000 / 60);
+
+ parts.add(new Connection.Footway(mins, departure, arrival, null));
}
else
{
- parts.add(new Connection.Footway(Integer.parseInt(min), departure, arrival, null));
- }
+ final List intermediateStops = new LinkedList();
+ for (final String[] tStop : track.subList(1, track.size() - 1))
+ {
+ ParserUtils.parseEuropeanTime(time, tStop[8]);
+ if (lastTime != null && time.getTime().before(lastTime))
+ time.add(Calendar.DAY_OF_YEAR, 1);
+ lastTime = time.getTime();
+ intermediateStops.add(new Stop(location(tStop), null, time.getTime()));
+ }
- lastArrival = arrival;
+ final Location arrival = location(tArr);
+
+ ParserUtils.parseEuropeanTime(time, tArr[7]);
+ if (lastTime != null && time.getTime().before(lastTime))
+ time.add(Calendar.DAY_OF_YEAR, 1);
+ lastTime = time.getTime();
+ final Date arrivalTime = time.getTime();
+ lastArrivalTime = arrivalTime;
+
+ final String arrivalPosition = !mDetails.group(3).equals(" ") ? ParserUtils.resolveEntities(mDetails.group(3))
+ : null;
+
+ final String lineStr = normalizeLine(ParserUtils.resolveEntities(tDep[3]));
+ final Line line = new Line(lineStr, lineColors(lineStr));
+
+ final Location destination;
+ if (mDetails.group(2) != null)
+ {
+ final String[] destinationPlaceAndName = splitNameAndPlace(ParserUtils.resolveEntities(mDetails.group(2)));
+ destination = new Location(LocationType.ANY, 0, destinationPlaceAndName[0], destinationPlaceAndName[1]);
+ }
+ else
+ {
+ destination = null;
+ }
+
+ parts.add(new Connection.Trip(line, destination, departureTime, departurePosition, departure, arrivalTime,
+ arrivalPosition, arrival, intermediateStops, null));
+ }
}
+
+ connections.add(new Connection(id, firstUri, firstDepartureTime, lastArrivalTime, from, to, parts, null));
}
else
{
- throw new IllegalArgumentException("cannot parse '" + mDetCoarse.group(1) + "' on " + uri);
+ throw new IllegalArgumentException("cannot parse '" + mConCoarse.group(2) + "' on " + allDetailsUri);
}
}
- if (firstDepartureTime != null && lastArrivalTime != null)
- return new GetConnectionDetailsResult(currentDate.getTime(), new Connection(AbstractHafasProvider.extractConnectionId(uri), uri,
- firstDepartureTime, lastArrivalTime, firstDeparture, lastArrival, parts, null));
- else
- return new GetConnectionDetailsResult(currentDate.getTime(), null);
+ return new QueryConnectionsResult(firstUri, from, via, to, linkLater, connections);
}
else
{
@@ -637,7 +602,13 @@ public final class BvgProvider extends AbstractHafasProvider
}
}
- private static final String DEPARTURE_URL_LIVE = "http://mobil.bvg.de/IstAbfahrtzeiten/index/mobil?";
+ @Override
+ public GetConnectionDetailsResult getConnectionDetails(final String uri) throws IOException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ private static final String DEPARTURE_URL_LIVE = BVG_MOBIL_BASE_URL + "/IstAbfahrtzeiten/index/mobil?";
private String departuresQueryLiveUri(final String stationId)
{
@@ -647,7 +618,7 @@ public final class BvgProvider extends AbstractHafasProvider
return uri.toString();
}
- private static final String DEPARTURE_URL_PLAN = "http://mobil.bvg.de/Fahrinfo/bin/stboard.bin/dox/dox?boardType=dep&disableEquivs=yes&start=yes&";
+ private static final String DEPARTURE_URL_PLAN = API_BASE + "stboard.bin/dox/dox?boardType=dep&disableEquivs=yes&start=yes&";
private String departuresQueryPlanUri(final String stationId, final int maxDepartures)
{
diff --git a/test/de/schildbach/pte/BvgProviderTest.java b/test/de/schildbach/pte/BvgProviderTest.java
deleted file mode 100644
index 36ed960c..00000000
--- a/test/de/schildbach/pte/BvgProviderTest.java
+++ /dev/null
@@ -1,97 +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 .
- */
-
-package de.schildbach.pte;
-
-import static junit.framework.Assert.assertTrue;
-
-import java.util.regex.Matcher;
-
-import org.junit.Test;
-
-/**
- * @author Andreas Schildbach
- */
-public class BvgProviderTest
-{
- @Test
- public void footwayWithLink()
- {
- assertFineConnectionDetails("" //
- + "10405 Bln Pankow, Christburger Str. 123\n"
- + "
\n" //
- + "10 Min.\n" //
- + "Fussweg\n" //
- + "
\n" //
- + "\n" //
- + "Prenzlauer Allee/Danziger Str. (Berlin)\n" //
- + "\n" //
- + "
\n");
- }
-
- @Test
- public void footwayWithoutLink()
- {
- assertFineConnectionDetails("" //
- + "18 Min.\n" //
- + "Fussweg\n" //
- + "
\n" //
- + "Berlin, Deutschlandhalle\n" //
- + "
Messedamm 26; 14055 Berlin\n" //
- + "
\n");
- }
-
- @Test
- public void footwayUebergang()
- {
- assertFineConnectionDetails("" //
- + "17 Min.\n" //
- + "Übergang\n" //
- + "
\n" //
- + "\n" //
- + "S Olympiastadion (Berlin)\n" //
- + "\n" //
- + "
\n");
- }
-
- @Test
- public void trip()
- {
- assertFineConnectionDetails("" //
- + "\n" //
- + "Brandenburg, Frhr.-v.-Thüngen-Str.\n" //
- + "\n" //
- + "
\n" //
- + "ab 09:35\n" //
- + "
BusH/528\n" //
- + "Ri. Brandenburg, Potsdamer Str.\n" //
- + "
\n" //
- + "an 09:41\n" //
- + "
\n" //
- + "\n" //
- + "Brandenburg, Plauer Str.\n" //
- + "\n" //
- + "
\n");
- }
-
- private void assertFineConnectionDetails(String s)
- {
- Matcher m = BvgProvider.P_CONNECTION_DETAILS_FINE.matcher(s);
- assertTrue(m.matches());
- // ParserUtils.printGroups(m);
- }
-}
diff --git a/test/de/schildbach/pte/live/BvgProviderLiveTest.java b/test/de/schildbach/pte/live/BvgProviderLiveTest.java
index b4be23df..9343daba 100644
--- a/test/de/schildbach/pte/live/BvgProviderLiveTest.java
+++ b/test/de/schildbach/pte/live/BvgProviderLiveTest.java
@@ -24,7 +24,6 @@ import org.junit.Test;
import de.schildbach.pte.BvgProvider;
import de.schildbach.pte.NetworkProvider.WalkSpeed;
-import de.schildbach.pte.dto.Connection;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
@@ -77,20 +76,59 @@ public class BvgProviderLiveTest
null, new Location(LocationType.STATION, 9013103, "Berlin", "Prinzenstraße"), new Date(), true, ALL_PRODUCTS, WalkSpeed.NORMAL);
System.out.println(result);
final QueryConnectionsResult moreResult = provider.queryMoreConnections(result.context);
- for (final Connection connection : result.connections)
- provider.getConnectionDetails(connection.link);
+ System.out.println(moreResult);
+ }
+
+ @Test
+ public void shortViaConnection() throws Exception
+ {
+ final QueryConnectionsResult result = provider.queryConnections(new Location(LocationType.STATION, 9056102, "Berlin", "Nollendorfplatz"),
+ new Location(LocationType.STATION, 9044202, "Berlin", "Bundesplatz"), new Location(LocationType.STATION, 9013103, "Berlin",
+ "Prinzenstraße"), new Date(), true, ALL_PRODUCTS, WalkSpeed.NORMAL);
+ System.out.println(result);
+ final QueryConnectionsResult moreResult = provider.queryMoreConnections(result.context);
System.out.println(moreResult);
}
@Test
public void connectionBetweenCoordinates() throws Exception
{
- final QueryConnectionsResult result = provider.queryConnections(new Location(LocationType.ADDRESS, 0, 52501507, 13357026), null,
- new Location(LocationType.ADDRESS, 0, 52513639, 13568648), new Date(), true, ALL_PRODUCTS, WalkSpeed.NORMAL);
+ final QueryConnectionsResult result = provider.queryConnections(new Location(LocationType.ADDRESS, 0, 52501507, 13357026, null, "from"),
+ null, new Location(LocationType.ADDRESS, 0, 52513639, 13568648, null, "to"), new Date(), true, ALL_PRODUCTS, WalkSpeed.NORMAL);
+ System.out.println(result);
+ final QueryConnectionsResult moreResult = provider.queryMoreConnections(result.context);
+ System.out.println(moreResult);
+ }
+
+ @Test
+ public void viaConnectionBetweenCoordinates() throws Exception
+ {
+ final QueryConnectionsResult result = provider.queryConnections(new Location(LocationType.ADDRESS, 0, 52501507, 13357026, null, "from"),
+ new Location(LocationType.ADDRESS, 0, 52479868, 13324247, null, "via"), new Location(LocationType.ADDRESS, 0, 52513639, 13568648,
+ null, "to"), new Date(), true, ALL_PRODUCTS, WalkSpeed.NORMAL);
+ System.out.println(result);
+ final QueryConnectionsResult moreResult = provider.queryMoreConnections(result.context);
+ System.out.println(moreResult);
+ }
+
+ @Test
+ public void connectionBetweenAddresses() throws Exception
+ {
+ final QueryConnectionsResult result = provider.queryConnections(new Location(LocationType.ADDRESS, 0, null, "10715 Bln Charlb.-Wilm., Weimarische Str. 7"),
+ null, new Location(LocationType.ADDRESS, 0, null, "10178 Bln Mitte, Sophienstr. 24"), new Date(), true, ALL_PRODUCTS, WalkSpeed.NORMAL);
+ System.out.println(result);
+ final QueryConnectionsResult moreResult = provider.queryMoreConnections(result.context);
+ System.out.println(moreResult);
+ }
+
+ @Test
+ public void viaConnectionBetweenAddresses() throws Exception
+ {
+ final QueryConnectionsResult result = provider.queryConnections(new Location(LocationType.ADDRESS, 0, null, "10715 Bln Charlb.-Wilm., Weimarische Str. 7"),
+ new Location(LocationType.ADDRESS, 0, null, "10115 Bln Mitte, Hannoversche Str. 20"), new Location(LocationType.ADDRESS, 0, null,
+ "10178 Bln Mitte, Sophienstr. 24"), new Date(), true, ALL_PRODUCTS, WalkSpeed.NORMAL);
System.out.println(result);
final QueryConnectionsResult moreResult = provider.queryMoreConnections(result.context);
- for (final Connection connection : result.connections)
- provider.getConnectionDetails(connection.link);
System.out.println(moreResult);
}
}