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