diff --git a/src/de/schildbach/pte/BvgProvider.java b/src/de/schildbach/pte/BvgProvider.java
index bb531725..6c73a916 100644
--- a/src/de/schildbach/pte/BvgProvider.java
+++ b/src/de/schildbach/pte/BvgProvider.java
@@ -23,6 +23,7 @@ import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
@@ -39,6 +40,7 @@ import de.schildbach.pte.dto.QueryConnectionsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.dto.QueryDeparturesResult.Status;
import de.schildbach.pte.dto.StationDepartures;
+import de.schildbach.pte.dto.Stop;
import de.schildbach.pte.exception.SessionExpiredException;
import de.schildbach.pte.util.Color;
import de.schildbach.pte.util.ParserUtils;
@@ -441,11 +443,12 @@ public final class BvgProvider extends AbstractHafasProvider
+ "([^<]*)" // departureLat,departureLon,departureName
+ ")?.*?" //
+ "(?:" //
- + "ab (\\d+:\\d+)\n" // departureTime
+ + "ab (\\d{1,2}:\\d{2})\n" // departureTime
+ "(?:Gl\\. (.+?))?.*?" // departurePosition
+ "\\s*(.*?)\\s*.*?" // line
- + "Ri\\. (.*?)[\n\\.]*<.*?" // destination
- + "an (\\d+:\\d+)\n" // arrivalTime
+ + "Ri\\. (.*?)[\n\\.]*<.*?\n" // destination
+ + "(.*?)\n" // intermediates
+ + "an (\\d{1,2}:\\d{2})\n" // arrivalTime
+ "(?:Gl\\. (.+?))?.*?" // arrivalPosition
+ "\n" // arrivalId
+ "([^<]*)" // arrivalName
@@ -456,11 +459,33 @@ public final class BvgProvider extends AbstractHafasProvider
+ "(?:\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);
@Override
public GetConnectionDetailsResult getConnectionDetails(final String uri) throws IOException
{
- final CharSequence page = ParserUtils.scrape(uri);
+ // 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 mHead = P_CONNECTION_DETAILS_HEAD.matcher(page);
if (mHead.matches())
@@ -474,6 +499,9 @@ public final class BvgProvider extends AbstractHafasProvider
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())
@@ -502,14 +530,14 @@ public final class BvgProvider extends AbstractHafasProvider
if (departure != null && firstDeparture == null)
firstDeparture = departure;
- final String min = mDetFine.group(14);
+ final String min = mDetFine.group(15);
if (min == null)
{
- final Calendar departureTime = new GregorianCalendar(timeZone());
- departureTime.setTimeInMillis(currentDate.getTimeInMillis());
- ParserUtils.parseEuropeanTime(departureTime, mDetFine.group(6));
- if (lastArrivalTime != null && departureTime.getTime().before(lastArrivalTime))
- departureTime.add(Calendar.DAY_OF_YEAR, 1);
+ ParserUtils.parseEuropeanTime(time, mDetFine.group(6));
+ 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);
@@ -520,38 +548,55 @@ public final class BvgProvider extends AbstractHafasProvider
final Location destination = new Location(LocationType.ANY, 0, destinationPlaceAndName[0], destinationPlaceAndName[1]);
- final Calendar arrivalTime = new GregorianCalendar(timeZone());
- arrivalTime.setTimeInMillis(currentDate.getTimeInMillis());
- ParserUtils.parseEuropeanTime(arrivalTime, mDetFine.group(10));
- if (departureTime.after(arrivalTime))
- arrivalTime.add(Calendar.DAY_OF_YEAR, 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 arrivalPosition = mDetFine.group(11);
+ final String[] placeAndName = splitNameAndPlace(ParserUtils.resolveEntities(mIntermediates.group(2)));
- final int arrivalId = Integer.parseInt(mDetFine.group(12));
+ ParserUtils.parseEuropeanTime(time, mIntermediates.group(3));
+ if (lastTime != null && time.getTime().before(lastTime))
+ time.add(Calendar.DAY_OF_YEAR, 1);
+ lastTime = time.getTime();
- final String[] arrivalPlaceAndName = splitNameAndPlace(ParserUtils.resolveEntities(mDetFine.group(13)));
+ 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.getTime(), departurePosition, departure,
- arrivalTime.getTime(), arrivalPosition, arrival, null, null));
+ parts.add(new Connection.Trip(line, destination, departureTime, departurePosition, departure, arrivalTime, arrivalPosition,
+ arrival, intermediateStops, null));
if (firstDepartureTime == null)
- firstDepartureTime = departureTime.getTime();
+ firstDepartureTime = departureTime;
lastArrival = arrival;
- lastArrivalTime = arrivalTime.getTime();
+ lastArrivalTime = arrivalTime;
}
else
{
- final int arrivalId = mDetFine.group(15) != null ? Integer.parseInt(mDetFine.group(15)) : 0;
+ final int arrivalId = mDetFine.group(16) != null ? Integer.parseInt(mDetFine.group(16)) : 0;
- final int arrivalLon = mDetFine.group(17) != null ? Integer.parseInt(mDetFine.group(17)) : 0;
- final int arrivalLat = mDetFine.group(18) != null ? Integer.parseInt(mDetFine.group(18)) : 0;
+ 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(16), mDetFine.group(19), mDetFine.group(20))));
+ 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]);