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 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}