use std::collections::HashMap;
use time::{OffsetDateTime, Weekday, util};
use crate::error::Error;
use crate::utility;
use crate::{MonthlyDayOrdinal, MonthlyWeekdayOrdinal, Ordinal};
pub struct Calendar {
days: Vec<CalendarDay>,
}
impl Calendar {
pub fn create_days(&mut self, from_date: OffsetDateTime, to_date: OffsetDateTime) -> Result<(), Error> {
let mut weekdays_counter = WeekDaysCounter::new();
let mut date = utility::first_date_of_month(&from_date)?;
while date < to_date {
weekdays_counter.inc_counter(date.weekday());
if date >= from_date {
let weekday_ordinal = weekdays_counter.weekday_ordinal(date.weekday())?;
self.insert_day(date, weekday_ordinal);
};
date = utility::next_day(&date)?;
};
Ok(())
}
pub fn days(&self) -> &Vec<CalendarDay> {
&self.days
}
fn insert_day(&mut self, date: OffsetDateTime, weekday_ordinal: MonthlyWeekdayOrdinal) -> () {
self.days.push(CalendarDay::new(date, weekday_ordinal));
}
pub fn new() -> Calendar {
Calendar {
days: Vec::new(),
}
}
}
#[derive (Debug)]
pub struct CalendarDay {
date: OffsetDateTime,
weekdays: [Weekday; 1],
monthly_days_ordinals: [MonthlyDayOrdinal; 1],
monthly_weekdays_ordinals: Vec<MonthlyWeekdayOrdinal>,
}
impl CalendarDay {
pub fn date(&self) -> OffsetDateTime {
self.date
}
pub fn monthly_days_ordinals(&self) -> &[MonthlyDayOrdinal] {
&self.monthly_days_ordinals
}
pub fn monthly_weekdays_ordinals(&self) -> &[MonthlyWeekdayOrdinal] {
&self.monthly_weekdays_ordinals
}
fn new(date: OffsetDateTime, monthly_weekday_ordinal: MonthlyWeekdayOrdinal) -> CalendarDay {
let weekday = date.weekday();
let monthly_day_ordinal = date.day();
let mut monthly_weekdays_ordinals = Vec::new();
monthly_weekdays_ordinals.push(monthly_weekday_ordinal);
if util::days_in_year_month(date.year(), date.month()) - monthly_day_ordinal < 7 {
monthly_weekdays_ordinals.push(MonthlyWeekdayOrdinal::new(Ordinal::Last, weekday));
};
CalendarDay {
date,
weekdays: [weekday],
monthly_days_ordinals: [monthly_day_ordinal],
monthly_weekdays_ordinals : monthly_weekdays_ordinals,
}
}
pub fn weekdays(&self) -> &[Weekday] {
&self.weekdays
}
}
#[derive (Debug)]
struct WeekDaysCounter {
weekdays: HashMap<Weekday, u8>,
}
impl WeekDaysCounter {
fn inc_counter(&mut self, weekday: Weekday) -> () {
*self.weekdays.entry(weekday).or_insert(0) += 1;
}
fn new() -> WeekDaysCounter {
WeekDaysCounter {
weekdays: HashMap::new()
}
}
fn weekday_ordinal(&self, weekday: Weekday) -> Result<MonthlyWeekdayOrdinal, Error> {
let ordinals = HashMap::from([(1, Ordinal::First), (2, Ordinal::Second), (3, Ordinal::Third), (4, Ordinal::Fourth), (5, Ordinal::Fifth)]);
let counter = self.weekdays.get(&weekday).ok_or(Error::NotFound)?;
let ordinal = ordinals.get(&counter).ok_or(Error::UnexpectedValue)?;
Ok(MonthlyWeekdayOrdinal::new(*ordinal, weekday))
}
}