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