private static final void parseDateTime(final Calendar calendar, final CharSequence str) {
    final Matcher m = P_DATE_TIME.matcher(str);
    if (!m.matches()) throw new RuntimeException("cannot parse: '" + str + "'");

    ParserUtils.parseGermanDate(calendar, m.group(1));
    ParserUtils.parseEuropeanTime(calendar, m.group(2));
  }
Пример #2
0
  @Override
  public GetConnectionDetailsResult getConnectionDetails(final String uri) throws IOException {
    final CharSequence page = ParserUtils.scrape(uri);

    final Matcher mError = P_CONNECTION_DETAILS_ERROR.matcher(page);
    if (mError.find()) {
      if (mError.group(1) != null) throw new SessionExpiredException();
    }

    final Matcher mHead = P_CONNECTION_DETAILS_HEAD.matcher(page);
    if (mHead.matches()) {
      final List<Connection.Part> parts = new ArrayList<Connection.Part>(4);

      Date firstDepartureTime = null;
      Location firstDeparture = null;
      Date lastArrivalTime = null;
      Location lastArrival = null;

      final Matcher mDetCoarse = P_CONNECTION_DETAILS_COARSE.matcher(mHead.group(1));
      while (mDetCoarse.find()) {
        final String section = mDetCoarse.group(1);
        if (P_CONNECTION_DETAILS_MESSAGES.matcher(section).find()) {
          // ignore message for now
        } else {
          final Matcher mDetFine = P_CONNECTION_DETAILS_FINE.matcher(section);
          if (mDetFine.matches()) {
            final Location departure =
                new Location(
                    LocationType.ANY, 0, null, ParserUtils.resolveEntities(mDetFine.group(1)));
            if (departure != null && firstDeparture == null) firstDeparture = departure;

            if (mDetFine.group(2) != null) {
              final String lineStr = normalizeLine(ParserUtils.resolveEntities(mDetFine.group(2)));
              final Line line = new Line(null, lineStr, lineColors(lineStr));

              final Calendar departureTime = new GregorianCalendar(timeZone());
              departureTime.clear();
              ParserUtils.parseEuropeanTime(departureTime, mDetFine.group(3));
              ParserUtils.parseGermanDate(departureTime, mDetFine.group(5));

              final String departurePosition = ParserUtils.resolveEntities(mDetFine.group(4));

              final Location arrival =
                  new Location(
                      LocationType.ANY, 0, null, ParserUtils.resolveEntities(mDetFine.group(6)));

              final Calendar arrivalTime = new GregorianCalendar(timeZone());
              arrivalTime.clear();
              ParserUtils.parseEuropeanTime(arrivalTime, mDetFine.group(7));
              ParserUtils.parseGermanDate(arrivalTime, mDetFine.group(9));

              final String arrivalPosition = ParserUtils.resolveEntities(mDetFine.group(8));

              parts.add(
                  new Connection.Trip(
                      line,
                      null,
                      departureTime.getTime(),
                      departurePosition,
                      departure,
                      arrivalTime.getTime(),
                      arrivalPosition,
                      arrival,
                      null,
                      null));

              if (firstDepartureTime == null) firstDepartureTime = departureTime.getTime();

              lastArrival = arrival;
              lastArrivalTime = arrivalTime.getTime();
            } else if (mDetFine.group(10) != null) {
              final String min = mDetFine.group(10);

              final Location arrival =
                  new Location(
                      LocationType.ANY, 0, null, ParserUtils.resolveEntities(mDetFine.group(11)));

              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));
              }

              lastArrival = arrival;
            } else {
              final Location arrival =
                  new Location(
                      LocationType.ANY, 0, null, ParserUtils.resolveEntities(mDetFine.group(12)));

              parts.add(new Connection.Footway(0, departure, arrival, null));
            }
          } else {
            throw new IllegalArgumentException("cannot parse '" + section + "' on " + uri);
          }
        }
      }

      // verify
      if (firstDepartureTime == null || lastArrivalTime == null)
        throw new IllegalStateException(
            "could not parse all parts of:\n" + mHead.group(1) + "\n" + parts);

      return new GetConnectionDetailsResult(
          new GregorianCalendar(timeZone()).getTime(),
          new Connection(
              AbstractHafasProvider.extractConnectionId(uri),
              uri,
              firstDepartureTime,
              lastArrivalTime,
              firstDeparture,
              lastArrival,
              parts,
              null,
              null));
    } else {
      throw new IOException(page.toString());
    }
  }
  public QueryDeparturesResult queryDepartures(
      final int stationId, final int maxDepartures, final boolean equivs) throws IOException {
    final ResultHeader header = new ResultHeader(SERVER_PRODUCT);
    final QueryDeparturesResult result = new QueryDeparturesResult(header);

    if (stationId < 1000000) // live
    {
      // scrape page
      final String uri = departuresQueryLiveUri(stationId);
      final CharSequence page = ParserUtils.scrape(uri);

      final Matcher mError = P_DEPARTURES_LIVE_ERRORS.matcher(page);
      if (mError.find()) {
        if (mError.group(1) != null)
          return new QueryDeparturesResult(header, QueryDeparturesResult.Status.INVALID_STATION);
        if (mError.group(2) != null)
          return new QueryDeparturesResult(header, QueryDeparturesResult.Status.SERVICE_DOWN);
        if (mError.group(3) != null) throw new UnexpectedRedirectException();
      }

      // parse page
      final Matcher mHead = P_DEPARTURES_LIVE_HEAD.matcher(page);
      if (mHead.matches()) {
        final String[] placeAndName =
            splitPlaceAndName(ParserUtils.resolveEntities(mHead.group(1)));
        final Calendar currentTime = new GregorianCalendar(timeZone());
        currentTime.clear();
        parseDateTime(currentTime, mHead.group(2));

        final Map<String, String> messages = new HashMap<String, String>();

        final Matcher mMsgsCoarse = P_DEPARTURES_LIVE_MSGS_COARSE.matcher(page);
        while (mMsgsCoarse.find()) {
          final Matcher mMsgsFine = P_DEPARTURES_LIVE_MSGS_FINE.matcher(mMsgsCoarse.group(1));
          if (mMsgsFine.matches()) {
            final String lineName = ParserUtils.resolveEntities(mMsgsFine.group(1));
            final char linePproduct = normalizeType(categoryFromName(lineName));
            final Line line = newLine(linePproduct, normalizeLineName(lineName), null);

            final String message =
                ParserUtils.resolveEntities(mMsgsFine.group(3)).replace('\n', ' ');
            messages.put(line.label, message);
          } else {
            throw new IllegalArgumentException(
                "cannot parse '" + mMsgsCoarse.group(1) + "' on " + uri);
          }
        }

        final List<Departure> departures = new ArrayList<Departure>(8);

        final Matcher mDepCoarse = P_DEPARTURES_LIVE_COARSE.matcher(page);
        while (mDepCoarse.find()) {
          final Matcher mDepFine = P_DEPARTURES_LIVE_FINE.matcher(mDepCoarse.group(1));
          if (mDepFine.matches()) {
            final Calendar parsedTime = new GregorianCalendar(timeZone());
            parsedTime.setTimeInMillis(currentTime.getTimeInMillis());
            ParserUtils.parseEuropeanTime(parsedTime, mDepFine.group(1));

            if (parsedTime.getTimeInMillis() - currentTime.getTimeInMillis()
                < -PARSER_DAY_ROLLOVER_THRESHOLD_MS) parsedTime.add(Calendar.DAY_OF_MONTH, 1);

            boolean isPlanned = mDepFine.group(2) != null;

            Date plannedTime = null;
            Date predictedTime = null;
            if (!isPlanned) predictedTime = parsedTime.getTime();
            else plannedTime = parsedTime.getTime();

            final String lineName = ParserUtils.resolveEntities(mDepFine.group(3));
            final char lineProduct = normalizeType(categoryFromName(lineName));
            final Line line = newLine(lineProduct, normalizeLineName(lineName), null);

            final Position position = null;

            final String[] destinationPlaceAndName =
                splitPlaceAndName(ParserUtils.resolveEntities(mDepFine.group(4)));
            final Location destination =
                new Location(
                    LocationType.ANY, 0, destinationPlaceAndName[0], destinationPlaceAndName[1]);

            final String message = messages.get(line.label);

            final Departure dep =
                new Departure(
                    plannedTime, predictedTime, line, position, destination, null, message);
            if (!departures.contains(dep)) departures.add(dep);
          } else {
            throw new IllegalArgumentException(
                "cannot parse '" + mDepCoarse.group(1) + "' on " + uri);
          }
        }

        result.stationDepartures.add(
            new StationDepartures(
                new Location(LocationType.STATION, stationId, placeAndName[0], placeAndName[1]),
                departures,
                null));
        return result;
      } else {
        throw new IllegalArgumentException("cannot parse '" + page + "' on " + uri);
      }
    } else {
      // scrape page
      final String uri = departuresQueryPlanUri(stationId, maxDepartures);
      final CharSequence page = ParserUtils.scrape(uri);

      final Matcher mError = P_DEPARTURES_PLAN_ERRORS.matcher(page);
      if (mError.find()) {
        if (mError.group(1) != null)
          return new QueryDeparturesResult(header, QueryDeparturesResult.Status.INVALID_STATION);
        if (mError.group(2) != null)
          return new QueryDeparturesResult(header, QueryDeparturesResult.Status.SERVICE_DOWN);
        if (mError.group(3) != null) throw new UnexpectedRedirectException();
      }

      // parse page
      final Matcher mHead = P_DEPARTURES_PLAN_HEAD.matcher(page);
      if (mHead.matches()) {
        final String[] placeAndName =
            splitPlaceAndName(ParserUtils.resolveEntities(mHead.group(1)));
        final Calendar currentTime = new GregorianCalendar(timeZone());
        currentTime.clear();
        ParserUtils.parseGermanDate(currentTime, mHead.group(2));
        final List<Departure> departures = new ArrayList<Departure>(8);

        final Matcher mDepCoarse = P_DEPARTURES_PLAN_COARSE.matcher(page);
        while (mDepCoarse.find()) {
          final Matcher mDepFine = P_DEPARTURES_PLAN_FINE.matcher(mDepCoarse.group(1));
          if (mDepFine.matches()) {
            final Calendar parsedTime = new GregorianCalendar(timeZone());
            parsedTime.setTimeInMillis(currentTime.getTimeInMillis());
            ParserUtils.parseEuropeanTime(parsedTime, mDepFine.group(1));

            if (parsedTime.getTimeInMillis() - currentTime.getTimeInMillis()
                < -PARSER_DAY_ROLLOVER_THRESHOLD_MS) parsedTime.add(Calendar.DAY_OF_MONTH, 1);

            final Date plannedTime = parsedTime.getTime();

            final String lineName = ParserUtils.resolveEntities(mDepFine.group(2));
            final char lineProduct = normalizeType(categoryFromName(lineName));
            final Line line = newLine(lineProduct, normalizeLineName(lineName), null);

            final Position position = new Position(ParserUtils.resolveEntities(mDepFine.group(3)));

            final int destinationId = Integer.parseInt(mDepFine.group(4));
            final String[] destinationPlaceAndName =
                splitPlaceAndName(ParserUtils.resolveEntities(mDepFine.group(5)));
            final Location destination =
                new Location(
                    destinationId > 0 ? LocationType.STATION : LocationType.ANY,
                    destinationId,
                    destinationPlaceAndName[0],
                    destinationPlaceAndName[1]);

            final Departure dep =
                new Departure(plannedTime, null, line, position, destination, null, null);
            if (!departures.contains(dep)) departures.add(dep);
          } else {
            throw new IllegalArgumentException(
                "cannot parse '" + mDepCoarse.group(1) + "' on " + uri);
          }
        }

        result.stationDepartures.add(
            new StationDepartures(
                new Location(LocationType.STATION, stationId, placeAndName[0], placeAndName[1]),
                departures,
                null));
        return result;
      } else {
        throw new IllegalArgumentException("cannot parse '" + page + "' on " + uri);
      }
    }
  }
Пример #4
0
  private QueryConnectionsResult queryConnections(final String uri, final CharSequence page)
      throws IOException {
    final Matcher mError = P_CHECK_CONNECTIONS_ERROR.matcher(page);
    if (mError.find()) {
      if (mError.group(1) != null)
        return new QueryConnectionsResult(null, QueryConnectionsResult.Status.TOO_CLOSE);
      if (mError.group(2) != null)
        return new QueryConnectionsResult(null, QueryConnectionsResult.Status.UNRESOLVABLE_ADDRESS);
      if (mError.group(3) != null)
        return new QueryConnectionsResult(null, QueryConnectionsResult.Status.NO_CONNECTIONS);
      if (mError.group(4) != null)
        return new QueryConnectionsResult(null, QueryConnectionsResult.Status.INVALID_DATE);
      if (mError.group(5) != null) throw new SessionExpiredException();
    }

    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 = 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(
                  AbstractHafasProvider.extractConnectionId(link),
                  link,
                  departureTime.getTime(),
                  arrivalTime.getTime(),
                  from,
                  to,
                  null,
                  null,
                  null);
          connections.add(connection);
        } else {
          throw new IllegalArgumentException(
              "cannot parse '" + mConCoarse.group(1) + "' on " + uri);
        }
      }

      return new QueryConnectionsResult(
          new ResultHeader(SERVER_PRODUCT), uri, from, null, to, linkLater, connections);
    } else {
      throw new IOException(page.toString());
    }
  }