hrdf_parser/
models.rs

1use std::{
2    collections::BTreeSet,
3    hash::{DefaultHasher, Hash, Hasher},
4};
5
6use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
7use rustc_hash::FxHashMap;
8use serde::{Deserialize, Serialize};
9use strum_macros::{self, Display, EnumString};
10
11use crate::{
12    storage::DataStorage,
13    utils::{add_1_day, sub_1_day},
14};
15
16// ------------------------------------------------------------------------------------------------
17// --- Model
18// ------------------------------------------------------------------------------------------------
19
20pub trait Model<M: Model<M>> {
21    // Primary key type.
22    type K: Copy + Eq + Hash + Serialize + for<'a> Deserialize<'a>;
23
24    fn id(&self) -> M::K;
25
26    fn vec_to_map(data: Vec<M>) -> FxHashMap<M::K, M> {
27        data.into_iter()
28            .fold(FxHashMap::default(), |mut acc, item| {
29                acc.insert(item.id(), item);
30                acc
31            })
32    }
33}
34
35macro_rules! impl_Model {
36    ($m:ty) => {
37        impl Model<$m> for $m {
38            type K = i32;
39
40            fn id(&self) -> Self::K {
41                self.id
42            }
43        }
44    };
45}
46
47// ------------------------------------------------------------------------------------------------
48// --- Attribute
49// ------------------------------------------------------------------------------------------------
50
51#[derive(Debug, Serialize, Deserialize)]
52pub struct Attribute {
53    id: i32,
54    designation: String,
55    stop_scope: i16,
56    main_sorting_priority: i16,
57    secondary_sorting_priority: i16,
58    description: FxHashMap<Language, String>,
59}
60
61impl_Model!(Attribute);
62
63impl Attribute {
64    pub fn new(
65        id: i32,
66        designation: String,
67        stop_scope: i16,
68        main_sorting_priority: i16,
69        secondary_sorting_priority: i16,
70    ) -> Self {
71        Self {
72            id,
73            designation,
74            stop_scope,
75            main_sorting_priority,
76            secondary_sorting_priority,
77            description: FxHashMap::default(),
78        }
79    }
80
81    // Getters/Setters
82
83    pub fn set_description(&mut self, language: Language, value: &str) {
84        self.description.insert(language, value.to_string());
85    }
86}
87
88// ------------------------------------------------------------------------------------------------
89// --- BitField
90// ------------------------------------------------------------------------------------------------
91
92#[derive(Debug, Serialize, Deserialize)]
93pub struct BitField {
94    id: i32,
95    bits: Vec<u8>,
96}
97
98impl_Model!(BitField);
99
100impl BitField {
101    pub fn new(id: i32, bits: Vec<u8>) -> Self {
102        Self { id, bits }
103    }
104
105    // Getters/Setters
106
107    pub fn bits(&self) -> &Vec<u8> {
108        &self.bits
109    }
110}
111
112// ------------------------------------------------------------------------------------------------
113// --- Color
114// ------------------------------------------------------------------------------------------------
115
116#[derive(Debug, Default, Serialize, Deserialize)]
117pub struct Color {
118    r: i16,
119    g: i16,
120    b: i16,
121}
122
123#[allow(unused)]
124impl Color {
125    pub fn new(r: i16, g: i16, b: i16) -> Self {
126        Self { r, g, b }
127    }
128
129    // Getters/Setters
130
131    pub fn r(&self) -> i16 {
132        self.r
133    }
134
135    pub fn g(&self) -> i16 {
136        self.g
137    }
138
139    pub fn b(&self) -> i16 {
140        self.b
141    }
142}
143
144// ------------------------------------------------------------------------------------------------
145// --- CoordinateSystem
146// ------------------------------------------------------------------------------------------------
147
148#[derive(Clone, Copy, Debug, Default, Display, Eq, Hash, PartialEq, Serialize, Deserialize)]
149pub enum CoordinateSystem {
150    #[default]
151    LV95,
152    WGS84,
153}
154
155// ------------------------------------------------------------------------------------------------
156// --- Coordinates
157// ------------------------------------------------------------------------------------------------
158
159#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
160pub struct Coordinates {
161    coordinate_system: CoordinateSystem,
162    x: f64,
163    y: f64,
164}
165
166#[allow(unused)]
167impl Coordinates {
168    pub fn new(coordinate_system: CoordinateSystem, x: f64, y: f64) -> Self {
169        Self {
170            coordinate_system,
171            x,
172            y,
173        }
174    }
175
176    // Getters/Setters
177
178    pub fn easting(&self) -> f64 {
179        assert!(self.coordinate_system == CoordinateSystem::LV95);
180        self.x
181    }
182
183    pub fn northing(&self) -> f64 {
184        assert!(self.coordinate_system == CoordinateSystem::LV95);
185        self.y
186    }
187
188    pub fn latitude(&self) -> f64 {
189        assert!(self.coordinate_system == CoordinateSystem::WGS84);
190        self.x
191    }
192
193    pub fn longitude(&self) -> f64 {
194        assert!(self.coordinate_system == CoordinateSystem::WGS84);
195        self.y
196    }
197}
198
199// ------------------------------------------------------------------------------------------------
200// --- Direction
201// ------------------------------------------------------------------------------------------------
202
203#[derive(Debug, Serialize, Deserialize)]
204pub struct Direction {
205    id: i32,
206    name: String,
207}
208
209impl_Model!(Direction);
210
211impl Direction {
212    pub fn new(id: i32, name: String) -> Self {
213        Self { id, name }
214    }
215}
216
217// ------------------------------------------------------------------------------------------------
218// --- DirectionType
219// ------------------------------------------------------------------------------------------------
220
221#[derive(
222    Clone, Copy, Debug, Default, Display, Eq, Hash, PartialEq, EnumString, Serialize, Deserialize,
223)]
224pub enum DirectionType {
225    #[default]
226    #[strum(serialize = "R")]
227    Outbound,
228
229    #[strum(serialize = "H")]
230    Return,
231}
232
233// ------------------------------------------------------------------------------------------------
234// --- Holiday
235// ------------------------------------------------------------------------------------------------
236
237#[derive(Debug, Serialize, Deserialize)]
238pub struct Holiday {
239    id: i32,
240    date: NaiveDate,
241    name: FxHashMap<Language, String>,
242}
243
244impl_Model!(Holiday);
245
246impl Holiday {
247    pub fn new(id: i32, date: NaiveDate, name: FxHashMap<Language, String>) -> Self {
248        Self { id, date, name }
249    }
250}
251
252// ------------------------------------------------------------------------------------------------
253// --- ExchangeTimeAdministration
254// ------------------------------------------------------------------------------------------------
255
256#[derive(Debug, Serialize, Deserialize)]
257pub struct ExchangeTimeAdministration {
258    id: i32,
259    stop_id: Option<i32>, // A None value means that the exchange time applies to all stops if there is no specific entry for the stop and the 2 administrations.
260    administration_1: String,
261    administration_2: String,
262    duration: i16, // Exchange time from administration 1 to administration 2 is in minutes.
263}
264
265impl_Model!(ExchangeTimeAdministration);
266
267impl ExchangeTimeAdministration {
268    pub fn new(
269        id: i32,
270        stop_id: Option<i32>,
271        administration_1: String,
272        administration_2: String,
273        duration: i16,
274    ) -> Self {
275        Self {
276            id,
277            stop_id,
278            administration_1,
279            administration_2,
280            duration,
281        }
282    }
283
284    // Getters/Setters
285
286    pub fn stop_id(&self) -> Option<i32> {
287        self.stop_id
288    }
289
290    pub fn administration_1(&self) -> &str {
291        &self.administration_1
292    }
293
294    pub fn administration_2(&self) -> &str {
295        &self.administration_2
296    }
297
298    pub fn duration(&self) -> i16 {
299        self.duration
300    }
301}
302
303// ------------------------------------------------------------------------------------------------
304// --- ExchangeTimeJourney
305// ------------------------------------------------------------------------------------------------
306
307#[derive(Debug, Serialize, Deserialize)]
308pub struct ExchangeTimeJourney {
309    id: i32,
310    stop_id: i32,
311    journey_id_1: i32,
312    journey_id_2: i32,
313    duration: i16, // Exchange time from journey 1 to journey 2 is in minutes.
314    is_guaranteed: bool,
315    bit_field_id: Option<i32>,
316}
317
318impl_Model!(ExchangeTimeJourney);
319
320impl ExchangeTimeJourney {
321    pub fn new(
322        id: i32,
323        stop_id: i32,
324        journey_id_1: i32,
325        journey_id_2: i32,
326        duration: i16,
327        is_guaranteed: bool,
328        bit_field_id: Option<i32>,
329    ) -> Self {
330        Self {
331            id,
332            stop_id,
333            journey_id_1,
334            journey_id_2,
335            duration,
336            is_guaranteed,
337            bit_field_id,
338        }
339    }
340
341    // Getters/Setters
342
343    pub fn stop_id(&self) -> i32 {
344        self.stop_id
345    }
346
347    pub fn journey_id_1(&self) -> i32 {
348        self.journey_id_1
349    }
350
351    pub fn journey_id_2(&self) -> i32 {
352        self.journey_id_2
353    }
354
355    pub fn duration(&self) -> i16 {
356        self.duration
357    }
358
359    pub fn bit_field_id(&self) -> Option<i32> {
360        self.bit_field_id
361    }
362}
363
364// ------------------------------------------------------------------------------------------------
365// --- ExchangeTimeLine
366// ------------------------------------------------------------------------------------------------
367
368#[derive(Debug, Serialize, Deserialize)]
369pub struct ExchangeTimeLine {
370    id: i32,
371    stop_id: Option<i32>,
372    line_1: LineInfo,
373    line_2: LineInfo,
374    duration: i16, // Exchange time from line 1 to line 2 is in minutes.
375    is_guaranteed: bool,
376}
377
378impl_Model!(ExchangeTimeLine);
379
380#[derive(Debug, Serialize, Deserialize)]
381pub(crate) struct LineInfo {
382    administration: String,
383    transport_type_id: i32,
384    line_id: Option<String>,
385    direction: Option<DirectionType>,
386}
387
388impl LineInfo {
389    pub(crate) fn new(
390        administration: String,
391        transport_type_id: i32,
392        line_id: Option<String>,
393        direction: Option<DirectionType>,
394    ) -> Self {
395        Self {
396            administration,
397            transport_type_id,
398            line_id,
399            direction,
400        }
401    }
402}
403
404impl ExchangeTimeLine {
405    pub(crate) fn new(
406        id: i32,
407        stop_id: Option<i32>,
408        line_1: LineInfo,
409        line_2: LineInfo,
410        duration: i16,
411        is_guaranteed: bool,
412    ) -> Self {
413        Self {
414            id,
415            stop_id,
416            line_1,
417            line_2,
418            duration,
419            is_guaranteed,
420        }
421    }
422}
423
424// ------------------------------------------------------------------------------------------------
425// --- InformationText
426// ------------------------------------------------------------------------------------------------
427
428#[derive(Debug, Serialize, Deserialize)]
429pub struct InformationText {
430    id: i32,
431    content: FxHashMap<Language, String>,
432}
433
434impl_Model!(InformationText);
435
436impl InformationText {
437    pub fn new(id: i32) -> Self {
438        Self {
439            id,
440            content: FxHashMap::default(),
441        }
442    }
443
444    // Getters/Setters
445
446    pub fn set_content(&mut self, language: Language, value: &str) {
447        self.content.insert(language, value.to_string());
448    }
449}
450
451// ------------------------------------------------------------------------------------------------
452// --- Journey
453// ------------------------------------------------------------------------------------------------
454
455#[derive(Debug, Default, Serialize, Deserialize)]
456pub struct Journey {
457    id: i32,
458    administration: String,
459    metadata: FxHashMap<JourneyMetadataType, Vec<JourneyMetadataEntry>>,
460    route: Vec<JourneyRouteEntry>,
461}
462
463impl_Model!(Journey);
464
465impl Journey {
466    pub fn new(id: i32, administration: String) -> Self {
467        Self {
468            id,
469            administration,
470            metadata: FxHashMap::default(),
471            route: Vec::new(),
472        }
473    }
474
475    // Getters/Setters
476
477    pub fn administration(&self) -> &str {
478        &self.administration
479    }
480
481    fn metadata(&self) -> &FxHashMap<JourneyMetadataType, Vec<JourneyMetadataEntry>> {
482        &self.metadata
483    }
484
485    pub fn route(&self) -> &Vec<JourneyRouteEntry> {
486        &self.route
487    }
488
489    // Functions
490
491    pub fn add_metadata_entry(&mut self, k: JourneyMetadataType, v: JourneyMetadataEntry) {
492        self.metadata.entry(k).or_default().push(v);
493    }
494
495    pub fn add_route_entry(&mut self, entry: JourneyRouteEntry) {
496        self.route.push(entry);
497    }
498
499    pub fn bit_field_id(&self) -> Option<i32> {
500        // unwrap: There will always be a BitField entry.
501        let entry = &self.metadata().get(&JourneyMetadataType::BitField).unwrap()[0];
502        entry.bit_field_id
503    }
504
505    pub fn transport_type_id(&self) -> i32 {
506        // unwrap: There will always be a TransportType entry.
507        let entry = &self
508            .metadata()
509            .get(&JourneyMetadataType::TransportType)
510            .unwrap()[0];
511        // unwrap: It's guaranteed to have value here.
512        entry.resource_id.unwrap()
513    }
514
515    pub fn transport_type<'a>(&'a self, data_storage: &'a DataStorage) -> &TransportType {
516        data_storage
517            .transport_types()
518            .find(self.transport_type_id())
519            .unwrap_or_else(|| panic!("Transport type {:?} not found.", self.transport_type_id()))
520    }
521
522    pub fn first_stop_id(&self) -> i32 {
523        // unwrap: The route always contains at least 2 entries.
524        self.route.first().unwrap().stop_id()
525    }
526
527    pub fn last_stop_id(&self) -> i32 {
528        // unwrap: The route always contains at least 2 entries.
529        self.route.last().unwrap().stop_id()
530    }
531
532    pub fn is_last_stop(&self, stop_id: i32, ignore_loop: bool) -> bool {
533        if ignore_loop && self.first_stop_id() == self.last_stop_id() {
534            false
535        } else {
536            stop_id == self.last_stop_id()
537        }
538    }
539
540    pub fn count_stops(&self, departure_stop_id: i32, arrival_stop_id: i32) -> usize {
541        self.route()
542            .iter()
543            .skip_while(|stop| stop.stop_id() != departure_stop_id)
544            .take_while(|stop| stop.stop_id() != arrival_stop_id)
545            .count()
546            + 1
547    }
548
549    pub fn hash_route(&self, departure_stop_id: i32) -> Option<u64> {
550        let index = self
551            .route
552            .iter()
553            .position(|route_entry| route_entry.stop_id() == departure_stop_id)?;
554
555        let mut hasher = DefaultHasher::new();
556        self.route
557            .iter()
558            .skip(index)
559            .map(|route_entry| route_entry.stop_id())
560            .collect::<BTreeSet<_>>()
561            .hash(&mut hasher);
562        Some(hasher.finish())
563    }
564
565    /// unwrap: Do not call this function if the stop is not part of the route.
566    /// unwrap: Do not call this function if the stop has no departure time (only the last stop has no departure time).
567    pub fn departure_time_of(&self, stop_id: i32) -> (NaiveTime, bool) {
568        let route = self.route();
569        let index = route
570            .iter()
571            .position(|route_entry| route_entry.stop_id() == stop_id)
572            .unwrap();
573        let departure_time = route[index].departure_time().unwrap();
574
575        (
576            departure_time,
577            // The departure time is on the next day if this evaluates to true.
578            departure_time < route.first().unwrap().departure_time().unwrap(),
579        )
580    }
581
582    /// The date must correspond to the route's first entry.
583    /// Do not call this function if the stop is not part of the route.
584    /// Do not call this function if the stop has no departure time (only the last stop has no departure time).
585    pub fn departure_at_of(&self, stop_id: i32, date: NaiveDate) -> NaiveDateTime {
586        match self.departure_time_of(stop_id) {
587            (departure_time, false) => NaiveDateTime::new(date, departure_time),
588            (departure_time, true) => NaiveDateTime::new(add_1_day(date), departure_time),
589        }
590    }
591
592    /// The date must be associated with the origin_stop_id.
593    /// Do not call this function if the stop is not part of the route.
594    pub fn departure_at_of_with_origin(
595        &self,
596        stop_id: i32,
597        date: NaiveDate,
598        // If it's not a departure date, it's an arrival date.
599        is_departure_date: bool,
600        origin_stop_id: i32,
601    ) -> NaiveDateTime {
602        let (departure_time, is_next_day) = self.departure_time_of(stop_id);
603        let (_, origin_is_next_day) = if is_departure_date {
604            self.departure_time_of(origin_stop_id)
605        } else {
606            self.arrival_time_of(origin_stop_id)
607        };
608
609        match (is_next_day, origin_is_next_day) {
610            (true, false) => NaiveDateTime::new(add_1_day(date), departure_time),
611            (false, true) => NaiveDateTime::new(sub_1_day(date), departure_time),
612            _ => NaiveDateTime::new(date, departure_time),
613        }
614    }
615
616    /// unwrap: Do not call this function if the stop is not part of the route.
617    /// unwrap: Do not call this function if the stop has no arrival time (only the first stop has no arrival time).
618    pub fn arrival_time_of(&self, stop_id: i32) -> (NaiveTime, bool) {
619        let route = self.route();
620        let index = route
621            .iter()
622            // The first route entry has no arrival time.
623            .skip(1)
624            .position(|route_entry| route_entry.stop_id() == stop_id)
625            .map(|i| i + 1)
626            .unwrap();
627        let arrival_time = route[index].arrival_time().unwrap();
628
629        (
630            arrival_time,
631            // The arrival time is on the next day if this evaluates to true.
632            arrival_time < route.first().unwrap().departure_time().unwrap(),
633        )
634    }
635
636    /// The date must be associated with the origin_stop_id.
637    pub fn arrival_at_of_with_origin(
638        &self,
639        stop_id: i32,
640        date: NaiveDate,
641        // If it's not a departure date, it's an arrival date.
642        is_departure_date: bool,
643        origin_stop_id: i32,
644    ) -> NaiveDateTime {
645        let (arrival_time, is_next_day) = self.arrival_time_of(stop_id);
646        let (_, origin_is_next_day) = if is_departure_date {
647            self.departure_time_of(origin_stop_id)
648        } else {
649            self.arrival_time_of(origin_stop_id)
650        };
651
652        match (is_next_day, origin_is_next_day) {
653            (true, false) => NaiveDateTime::new(add_1_day(date), arrival_time),
654            (false, true) => NaiveDateTime::new(sub_1_day(date), arrival_time),
655            _ => NaiveDateTime::new(date, arrival_time),
656        }
657    }
658
659    /// Excluding departure stop.
660    pub fn route_section(
661        &self,
662        departure_stop_id: i32,
663        arrival_stop_id: i32,
664    ) -> Vec<&JourneyRouteEntry> {
665        let mut route_iter = self.route().iter();
666
667        for route_entry in route_iter.by_ref() {
668            if route_entry.stop_id() == departure_stop_id {
669                break;
670            }
671        }
672
673        let mut result = Vec::new();
674
675        for route_entry in route_iter {
676            result.push(route_entry);
677
678            if route_entry.stop_id() == arrival_stop_id {
679                break;
680            }
681        }
682
683        result
684    }
685}
686
687// ------------------------------------------------------------------------------------------------
688// --- JourneyMetadataType
689// ------------------------------------------------------------------------------------------------
690
691#[derive(Clone, Copy, Debug, Default, Display, Eq, Hash, PartialEq, Serialize, Deserialize)]
692pub enum JourneyMetadataType {
693    #[default]
694    Attribute,
695    BitField,
696    Direction,
697    InformationText,
698    Line,
699    ExchangeTimeBoarding,
700    ExchangeTimeDisembarking,
701    TransportType,
702}
703
704// ------------------------------------------------------------------------------------------------
705// --- JourneyMetadataEntry
706// ------------------------------------------------------------------------------------------------
707
708#[derive(Debug, Serialize, Deserialize)]
709pub struct JourneyMetadataEntry {
710    from_stop_id: Option<i32>,
711    until_stop_id: Option<i32>,
712    resource_id: Option<i32>,
713    bit_field_id: Option<i32>,
714    departure_time: Option<NaiveTime>,
715    arrival_time: Option<NaiveTime>,
716    extra_field_1: Option<String>,
717    extra_field_2: Option<i32>,
718}
719
720impl JourneyMetadataEntry {
721    #[allow(clippy::too_many_arguments)]
722    pub fn new(
723        from_stop_id: Option<i32>,
724        until_stop_id: Option<i32>,
725        resource_id: Option<i32>,
726        bit_field_id: Option<i32>,
727        departure_time: Option<NaiveTime>,
728        arrival_time: Option<NaiveTime>,
729        extra_field_1: Option<String>,
730        extra_field_2: Option<i32>,
731    ) -> Self {
732        Self {
733            from_stop_id,
734            until_stop_id,
735            resource_id,
736            bit_field_id,
737            departure_time,
738            arrival_time,
739            extra_field_1,
740            extra_field_2,
741        }
742    }
743}
744
745// ------------------------------------------------------------------------------------------------
746// --- JourneyRouteEntry
747// ------------------------------------------------------------------------------------------------
748
749#[derive(Debug, Serialize, Deserialize)]
750pub struct JourneyRouteEntry {
751    stop_id: i32,
752    arrival_time: Option<NaiveTime>,
753    departure_time: Option<NaiveTime>,
754}
755
756impl JourneyRouteEntry {
757    pub fn new(
758        stop_id: i32,
759        arrival_time: Option<NaiveTime>,
760        departure_time: Option<NaiveTime>,
761    ) -> Self {
762        Self {
763            stop_id,
764            arrival_time,
765            departure_time,
766        }
767    }
768
769    // Getters/Setters
770
771    pub fn stop_id(&self) -> i32 {
772        self.stop_id
773    }
774
775    pub fn arrival_time(&self) -> &Option<NaiveTime> {
776        &self.arrival_time
777    }
778
779    pub fn departure_time(&self) -> &Option<NaiveTime> {
780        &self.departure_time
781    }
782
783    // Functions
784
785    pub fn stop<'a>(&'a self, data_storage: &'a DataStorage) -> &Stop {
786        data_storage
787            .stops()
788            .find(self.stop_id())
789            .unwrap_or_else(|| panic!("Stop {:?} not found.", self.stop_id()))
790    }
791}
792
793// ------------------------------------------------------------------------------------------------
794// --- JourneyPlatform
795// ------------------------------------------------------------------------------------------------
796
797#[derive(Debug, Serialize, Deserialize)]
798pub struct JourneyPlatform {
799    journey_id: i32,
800    platform_id: i32,
801    time: Option<NaiveTime>,
802    bit_field_id: Option<i32>,
803}
804
805impl JourneyPlatform {
806    pub fn new(
807        journey_id: i32,
808        platform_id: i32,
809        time: Option<NaiveTime>,
810        bit_field_id: Option<i32>,
811    ) -> Self {
812        Self {
813            journey_id,
814            platform_id,
815            time,
816            bit_field_id,
817        }
818    }
819}
820
821impl Model<JourneyPlatform> for JourneyPlatform {
822    type K = (i32, i32);
823
824    fn id(&self) -> Self::K {
825        (self.journey_id, self.platform_id)
826    }
827}
828
829// ------------------------------------------------------------------------------------------------
830// --- Language
831// ------------------------------------------------------------------------------------------------
832
833#[derive(
834    Clone, Copy, Debug, Default, Display, Eq, Hash, PartialEq, EnumString, Serialize, Deserialize,
835)]
836pub enum Language {
837    #[default]
838    #[strum(serialize = "deu")]
839    German,
840
841    #[strum(serialize = "fra")]
842    French,
843
844    #[strum(serialize = "ita")]
845    Italian,
846
847    #[strum(serialize = "eng")]
848    English,
849}
850
851// ------------------------------------------------------------------------------------------------
852// --- Line
853// ------------------------------------------------------------------------------------------------
854
855#[derive(Debug, Default, Serialize, Deserialize)]
856pub struct Line {
857    id: i32,
858    name: String,
859    short_name: String,
860    text_color: Color,
861    background_color: Color,
862}
863
864impl_Model!(Line);
865
866impl Line {
867    pub fn new(id: i32, name: String) -> Self {
868        Self {
869            id,
870            name,
871            short_name: String::default(),
872            text_color: Color::default(),
873            background_color: Color::default(),
874        }
875    }
876
877    // Getters/Setters
878
879    pub fn set_short_name(&mut self, value: String) {
880        self.short_name = value;
881    }
882
883    pub fn set_text_color(&mut self, value: Color) {
884        self.text_color = value;
885    }
886
887    pub fn set_background_color(&mut self, value: Color) {
888        self.background_color = value;
889    }
890}
891
892// ------------------------------------------------------------------------------------------------
893// --- Platform
894// ------------------------------------------------------------------------------------------------
895
896#[derive(Debug, Serialize, Deserialize)]
897pub struct Platform {
898    id: i32,
899    name: String,
900    sectors: Option<String>,
901    stop_id: i32,
902    sloid: String,
903    lv95_coordinates: Coordinates,
904    wgs84_coordinates: Coordinates,
905}
906
907impl_Model!(Platform);
908
909impl Platform {
910    pub fn new(id: i32, name: String, sectors: Option<String>, stop_id: i32) -> Self {
911        Self {
912            id,
913            name,
914            sectors,
915            stop_id,
916            sloid: String::default(),
917            lv95_coordinates: Coordinates::default(),
918            wgs84_coordinates: Coordinates::default(),
919        }
920    }
921
922    // Getters/Setters
923
924    pub fn set_sloid(&mut self, value: String) {
925        self.sloid = value;
926    }
927
928    pub fn set_lv95_coordinates(&mut self, value: Coordinates) {
929        self.lv95_coordinates = value;
930    }
931
932    pub fn set_wgs84_coordinates(&mut self, value: Coordinates) {
933        self.wgs84_coordinates = value;
934    }
935}
936
937// ------------------------------------------------------------------------------------------------
938// --- Stop
939// ------------------------------------------------------------------------------------------------
940
941#[derive(Debug, Serialize, Deserialize)]
942pub struct Stop {
943    id: i32,
944    name: String,
945    long_name: Option<String>,
946    abbreviation: Option<String>,
947    synonyms: Option<Vec<String>>,
948    lv95_coordinates: Option<Coordinates>,
949    wgs84_coordinates: Option<Coordinates>,
950    exchange_priority: i16,
951    exchange_flag: i16,
952    exchange_time: Option<(i16, i16)>, // (InterCity exchange time, Exchange time for all other journey types)
953    restrictions: i16,
954    sloid: String,
955    boarding_areas: Vec<String>,
956}
957
958impl_Model!(Stop);
959
960impl Stop {
961    pub fn new(
962        id: i32,
963        name: String,
964        long_name: Option<String>,
965        abbreviation: Option<String>,
966        synonyms: Option<Vec<String>>,
967    ) -> Self {
968        Self {
969            id,
970            name,
971            long_name,
972            abbreviation,
973            synonyms,
974            lv95_coordinates: None,
975            wgs84_coordinates: None,
976            exchange_priority: 8, // 8 is the default priority.
977            exchange_flag: 0,
978            exchange_time: None,
979            restrictions: 0,
980            sloid: String::default(),
981            boarding_areas: Vec::new(),
982        }
983    }
984
985    // Getters/Setters
986
987    pub fn name(&self) -> &str {
988        &self.name
989    }
990
991    pub fn lv95_coordinates(&self) -> Option<Coordinates> {
992        self.lv95_coordinates
993    }
994
995    pub fn set_lv95_coordinates(&mut self, value: Coordinates) {
996        self.lv95_coordinates = Some(value);
997    }
998
999    pub fn wgs84_coordinates(&self) -> Option<Coordinates> {
1000        self.wgs84_coordinates
1001    }
1002
1003    pub fn set_wgs84_coordinates(&mut self, value: Coordinates) {
1004        self.wgs84_coordinates = Some(value);
1005    }
1006
1007    pub fn set_exchange_priority(&mut self, value: i16) {
1008        self.exchange_priority = value;
1009    }
1010
1011    pub fn exchange_flag(&self) -> i16 {
1012        self.exchange_flag
1013    }
1014
1015    pub fn set_exchange_flag(&mut self, value: i16) {
1016        self.exchange_flag = value;
1017    }
1018
1019    pub fn exchange_time(&self) -> Option<(i16, i16)> {
1020        self.exchange_time
1021    }
1022
1023    pub fn set_exchange_time(&mut self, value: Option<(i16, i16)>) {
1024        self.exchange_time = value;
1025    }
1026
1027    pub fn set_restrictions(&mut self, value: i16) {
1028        self.restrictions = value;
1029    }
1030
1031    pub fn set_sloid(&mut self, value: String) {
1032        self.sloid = value;
1033    }
1034
1035    // Functions
1036
1037    pub fn add_boarding_area(&mut self, value: String) {
1038        self.boarding_areas.push(value);
1039    }
1040
1041    pub fn can_be_used_as_exchange_point(&self) -> bool {
1042        self.exchange_flag() != 0
1043    }
1044}
1045
1046// ------------------------------------------------------------------------------------------------
1047// --- StopConnection
1048// ------------------------------------------------------------------------------------------------
1049
1050#[derive(Debug, Default, Serialize, Deserialize)]
1051pub struct StopConnection {
1052    id: i32,
1053    stop_id_1: i32,
1054    stop_id_2: i32,
1055    duration: i16, // Exchange time from stop 1 to stop 2 is in minutes.
1056    attribute: i32,
1057}
1058
1059impl_Model!(StopConnection);
1060
1061impl StopConnection {
1062    pub fn new(id: i32, stop_id_1: i32, stop_id_2: i32, duration: i16) -> Self {
1063        Self {
1064            id,
1065            stop_id_1,
1066            stop_id_2,
1067            duration,
1068            attribute: 0,
1069        }
1070    }
1071
1072    // Getters/Setters
1073
1074    pub fn stop_id_1(&self) -> i32 {
1075        self.stop_id_1
1076    }
1077
1078    pub fn stop_id_2(&self) -> i32 {
1079        self.stop_id_2
1080    }
1081
1082    pub fn duration(&self) -> i16 {
1083        self.duration
1084    }
1085
1086    pub fn set_attribute(&mut self, value: i32) {
1087        self.attribute = value;
1088    }
1089}
1090
1091// ------------------------------------------------------------------------------------------------
1092// --- ThroughService
1093// ------------------------------------------------------------------------------------------------
1094
1095#[derive(Debug, Serialize, Deserialize)]
1096pub struct ThroughService {
1097    id: i32,
1098    journey_1_id: i32,
1099    journey_1_stop_id: i32, // Last stop of journey 1.
1100    journey_2_id: i32,
1101    journey_2_stop_id: Option<i32>, // First stop of journey 2.
1102    bit_field_id: i32,
1103}
1104
1105impl_Model!(ThroughService);
1106
1107impl ThroughService {
1108    pub fn new(
1109        id: i32,
1110        journey_1_id: i32,
1111        journey_1_stop_id: i32,
1112        journey_2_id: i32,
1113        journey_2_stop_id: Option<i32>,
1114        bit_field_id: i32,
1115    ) -> Self {
1116        Self {
1117            id,
1118            journey_1_id,
1119            journey_1_stop_id,
1120            journey_2_id,
1121            journey_2_stop_id,
1122            bit_field_id,
1123        }
1124    }
1125}
1126
1127// ------------------------------------------------------------------------------------------------
1128// --- TimetableMetadataEntry
1129// ------------------------------------------------------------------------------------------------
1130
1131#[derive(Debug, Serialize, Deserialize)]
1132pub struct TimetableMetadataEntry {
1133    id: i32,
1134    key: String,
1135    value: String,
1136}
1137
1138impl_Model!(TimetableMetadataEntry);
1139
1140impl TimetableMetadataEntry {
1141    pub fn new(id: i32, key: String, value: String) -> Self {
1142        Self { id, key, value }
1143    }
1144
1145    // Getters/Setters
1146
1147    pub fn key(&self) -> &str {
1148        &self.key
1149    }
1150
1151    pub fn value(&self) -> &str {
1152        &self.value
1153    }
1154
1155    /// unwrap: Do not call this function if the value is not a date.
1156    #[allow(non_snake_case)]
1157    pub fn value_as_NaiveDate(&self) -> NaiveDate {
1158        NaiveDate::parse_from_str(self.value(), "%Y-%m-%d").unwrap()
1159    }
1160}
1161
1162// ------------------------------------------------------------------------------------------------
1163// --- TransportCompany
1164// ------------------------------------------------------------------------------------------------
1165
1166#[derive(Debug, Serialize, Deserialize)]
1167pub struct TransportCompany {
1168    id: i32,
1169    short_name: FxHashMap<Language, String>,
1170    long_name: FxHashMap<Language, String>,
1171    full_name: FxHashMap<Language, String>,
1172    administrations: Vec<String>,
1173}
1174
1175impl_Model!(TransportCompany);
1176
1177impl TransportCompany {
1178    pub fn new(id: i32, administrations: Vec<String>) -> Self {
1179        Self {
1180            id,
1181            short_name: FxHashMap::default(),
1182            long_name: FxHashMap::default(),
1183            full_name: FxHashMap::default(),
1184            administrations,
1185        }
1186    }
1187
1188    // Getters/Setters
1189
1190    pub fn set_short_name(&mut self, language: Language, value: &str) {
1191        self.short_name.insert(language, value.to_string());
1192    }
1193
1194    pub fn set_long_name(&mut self, language: Language, value: &str) {
1195        self.long_name.insert(language, value.to_string());
1196    }
1197
1198    pub fn set_full_name(&mut self, language: Language, value: &str) {
1199        self.full_name.insert(language, value.to_string());
1200    }
1201}
1202
1203// ------------------------------------------------------------------------------------------------
1204// --- TransportType
1205// ------------------------------------------------------------------------------------------------
1206
1207#[derive(Debug, Default, Serialize, Deserialize)]
1208pub struct TransportType {
1209    id: i32,
1210    designation: String,
1211    product_class_id: i16,
1212    tarrif_group: String,
1213    output_control: i16,
1214    short_name: String,
1215    surchage: i16,
1216    flag: String,
1217    product_class_name: FxHashMap<Language, String>,
1218    category_name: FxHashMap<Language, String>,
1219}
1220
1221impl_Model!(TransportType);
1222
1223impl TransportType {
1224    #[allow(clippy::too_many_arguments)]
1225    pub fn new(
1226        id: i32,
1227        designation: String,
1228        product_class_id: i16,
1229        tarrif_group: String,
1230        output_control: i16,
1231        short_name: String,
1232        surchage: i16,
1233        flag: String,
1234    ) -> Self {
1235        Self {
1236            id,
1237            designation,
1238            product_class_id,
1239            tarrif_group,
1240            output_control,
1241            short_name,
1242            surchage,
1243            flag,
1244            product_class_name: FxHashMap::default(),
1245            category_name: FxHashMap::default(),
1246        }
1247    }
1248
1249    // Getters/Setters
1250
1251    pub fn designation(&self) -> &str {
1252        &self.designation
1253    }
1254
1255    pub fn product_class_id(&self) -> i16 {
1256        self.product_class_id
1257    }
1258
1259    pub fn set_product_class_name(&mut self, language: Language, value: &str) {
1260        self.product_class_name.insert(language, value.to_string());
1261    }
1262
1263    pub fn set_category_name(&mut self, language: Language, value: &str) {
1264        self.category_name.insert(language, value.to_string());
1265    }
1266}
1267
1268// ------------------------------------------------------------------------------------------------
1269// --- Version
1270// ------------------------------------------------------------------------------------------------
1271
1272#[derive(Clone, Copy, Debug, Display, Eq, Hash, PartialEq, Serialize, Deserialize)]
1273#[allow(non_camel_case_types)]
1274pub enum Version {
1275    V_5_40_41_2_0_4,
1276    V_5_40_41_2_0_5,
1277}