thisweek_core/
calendar.rs

1use crate::config;
2use crate::language::Language;
3use crate::models::ObjectiveTag;
4use crate::models::*;
5use crate::prelude::Error;
6use crate::prelude::Result as AppResult;
7use crate::time;
8use crate::week_info::Date;
9use crate::week_info::DateView;
10use chrono::{DateTime, Local};
11use serde::Serialize;
12
13pub mod arabic;
14pub mod calendar_names;
15pub mod chinese;
16pub mod gregorian;
17pub mod persian;
18
19#[derive(Clone, Debug)]
20pub struct CalendarLanguagePair {
21    pub calendar: Calendar,
22    pub language: Language,
23}
24
25impl CalendarLanguagePair {
26    pub fn get_objective_tag(
27        &self,
28        year: Option<i32>,
29        season: Option<i32>,
30        month: Option<i32>,
31    ) -> Option<ObjectiveTag> {
32        if let Some(year) = year {
33            let calview = self.calendar.get_calendar_view(&self.language);
34            let year_string = year.to_string();
35            let year_string = self.language.change_numbers_language(&year_string);
36            let (text, r#type) = if let Some(season) = season {
37                let season = season - 1;
38                let season = calview.seasons_names[season as usize].clone();
39                (format!("{season} {year_string}"), OBJECTIVE_TYPE_SEASONAL)
40            } else if let Some(month) = month {
41                let month = month - 1;
42                let month = calview.months_names[month as usize].clone();
43                (format!("{month} {year_string}"), OBJECTIVE_TYPE_MONTHLY)
44            } else {
45                (year_string.clone(), OBJECTIVE_TYPE_YEARLY)
46            };
47            Some(ObjectiveTag {
48                calendar: calview.calendar,
49                text,
50                r#type,
51                calendar_name: calview.calendar_name.clone(),
52                language: calview.language.clone(),
53                year_string,
54                year,
55                season: season.map(|i| i as usize),
56                month: month.map(|i| i as usize),
57            })
58        } else {
59            None
60        }
61    }
62}
63
64impl From<&Calendar> for CalendarLanguagePair {
65    fn from(val: &Calendar) -> Self {
66        let main_pair: CalendarLanguagePair = config::get_main_cal_lang_pair();
67        let second_pair: Option<CalendarLanguagePair> = config::get_second_cal_lang_pair();
68        if *val == main_pair.calendar {
69            main_pair
70        } else if let Some(pair) = second_pair {
71            if *val == pair.calendar {
72                pair
73            } else {
74                CalendarLanguagePair {
75                    calendar: val.clone(),
76                    language: Language::default(),
77                }
78            }
79        } else {
80            CalendarLanguagePair {
81                calendar: val.clone(),
82                language: Language::default(),
83            }
84        }
85    }
86}
87
88use self::arabic::ArabicCalendar;
89use self::chinese::ChineseCalendar;
90use self::gregorian::GregorianCalendar;
91use self::persian::PersianCalendar;
92
93pub const CALENDAR_GREGORIAN: i32 = 0;
94pub const CALENDAR_PERSIAN: i32 = 1;
95pub const CALENDAR_CHINESE: i32 = 2;
96pub const CALENDAR_ARABIC: i32 = 3;
97
98pub const CALENDAR_GREGORIAN_STRING: &str = "Gregorian";
99pub const CALENDAR_PERSIAN_STRING: &str = "Persian";
100pub const CALENDAR_CHINESE_STRING: &str = "Chinese";
101pub const CALENDAR_ARABIC_STRING: &str = "Arabic";
102
103#[derive(Debug, Serialize, Clone, PartialEq)]
104pub enum Calendar {
105    Gregorian(gregorian::GregorianCalendar),
106    Persian(persian::PersianCalendar),
107    Chinese(chinese::ChineseCalendar),
108    Arabic(arabic::ArabicCalendar),
109}
110
111impl Default for Calendar {
112    fn default() -> Self {
113        Calendar::Gregorian(gregorian::GregorianCalendar)
114    }
115}
116
117impl Calendar {
118    pub fn get_date(&self, day: i32) -> Date {
119        match self {
120            Calendar::Gregorian(_) => GregorianCalendar::get_date(day),
121            Calendar::Persian(_) => PersianCalendar::get_date(day),
122            Calendar::Chinese(_) => ChineseCalendar::get_date(day),
123            Calendar::Arabic(_) => ArabicCalendar::get_date(day),
124        }
125    }
126
127    pub fn get_date_view(&self, day: i32, lang: &Language) -> DateView {
128        match self {
129            Calendar::Gregorian(_) => GregorianCalendar::get_date_view(day, lang),
130            Calendar::Persian(_) => PersianCalendar::get_date_view(day, lang),
131            Calendar::Chinese(_) => ChineseCalendar::get_date_view(day, lang),
132            Calendar::Arabic(_) => ArabicCalendar::get_date_view(day, lang),
133        }
134    }
135
136    pub fn get_calendar_view(&self, lang: &Language) -> CalendarView {
137        match self {
138            Calendar::Gregorian(_) => GregorianCalendar::get_calendar_view(lang),
139            Calendar::Persian(_) => PersianCalendar::get_calendar_view(lang),
140            Calendar::Chinese(_) => ChineseCalendar::get_calendar_view(lang),
141            Calendar::Arabic(_) => ArabicCalendar::get_calendar_view(lang),
142        }
143    }
144
145    pub fn get_dates_view(
146        &self,
147        start_day: i32,
148        end_day: i32,
149        _lang: &Language,
150    ) -> AppResult<Vec<DateView>> {
151        match self {
152            Calendar::Gregorian(_) => GregorianCalendar::get_dates_view(start_day, end_day, _lang),
153            Calendar::Persian(_) => PersianCalendar::get_dates_view(start_day, end_day, _lang),
154            Calendar::Chinese(_) => ChineseCalendar::get_dates_view(start_day, end_day, _lang),
155            Calendar::Arabic(_) => ArabicCalendar::get_dates_view(start_day, end_day, _lang),
156        }
157    }
158
159    pub fn into_direction(&self) -> String {
160        match self {
161            Calendar::Gregorian(_) => "ltr".into(),
162            Calendar::Persian(_) => "rtl".into(),
163            Calendar::Chinese(_) => "ltr".into(),
164            Calendar::Arabic(_) => "rtl".into(),
165        }
166    }
167}
168
169impl From<Calendar> for i32 {
170    fn from(val: Calendar) -> Self {
171        match val {
172            Calendar::Gregorian(_) => CALENDAR_GREGORIAN,
173            Calendar::Persian(_) => CALENDAR_PERSIAN,
174            Calendar::Chinese(_) => CALENDAR_CHINESE,
175            Calendar::Arabic(_) => CALENDAR_ARABIC,
176        }
177    }
178}
179
180impl From<Calendar> for String {
181    fn from(val: Calendar) -> Self {
182        match val {
183            Calendar::Gregorian(_) => CALENDAR_GREGORIAN_STRING.to_string(),
184            Calendar::Persian(_) => CALENDAR_PERSIAN_STRING.to_string(),
185            Calendar::Chinese(_) => CALENDAR_CHINESE_STRING.to_string(),
186            Calendar::Arabic(_) => CALENDAR_ARABIC_STRING.to_string(),
187        }
188    }
189}
190
191impl From<String> for Calendar {
192    fn from(val: String) -> Self {
193        if val == "Persian" {
194            Calendar::Persian(persian::PersianCalendar)
195        } else if val == "Gregorian" {
196            Calendar::Gregorian(gregorian::GregorianCalendar)
197        } else if val == "Chinese" {
198            Calendar::Chinese(chinese::ChineseCalendar)
199        } else if val == "Arabic" {
200            Calendar::Arabic(arabic::ArabicCalendar)
201        } else {
202            Calendar::Gregorian(gregorian::GregorianCalendar)
203        }
204    }
205}
206
207impl From<i32> for Calendar {
208    fn from(val: i32) -> Self {
209        match val {
210            CALENDAR_PERSIAN => Calendar::Persian(persian::PersianCalendar),
211            CALENDAR_GREGORIAN => Calendar::Gregorian(gregorian::GregorianCalendar),
212            CALENDAR_CHINESE => Calendar::Chinese(chinese::ChineseCalendar),
213            CALENDAR_ARABIC => Calendar::Arabic(arabic::ArabicCalendar),
214            _ => panic!("@from() not a valid calendar number: {}", val),
215        }
216    }
217}
218
219#[derive(Serialize)]
220pub struct CalendarView {
221    pub calendar: i32,
222    pub calendar_name: String,
223    pub language: String,
224    pub direction: String,
225    pub months_names: Vec<String>,
226    pub seasons_names: Vec<String>,
227}
228
229pub trait CalendarSpecificDateView {
230    fn new_date(datetime: DateTime<Local>) -> Date;
231    fn new_date_view(datetime: DateTime<Local>, lang: &Language) -> DateView;
232    fn get_calendar_view(lang: &Language) -> CalendarView;
233
234    fn get_date(day: i32) -> Date {
235        let datetime: DateTime<Local> = time::get_local_datetime_form_unix_day(day);
236        Self::new_date(datetime)
237    }
238
239    fn get_date_view(day: i32, lang: &Language) -> DateView {
240        let datetime: DateTime<Local> = time::get_local_datetime_form_unix_day(day);
241        let mut dateview = Self::new_date_view(datetime, lang);
242        dateview.unix_day = day;
243        dateview
244    }
245
246    fn get_dates_view(start_day: i32, end_day: i32, lang: &Language) -> AppResult<Vec<DateView>> {
247        Self::check_days_range(start_day, end_day)?;
248        let mut dates: Vec<DateView> = Vec::new();
249        // convert days to DateTime
250        for i in start_day..=end_day {
251            let date = Self::get_date_view(i, lang);
252            dates.push(date);
253        }
254        Ok(dates)
255    }
256
257    fn check_days_range(start_day: i32, end_day: i32) -> AppResult<()> {
258        if start_day > end_day {
259            Err(Error::BadDaysRangeError)
260        } else if (end_day - start_day) > 20 {
261            Err(Error::LongDaysRangeError(end_day - start_day))
262        } else {
263            Ok(())
264        }
265    }
266}