diff --git a/src/de/schildbach/pte/AbstractHafasProvider.java b/src/de/schildbach/pte/AbstractHafasProvider.java
index 49b0c794..cfc97e21 100644
--- a/src/de/schildbach/pte/AbstractHafasProvider.java
+++ b/src/de/schildbach/pte/AbstractHafasProvider.java
@@ -922,7 +922,7 @@ public abstract class AbstractHafasProvider implements NetworkProvider
LINES.put('?', new int[] { Color.DKGRAY, Color.WHITE });
}
- public final int[] lineColors(final String line)
+ public int[] lineColors(final String line)
{
if (line.length() == 0)
return null;
diff --git a/src/de/schildbach/pte/BvgProvider.java b/src/de/schildbach/pte/BvgProvider.java
index c6eb2c5a..74c09ab1 100644
--- a/src/de/schildbach/pte/BvgProvider.java
+++ b/src/de/schildbach/pte/BvgProvider.java
@@ -42,6 +42,7 @@ import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryConnectionsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.dto.QueryDeparturesResult.Status;
+import de.schildbach.pte.dto.Station;
import de.schildbach.pte.exception.SessionExpiredException;
import de.schildbach.pte.util.Color;
import de.schildbach.pte.util.ParserUtils;
@@ -49,7 +50,7 @@ import de.schildbach.pte.util.ParserUtils;
/**
* @author Andreas Schildbach
*/
-public final class BvgProvider implements NetworkProvider
+public final class BvgProvider extends AbstractHafasProvider
{
public static final String NETWORK_ID = "mobil.bvg.de";
@@ -57,6 +58,12 @@ public final class BvgProvider implements NetworkProvider
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 API_BASE = "http://mobil.bvg.de/Fahrinfo/bin/";
+
+ public BvgProvider()
+ {
+ super(null, null);
+ }
public boolean hasCapabilities(final Capability... capabilities)
{
@@ -72,6 +79,7 @@ public final class BvgProvider implements NetworkProvider
private static final Pattern P_MULTI_NAME = Pattern.compile("\\s*(.*?)\\s*",
Pattern.DOTALL);
+ @Override
public List autocompleteStations(final CharSequence constraint) throws IOException
{
final List results = new ArrayList();
@@ -93,10 +101,72 @@ public final class BvgProvider implements NetworkProvider
return results;
}
+ private final String NEARBY_URI = API_BASE + "stboard.bin/dn?distance=50&near&input=%s";
+
+ @Override
+ protected String nearbyStationUri(final String stationId)
+ {
+ return String.format(NEARBY_URI, ParserUtils.urlEncode(stationId));
+ }
+
+ private final static Pattern P_NEARBY_OWN = Pattern
+ .compile("/Stadtplan/index.*?location=(\\d+),HST,WGS84,(-?\\d+\\.\\d+),(-?\\d+\\.\\d+)&label=([^\"]*)\"");
+ private final static Pattern P_NEARBY_PAGE = Pattern.compile("(.*?)", Pattern.DOTALL);
+ private final static Pattern P_NEARBY_COARSE = Pattern.compile("(.*?)
", Pattern.DOTALL);
+ private final static Pattern P_NEARBY_FINE_LOCATION = Pattern.compile("input=(\\d+)&[^\"]*\">([^<]*)<");
+
+ @Override
public NearbyStationsResult nearbyStations(final String stationId, final int lat, final int lon, final int maxDistance, final int maxStations)
throws IOException
{
- throw new UnsupportedOperationException();
+ if (stationId == null)
+ throw new IllegalArgumentException("stationId must be given");
+
+ final List stations = new ArrayList();
+
+ final String uri = nearbyStationUri(stationId);
+ final CharSequence page = ParserUtils.scrape(uri);
+
+ final Matcher mOwn = P_NEARBY_OWN.matcher(page);
+ if (mOwn.find())
+ {
+ final int parsedId = Integer.parseInt(mOwn.group(1));
+ final int parsedLon = (int) (Float.parseFloat(mOwn.group(2)) * 1E6);
+ final int parsedLat = (int) (Float.parseFloat(mOwn.group(3)) * 1E6);
+ final String parsedName = ParserUtils.urlDecode(mOwn.group(4), "ISO-8859-1");
+ stations.add(new Station(parsedId, parsedName, parsedLat, parsedLon, 0, null, null));
+ }
+
+ final Matcher mPage = P_NEARBY_PAGE.matcher(page);
+ if (mPage.find())
+ {
+ final Matcher mCoarse = P_NEARBY_COARSE.matcher(mPage.group(1));
+
+ while (mCoarse.find())
+ {
+ final Matcher mFineLocation = P_NEARBY_FINE_LOCATION.matcher(mCoarse.group(1));
+
+ if (mFineLocation.find())
+ {
+ final int parsedId = Integer.parseInt(mFineLocation.group(1));
+ final String parsedName = ParserUtils.resolveEntities(mFineLocation.group(2));
+ stations.add(new Station(parsedId, parsedName, 0, 0, 0, null, null));
+ }
+ else
+ {
+ throw new IllegalArgumentException("cannot parse '" + mCoarse.group(1) + "' on " + uri);
+ }
+ }
+
+ if (maxStations == 0 || maxStations >= stations.size())
+ return new NearbyStationsResult(stations);
+ else
+ return new NearbyStationsResult(stations.subList(0, maxStations));
+ }
+ else
+ {
+ throw new IllegalArgumentException("cannot parse '" + page + "' on " + uri);
+ }
}
public static final String STATION_URL_CONNECTION = "http://mobil.bvg.de/Fahrinfo/bin/query.bin/dox";
@@ -183,6 +253,7 @@ public final class BvgProvider implements NetworkProvider
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)");
+ @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
{
@@ -216,6 +287,7 @@ public final class BvgProvider implements NetworkProvider
}
}
+ @Override
public QueryConnectionsResult queryMoreConnections(final String uri) throws IOException
{
final CharSequence page = ParserUtils.scrape(uri);
@@ -321,6 +393,7 @@ public final class BvgProvider implements NetworkProvider
+ "(.*?)|([^<]*)|([^<]*)).*?" // arrival
+ ").*?", Pattern.DOTALL);
+ @Override
public GetConnectionDetailsResult getConnectionDetails(final String uri) throws IOException
{
final CharSequence page = ParserUtils.scrape(uri);
@@ -648,15 +721,16 @@ public final class BvgProvider implements NetworkProvider
throw new IllegalStateException("cannot normalize line " + line);
}
+ @Override
+ protected char normalizeType(final String type)
+ {
+ throw new UnsupportedOperationException();
+ }
+
private static final Map LINES = new HashMap();
static
{
- LINES.put("I", new int[] { Color.WHITE, Color.RED, Color.RED }); // generic
- LINES.put("R", new int[] { Color.WHITE, Color.RED, Color.RED }); // generic
- LINES.put("S", new int[] { Color.parseColor("#006e34"), Color.WHITE }); // generic
- LINES.put("U", new int[] { Color.parseColor("#003090"), Color.WHITE }); // generic
-
LINES.put("SS1", new int[] { Color.rgb(221, 77, 174), Color.WHITE });
LINES.put("SS2", new int[] { Color.rgb(16, 132, 73), Color.WHITE });
LINES.put("SS25", new int[] { Color.rgb(16, 132, 73), Color.WHITE });
@@ -764,10 +838,13 @@ public final class BvgProvider implements NetworkProvider
LINES.put("RRB93", new int[] { Color.parseColor("#A7653F"), Color.WHITE });
}
+ @Override
public int[] lineColors(final String line)
{
- if (line.length() == 0)
- return null;
- return LINES.get(line);
+ final int[] lineColors = LINES.get(line);
+ if (lineColors != null)
+ return lineColors;
+ else
+ return super.lineColors(line);
}
}
diff --git a/src/de/schildbach/pte/util/ParserUtils.java b/src/de/schildbach/pte/util/ParserUtils.java
index 5e2d2c3f..317d2bf4 100644
--- a/src/de/schildbach/pte/util/ParserUtils.java
+++ b/src/de/schildbach/pte/util/ParserUtils.java
@@ -27,6 +27,7 @@ import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
+import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -360,6 +361,18 @@ public final class ParserUtils
}
}
+ public static String urlDecode(final String str, final String enc)
+ {
+ try
+ {
+ return URLDecoder.decode(str, enc);
+ }
+ catch (final UnsupportedEncodingException x)
+ {
+ throw new RuntimeException(x);
+ }
+ }
+
public static T selectNotNull(final T... groups)
{
T selected = null;
diff --git a/test/de/schildbach/pte/live/BvgProviderLiveTest.java b/test/de/schildbach/pte/live/BvgProviderLiveTest.java
new file mode 100644
index 00000000..d6ae61c1
--- /dev/null
+++ b/test/de/schildbach/pte/live/BvgProviderLiveTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2010 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.live;
+
+import org.junit.Test;
+
+import de.schildbach.pte.BvgProvider;
+import de.schildbach.pte.dto.NearbyStationsResult;
+import de.schildbach.pte.dto.QueryDeparturesResult;
+
+/**
+ * @author Andreas Schildbach
+ */
+public class BvgProviderLiveTest
+{
+ private BvgProvider provider = new BvgProvider();
+
+ @Test
+ public void nearbyStation() throws Exception
+ {
+ final NearbyStationsResult result = provider.nearbyStations("9415052", 0, 0, 0, 0);
+ System.out.println(result.stations.size() + " " + result.stations);
+ }
+
+ @Test
+ public void departures() throws Exception
+ {
+ final QueryDeparturesResult queryDepartures = provider.queryDepartures("309557", 0);
+ System.out.println(queryDepartures.departures);
+ }
+}