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