use chrono::{Datelike, Local};
use std::convert::TryInto;
use crate::{
BengaliDate, BengaliMonths, BengaliWeekDays, Date, DateError, EnglishDate, EnglishMonths,
};
fn is_leap_year(year: u16) -> bool {
year % 4 == 0
}
fn gregorian_to_bengali_date(english_date: EnglishDate) -> Result<Date, DateError> {
let (english_day, english_month, english_year) = english_date.get_date();
let bengali_year: u16 = if english_month < 4 || (english_month == 4 && english_day < 14) {
match english_year.checked_sub(594) {
Some(year) => year,
None => {
return Err(DateError::ArithmeticError);
}
}
} else {
match english_year.checked_sub(593) {
Some(year) => year,
None => {
return Err(DateError::ArithmeticError);
}
}
};
let (bengali_day, bengali_month) = if english_month == 1 {
if english_day <= 14 {
(english_day + 16, 9)
} else {
(english_day - 14, 10)
}
} else if english_month == 2 {
if english_day <= 13 {
(english_day + 17, 10)
} else {
(english_day - 13, 11)
}
} else if english_month == 3 {
if english_day <= 14 {
if is_leap_year(english_year) {
(english_day + 16, 11)
} else {
(english_day + 15, 11)
}
} else {
(english_day - 14, 12)
}
} else if english_month == 4 {
if english_day <= 13 {
(english_day + 17, 12)
} else {
(english_day - 13, 1)
}
} else if english_month == 5 {
if english_day <= 14 {
(english_day + 17, 1)
} else {
(english_day - 14, 2)
}
} else if english_month == 6 {
if english_day <= 14 {
(english_day + 17, 2)
} else {
(english_day - 14, 3)
}
} else if english_month == 7 {
if english_day <= 15 {
(english_day + 16, 3)
} else {
(english_day - 15, 4)
}
} else if english_month == 8 {
if english_day <= 15 {
(english_day + 16, 4)
} else {
(english_day - 15, 5)
}
} else if english_month == 9 {
if english_day <= 15 {
(english_day + 16, 5)
} else {
(english_day - 15, 6)
}
} else if english_month == 10 {
if english_day <= 16 {
(english_day + 15, 6)
} else {
(english_day - 16, 7)
}
} else if english_month == 11 {
if english_day <= 15 {
(english_day + 15, 7)
} else {
(english_day - 15, 8)
}
} else if english_month == 12 {
if english_day <= 15 {
(english_day + 15, 8)
} else {
(english_day - 15, 9)
}
} else {
return Err(DateError::WrongDay);
};
let bengali_weekday =
BengaliWeekDays::get_english_weekday(english_date.get_week_day().unwrap().as_str());
match BengaliDate::create_date_with_weekday(
bengali_day,
bengali_weekday.unwrap(),
BengaliMonths::get_month(bengali_month).unwrap(),
bengali_year,
) {
Ok(bengali_date) => Ok(Date::Bengali(bengali_date)),
Err(err) => Err(err),
}
}
fn bengali_to_gregorian_date(bengali_date: BengaliDate) -> Result<Date, DateError> {
let (bengali_day, bengali_month, bengali_year) = bengali_date.get_date();
let english_year: u16 = if (bengali_month == 9 && bengali_day >= 17)
|| (bengali_month == 12 && bengali_day <= 30)
|| bengali_month == 10
|| bengali_month == 11
{
match bengali_year.checked_add(594) {
Some(year) => year,
None => return Err(DateError::ArithmeticError),
}
} else {
match bengali_year.checked_add(593) {
Some(year) => year,
None => return Err(DateError::ArithmeticError),
}
};
let (english_date, english_month) = if bengali_month == 9 {
if bengali_day >= 17 {
(bengali_day - 16, 1)
} else {
(bengali_day + 15, 12)
}
} else if bengali_month == 10 {
if bengali_day >= 18 {
(bengali_day - 17, 2)
} else {
(bengali_day + 14, 1)
}
} else if bengali_month == 11 {
if is_leap_year(english_year) {
if bengali_day >= 17 {
(bengali_day - 16, 3)
} else {
(bengali_day + 13, 2)
}
} else {
if bengali_day >= 16 {
(bengali_day - 15, 3)
} else {
(bengali_day + 13, 2)
}
}
} else if bengali_month == 12 {
if bengali_day >= 18 {
(bengali_day - 17, 4)
} else {
(bengali_day + 14, 3)
}
} else if bengali_month == 1 {
if bengali_day >= 18 {
(bengali_day - 17, 5)
} else {
(bengali_day + 13, 4)
}
} else if bengali_month == 2 {
if bengali_day >= 18 {
(bengali_day - 17, 6)
} else {
(bengali_day + 14, 5)
}
} else if bengali_month == 3 {
if bengali_day >= 17 {
(bengali_day - 16, 7)
} else {
(bengali_day + 14, 6)
}
} else if bengali_month == 4 {
if bengali_day >= 17 {
(bengali_day - 16, 8)
} else {
(bengali_day + 15, 7)
}
} else if bengali_month == 5 {
if bengali_day >= 17 {
(bengali_day - 16, 9)
} else {
(bengali_day + 15, 8)
}
} else if bengali_month == 6 {
if bengali_day >= 16 {
(bengali_day - 15, 10)
} else {
(bengali_day + 15, 9)
}
} else if bengali_month == 7 {
if bengali_day >= 16 {
(bengali_day - 15, 11)
} else {
(bengali_day + 16, 10)
}
} else if bengali_month == 8 {
if bengali_day >= 16 {
(bengali_day - 15, 12)
} else {
(bengali_day + 15, 11)
}
} else {
return Err(DateError::WrongDay);
};
match EnglishDate::create_date(
english_date,
EnglishMonths::get_month(english_month).unwrap(),
english_year,
) {
Ok(english_date) => Ok(Date::English(english_date)),
Err(err) => Err(err),
}
}
pub fn get_today_bengali_date() -> Result<Date, DateError> {
let today = Local::now();
let today_day: u8 = match today.day().try_into() {
Ok(day) => day,
Err(err) => {
return Err(DateError::CastingError(err)); }
};
let today_month: u8 = match today.month().try_into() {
Ok(month) => month,
Err(err) => {
return Err(DateError::CastingError(err)); }
};
let today_year: u16 = match today.year().try_into() {
Ok(year) => year,
Err(err) => {
return Err(DateError::CastingError(err)); }
};
match EnglishMonths::get_month(today_month) {
Ok(month) => {
let english_date = EnglishDate::create_date(today_day, month, today_year);
match english_date {
Ok(date) => match gregorian_to_bengali_date(date) {
Ok(bengali_date) => Ok(bengali_date),
Err(err) => Err(err),
},
Err(err) => return Err(err),
}
}
Err(err) => match err {
_ => return Err(DateError::WrongMonth(err)),
},
}
}
pub fn get_bengali_date_from_gregorian(english_date: EnglishDate) -> Result<Date, DateError> {
match gregorian_to_bengali_date(english_date) {
Ok(date) => Ok(date),
Err(err) => Err(err),
}
}
pub fn get_gregorian_date_from_bengali(bengali_date: BengaliDate) -> Result<Date, DateError> {
match bengali_to_gregorian_date(bengali_date) {
Ok(date) => Ok(date),
Err(err) => Err(err),
}
}