listShapesForRoute method

Future<Set<RouteDirection>> listShapesForRoute(
  1. GtfsDataset dataset,
  2. Route route
)

Implementation

Future<Set<RouteDirection>> listShapesForRoute(
  GtfsDataset dataset,
  Route route,
) async {
  final trips = (await dataset.trips.listResource(
    LoadCriterion([
      'route_id',
    ], (requestedFields) => requestedFields[0] == route.id),
  ));

  Map<RawDirectionId, Set<String>> rawRouteDirections = {};

  void addRawRouteDirection(RawDirectionId value) {
    final existingRawRouteDirection = rawRouteDirections.keys
        .cast<RawDirectionId?>()
        .firstWhere(
          (element) =>
              listEquals(element!.stopIds, value.stopIds) &&
              listEquals(
                element.headsigns.toList(growable: false),
                value.headsigns.toList(growable: false),
              ),
          orElse: () => null,
        );

    rawRouteDirections[existingRawRouteDirection ?? value] =
        (rawRouteDirections[existingRawRouteDirection] ?? <String>{})
          ..add(value.tripId);
  }

  String? currentTripId;
  Map<int, String> currentMarkedStopIds = {};
  Set<String> headsigns = {};

  final tripIds = trips.map((trip) => trip.id);
  await for (StopTime stopTime in dataset.stopTimes.streamResource(
    LoadCriterion([
      'trip_id',
    ], (requestedFields) => tripIds.contains(requestedFields[0])),
  )) {
    if (currentTripId == null) {
      currentTripId = stopTime.tripId;
      final firstHeadsign =
          trips
              .firstWhere((element) => element.id == currentTripId)
              .tripHeadsign;
      if (firstHeadsign != null) {
        headsigns.add(firstHeadsign);
      }
    } else if (currentTripId != stopTime.tripId) {
      final sortedStopIds = (currentMarkedStopIds.entries.toList(
        growable: false,
      )..sort(
        (a, b) => a.key.compareTo(b.key),
      )).map((e) => e.value).toList(growable: false);

      addRawRouteDirection((
        stopIds: sortedStopIds,
        headsigns: headsigns,
        tripId: currentTripId,
      ));

      currentTripId = stopTime.tripId;
      currentMarkedStopIds = {};
      headsigns = {};
      final headsign =
          trips
              .firstWhere((element) => element.id == currentTripId)
              .tripHeadsign;
      if (headsign != null) {
        headsigns.add(headsign);
      }
    }

    currentMarkedStopIds[stopTime.stopSequence] =
        stopTime.stopId!; // TODO: Make work with edge cases
    if (stopTime.stopHeadsign != null) {
      headsigns.add(stopTime.stopHeadsign!);
    }
  }

  final sortedStopIds = (currentMarkedStopIds.entries.toList(growable: false)
    ..sort(
      (a, b) => a.key.compareTo(b.key),
    )).map((e) => e.value).toList(growable: false);

  addRawRouteDirection((
    stopIds: sortedStopIds,
    headsigns: headsigns,
    tripId: currentTripId!,
  ));

  Set<String> presentStopIds = rawRouteDirections.keys.fold(
    <String>{},
    (previousValue, element) => previousValue..addAll(element.stopIds),
  );
  Map<String, Stop> stops = {};
  await for (AStop stop in dataset.stops.streamResource(
    LoadCriterion([
      'stop_id',
    ], (requestedFields) => presentStopIds.contains(requestedFields.single)),
  )) {
    stops[stop.id] =
        stop
            as Stop; // From the spec we know these are type 0 (stop/platform)
  }
  return rawRouteDirections.entries
      .map(
        (kp) => RouteDirection(
          stops: kp.key.stopIds.map((e) => stops[e]!).toList(growable: false),
          name: kp.key.headsigns.join(' / '),
          tripIds: kp.value.toList(growable: false),
        ),
      )
      .toSet();
}