import 'dart:typed_data'; import 'package:bus_infotainment/audio_cache.dart'; import 'package:bus_infotainment/backend/live_information.dart'; import 'package:bus_infotainment/backend/modules/info_module.dart'; import 'package:bus_infotainment/utils/NameBeautify.dart'; import 'package:bus_infotainment/utils/OrdinanceSurveyUtils.dart'; import 'package:fast_csv/csv_converter.dart'; import 'package:vector_math/vector_math.dart'; class BusSequences extends InfoModule { Map routes = {}; Map destinations = {}; BusSequences.fromCSV(String destinationsCSV, String busSequencesCSV) { // Init the bus destinations List> destinationRows = CsvConverter().convert(destinationsCSV); destinationRows.removeAt(0); print("Destination rows: ${destinationRows.length}"); for (int i = 0; i < destinationRows.length; i++) { try { List entries = destinationRows[i]; // print("Parsing destination row $i: $entries"); String routeNumber = entries[0].toString(); BusRoute route = routes.containsKey(routeNumber) ? routes[routeNumber]! : BusRoute(routeNumber: routeNumber); String blind = entries[1].toString(); double lat = double.parse(entries[2].toString()); double long = double.parse(entries[3].toString()); Vector2 grid = OSGrid.toNorthingEasting(lat, long); BusDestination destination = BusDestination(); destination.destination = blind; destination.easting = grid.x; destination.northing = grid.y; route.destinations.add(destination); routes[routeNumber] = route; destinations[blind] = destination; } catch (e) {} } print("Loaded ${destinations.length} destinations"); // Init the bus routes List> busSequenceRows = CsvConverter().convert(busSequencesCSV); busSequenceRows.removeAt(0); for (int i = 0; i < busSequenceRows.length; i++) { try { List entries = busSequenceRows[i]; // print("Parsing bus sequence row $i: $entries"); String routeNumber = entries[0].toString(); BusRoute route = routes.containsKey(routeNumber) ? routes[routeNumber]! : BusRoute(routeNumber: routeNumber); int routeVariant = int.parse(entries[1]); BusRouteStop stop = BusRouteStop(); stop.stopName = entries[6].toString(); stop.stopCode = entries[4].toString(); stop.easting = int.parse(entries[7]); stop.northing = int.parse(entries[8]); stop.heading = int.parse(entries[9] != "" ? entries[9] : "-1"); BusRouteVariant variant = route.routeVariants.containsKey(routeVariant) ? route.routeVariants[routeVariant]! : BusRouteVariant(routeVariant: routeVariant, busRoute: route); variant.busStops.add(stop); route.routeVariants[routeVariant] = variant; routes[routeNumber] = route; } catch (e) { print("Error parsing bus sequence: $e"); } } print("Loaded ${routes.length} routes"); // Remove any empty routes List emptyRoutes = []; for (String routeNumber in routes.keys) { if (routes[routeNumber]!.routeVariants.isEmpty) { emptyRoutes.add(routeNumber); } } for (String routeNumber in emptyRoutes) { routes.remove(routeNumber); } } } class BusRoute { String routeNumber = ""; List destinations = []; AnnouncementCache? announcementCache; Map routeVariants = {}; BusRoute({ this.routeNumber = "-1", this.announcementCache, }); } class BusRouteVariant { int routeVariant = -1; List busStops = []; late BusRoute busRoute; BusRouteVariant({ this.routeVariant = -1, required this.busRoute, }); BusDestination? _destination; BusDestination? get destination { if (_destination == null) { // Get the nearest destination BusDestination? nearestDestinationA; double nearestDistanceA = double.infinity; Vector2 stopLocation = Vector2(busStops.last.northing.toDouble(), busStops.last.easting.toDouble()); for (BusDestination destination in busRoute.destinations) { Vector2 destinationLocation = Vector2(destination.northing.toDouble(), destination.easting.toDouble()); double distance = stopLocation.distanceTo(destinationLocation); if (distance < nearestDistanceA) { nearestDestinationA = destination; nearestDistanceA = distance; } } // get the nearest destination from global pool of destinations BusDestination? nearestDestinationB; double nearestDistanceB = double.infinity; for (BusDestination destination in LiveInformation().busSequences.destinations.values) { Vector2 destinationLocation = Vector2(destination.northing.toDouble(), destination.easting.toDouble()); double distance = stopLocation.distanceTo(destinationLocation); if (distance < nearestDistanceB) { nearestDestinationB = destination; nearestDistanceB = distance; } } print("Nearest destination A: $nearestDestinationA, distance: $nearestDistanceA"); print("Nearest destination B: $nearestDestinationB, distance: $nearestDistanceB"); // Choose the nearest destination if (nearestDistanceA < nearestDistanceB) { _destination = nearestDestinationA; } else { _destination = nearestDestinationB; } } return _destination; } @override String toString() { return 'BusRouteVariant{routeVariant: $routeVariant, busRoute: ${busRoute.routeNumber}, busStops: ${busStops.length}, destinations: ${busRoute.destinations.length}}'; } } class BusRouteStop { String stopName = ""; int easting = -1; int northing = -1; int heading = -1; String stopCode = ""; String get formattedStopName { return NameBeautify.beautifyStopName(stopName); } String getAudioFileName() { // Convert the stop name to all caps String stopName = this.stopName.toUpperCase(); stopName = NameBeautify.beautifyStopName(stopName); // replace & with N stopName = stopName.replaceAll('&', 'N'); stopName = stopName.replaceAll('/', ''); stopName = stopName.replaceAll('\'', ''); stopName = stopName.replaceAll(' ', ' '); // Replace space with underscore stopName = stopName.replaceAll(' ', '_'); stopName = stopName.replaceAll('-', '_'); // convert to all caps stopName = stopName.toUpperCase(); stopName = "S_${stopName}_001.mp3"; return stopName; } } class BusDestination { String destination = ""; double easting = -1; double northing = -1; Future getAudioBytes() async { // Convert the stop name to all caps String name = destination.toUpperCase(); name = NameBeautify.beautifyStopName(name); // replace & with N name = name.replaceAll('&', 'N'); name = name.replaceAll('/', ''); name = name.replaceAll('\'', ''); name = name.replaceAll(' ', ' '); // Replace space with underscore name = name.replaceAll(' ', '_'); name = name.replaceAll('-', '_'); // convert to all caps name = name.toUpperCase(); String audioNameA = "D_${name}_001.mp3"; String audioNameB = "S_${name}_001.mp3"; String audioNameC = "A_${name}_001.mp3"; print("Audio name A: $audioNameA"); print("Audio name B: $audioNameB"); print("Audio name C: $audioNameC"); await LiveInformation().announcementModule.announcementCache.loadAnnouncementsFromBytes(await LiveInformation().announcementModule.getBundleBytes(), [audioNameA, audioNameB, audioNameC]); Uint8List? audioBytesA = LiveInformation().announcementModule.announcementCache[audioNameA]; Uint8List? audioBytesB = LiveInformation().announcementModule.announcementCache[audioNameB]; Uint8List? audioBytesC = LiveInformation().announcementModule.announcementCache[audioNameC]; if (audioBytesA != null) return audioBytesA; if (audioBytesB != null) return audioBytesB; if (audioBytesC != null) return audioBytesC; print("No audio bytes found for $name"); return Uint8List(0); } }