1use crate::graph::Interval;
2use crate::units::distance::Distance;
3use crate::{graph::Station, units::time::TimetableTime};
4use bevy::ecs::entity::{EntityMapper, MapEntities};
5use bevy::prelude::*;
6use moonshine_core::kind::{Instance, SpawnInstance};
7use moonshine_core::save::prelude::*;
8
9pub type DisplayedLineType = Vec<(Instance<Station>, f32)>;
14
15pub type RulerLineType = Vec<(Instance<Station>, TimetableTime)>;
16
17#[derive(Reflect, Debug, Default)]
18pub enum ScaleMode {
19 Linear,
20 #[default]
21 Logarithmic,
22 Uniform,
23}
24
25#[derive(Reflect, Component, Debug)]
27#[component(map_entities)]
28#[reflect(Component, MapEntities)]
29#[require(Name, Save)]
30pub struct DisplayedLine {
31 pub stations: Vec<(Instance<Station>, f32)>,
32 pub scale_mode: ScaleMode,
33}
34
35impl MapEntities for DisplayedLine {
36 fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
37 for (station, _) in &mut self.stations {
38 station.map_entities(entity_mapper);
39 }
40 }
41}
42
43pub enum DisplayedLineError {
44 InvalidIndex,
45 SameStationAsNeighbor,
46 AdjacentIntervals((Entity, Entity)),
47}
48
49impl std::fmt::Debug for DisplayedLineError {
50 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51 match self {
52 DisplayedLineError::InvalidIndex => write!(f, "Invalid index for inserting station"),
53 DisplayedLineError::SameStationAsNeighbor => {
54 write!(f, "Cannot insert the same station as a neighbor")
55 }
56 DisplayedLineError::AdjacentIntervals((e1, e2)) => {
57 write!(
58 f,
59 "Cannot insert station that would create adjacent identical intervals: ({:?}, {:?})",
60 e1, e2
61 )
62 }
63 }
64 }
65}
66
67impl DisplayedLine {
68 pub fn new(stations: DisplayedLineType) -> Self {
69 Self {
70 stations,
71 scale_mode: ScaleMode::default(),
72 }
73 }
74 pub fn _new(stations: impl Iterator<Item = Entity>) -> Self {
75 todo!("implement this stuff")
76 }
77 pub fn stations(&self) -> &DisplayedLineType {
78 &self.stations
79 }
80 pub unsafe fn stations_mut(&mut self) -> &mut DisplayedLineType {
81 &mut self.stations
82 }
83 pub fn insert(
84 &mut self,
85 index: usize,
86 (station, height): (Instance<Station>, f32),
87 ) -> Result<(), DisplayedLineError> {
88 if index > self.stations.len() {
91 return Err(DisplayedLineError::InvalidIndex);
92 };
93 let prev_prev = if index >= 2 {
94 Some(self.stations[index - 2].0)
95 } else {
96 None
97 };
98 let prev = if index >= 1 {
99 Some(self.stations[index - 1].0)
100 } else {
101 None
102 };
103 let next = self.stations.get(index).map(|(e, _)| *e);
104 let next_next = self.stations.get(index + 1).map(|(e, _)| *e);
105 if let Some(prev_prev) = prev_prev
106 && prev_prev == station
107 {
108 return Err(DisplayedLineError::AdjacentIntervals((
109 prev_prev.entity(),
110 prev.unwrap().entity(),
111 )));
112 };
113 if let Some(next_next) = next_next
114 && next_next == station
115 {
116 return Err(DisplayedLineError::AdjacentIntervals((
117 next.unwrap().entity(),
118 next_next.entity(),
119 )));
120 };
121 if let Some(prev) = prev
122 && prev == station
123 {
124 return Err(DisplayedLineError::SameStationAsNeighbor);
125 };
126 if let Some(next) = next
127 && next == station
128 {
129 return Err(DisplayedLineError::SameStationAsNeighbor);
130 };
131 self.stations.insert(index, (station, height));
132 Ok(())
133 }
134 pub fn push(&mut self, station: (Instance<Station>, f32)) -> Result<(), DisplayedLineError> {
135 self.insert(self.stations.len(), station)
136 }
137}
138
139pub fn adjust_intervals_length(
140 In(entity): In<Entity>,
141 graph: Res<crate::graph::Graph>,
142 intervals: Query<&Interval>,
143 mut displayed_lines: Query<&mut DisplayedLine>,
144 names: Query<&Name>,
145) {
146 let mut displayed_line = match displayed_lines.get_mut(entity) {
147 Ok(l) => l,
148 Err(e) => {
149 error!("Could not get displayed line: {:?}", e);
150 return;
151 }
152 };
153 let mut stations_iter = displayed_line.stations.iter_mut();
154 let Some((prev, _)) = stations_iter.next() else {
155 warn!(
156 "Displayed line {} is empty, skipping...",
157 names.get(entity).map_or("<unknown>", Name::as_str)
158 );
159 return;
160 };
161 let mut prev = *prev;
162 for (curr, height) in stations_iter {
163 let (count, acc) = graph
164 .edges_connecting(prev, *curr)
165 .filter_map(|r| intervals.get(r.weight.entity()).ok())
166 .fold((0i32, Distance(0)), |(count, len), i| {
167 (count + 1, len + i.length)
168 });
169 if count == 0 {
170 warn!(
171 "There are no intervals connecting between {} and {}, skipping",
172 names.get(prev.entity()).map_or("<unknown>", Name::as_str),
173 names.get(curr.entity()).map_or("<unknown>", Name::as_str)
174 );
175 continue;
176 }
177 let average_length = acc / count;
178 *height = average_length.0 as f32;
179 prev = *curr;
180 }
181}
182
183pub fn create_intervals_from_displayed_line(
184 In(line_entity): In<Entity>,
185 displayed_lines: Query<&DisplayedLine>,
186 mut graph: ResMut<crate::graph::Graph>,
187 mut commands: Commands,
188 stations: Query<&Station>,
189) {
190 let line = match displayed_lines.get(line_entity) {
191 Ok(l) => l,
192 Err(e) => {
193 error!("Could not find displayed line: {:?}", e);
194 return;
195 }
196 };
197 for w in line.stations.windows(2) {
199 let [(prev, _), (curr, _)] = w else {
200 unreachable!()
201 };
202 let length = {
203 let Ok(p) = stations.get(prev.entity()) else {
204 return;
205 };
206 let Ok(c) = stations.get(curr.entity()) else {
207 return;
208 };
209 Distance(p.0.distance(c.0) as i32)
210 };
211 if !graph.contains_edge(*prev, *curr) {
212 let i1 = commands
213 .spawn_instance(Interval {
214 length,
215 speed_limit: None,
216 })
217 .instance();
218 graph.add_edge(*prev, *curr, i1);
219 }
220 if !graph.contains_edge(*curr, *prev) {
221 let i2 = commands
222 .spawn_instance(Interval {
223 length,
224 speed_limit: None,
225 })
226 .instance();
227 graph.add_edge(*curr, *prev, i2);
228 }
229 }
230}
231
232#[derive(Component, Debug)]
233#[require(Name)]
234pub struct RulerLine(pub RulerLineType);
235
236pub struct LinesPlugin;
237
238impl Plugin for LinesPlugin {
239 fn build(&self, app: &mut App) {}
240}