1use std::{collections::HashMap, io::Cursor};
2
3use bevy::prelude::*;
4use egui::Pos2;
5use moonshine_core::kind::{InsertInstance, Instance};
6
7use crate::{
8 graph::{Graph, Station},
9 units::time::TimetableTime,
10 vehicles::{
11 Vehicle,
12 entries::{TimetableEntry, TravelMode, VehicleSchedule},
13 vehicle_set::VehicleSet,
14 },
15};
16
17#[derive(Event, Deref)]
18pub struct GtfsLoaded(pub Vec<u8>);
19
20pub fn load_gtfs_static(data: On<GtfsLoaded>, mut commands: Commands, mut graph: ResMut<Graph>) {
21 let reader = Cursor::new(data.as_slice());
22 let Ok(gtfs) = gtfs_structures::Gtfs::from_reader(reader) else {
23 return;
24 };
25 let mut station_map: HashMap<String, Instance<Station>> =
26 HashMap::with_capacity(gtfs.stops.len());
27 for (_, stop) in gtfs.stops.iter() {
28 let longitude = stop.longitude.unwrap_or_default();
29 let latitude = stop.latitude.unwrap_or_default();
30 let name = stop.name.as_ref().unwrap_or(&stop.id);
31 let (northing, easting, _) = utm::to_utm_wgs84_no_zone(latitude, longitude);
32 let station_instance = commands
33 .spawn((Name::new(name.clone()),))
34 .insert_instance(Station(Pos2 {
35 x: easting as f32,
36 y: -northing as f32,
37 }))
38 .instance();
39 graph.add_node(station_instance);
40 station_map.insert(stop.id.clone(), station_instance);
41 }
42 let vehicle_set_entity = commands
43 .spawn((Name::new("New GTFS Import"), VehicleSet))
44 .id();
45 for (_, trip) in gtfs.trips.into_iter() {
46 let vehicle_entity = commands
47 .spawn(Name::new(trip.route_id))
48 .insert_instance(Vehicle)
49 .id();
50 commands
51 .entity(vehicle_set_entity)
52 .add_child(vehicle_entity);
53 let mut schedule_entities = Vec::new();
54 for stop_time in trip.stop_times {
55 let arrival = stop_time.arrival_time.map_or(TravelMode::Flexible, |t| {
56 TravelMode::At(TimetableTime(t as i32))
57 });
58 let departure = Some(stop_time.departure_time.map_or(TravelMode::Flexible, |t| {
59 TravelMode::At(TimetableTime(t as i32))
60 }));
61 let Some(station_instance) = station_map.get(&stop_time.stop.id) else {
62 continue;
63 };
64 let entry_entity = commands
65 .spawn(TimetableEntry {
66 station: station_instance.entity(),
67 arrival,
68 departure,
69 service: None,
70 track: None,
71 })
72 .id();
73 commands.entity(vehicle_entity).add_child(entry_entity);
74 schedule_entities.push(entry_entity);
75 }
76 commands.entity(vehicle_entity).insert(VehicleSchedule {
77 entities: schedule_entities,
78 ..Default::default()
79 });
80 }
81}