use super::{calendar_collection::CalendarCollection, event::Event};
use crate::views::{day_view, week_view};
use chrono::{Datelike, NaiveDate};
use chrono_tz::Tz as ChronoTz;
use color_eyre::eyre::{eyre, Result};
use std::ops::Bound::Included;
use std::{cmp::Ordering, path::PathBuf, rc::Rc};
#[derive(Debug, Clone, Copy)]
pub struct Month<'a> {
parent_collection: &'a CalendarCollection,
pub(crate) year: i32,
pub(crate) month: u8,
}
impl Month<'_> {
pub fn new(parent_collection: &CalendarCollection, start: NaiveDate) -> Month<'_> {
Month {
parent_collection,
year: start.year(),
month: start.month0() as u8,
}
}
pub fn year(&self) -> i32 {
self.year
}
pub fn month0(&self) -> u8 {
self.month
}
pub fn month(&self) -> u8 {
self.month + 1
}
pub(crate) fn timezone(&self) -> ChronoTz {
*self.parent_collection.display_timezone()
}
pub(crate) fn naive_date(&self) -> Option<NaiveDate> {
NaiveDate::from_ymd_opt(self.year, self.month().into(), 1)
}
pub(crate) fn last_day(&self) -> Option<NaiveDate> {
NaiveDate::from_ymd_opt(self.year, self.month() as u32 + 1, 1)
.unwrap_or(NaiveDate::from_ymd_opt(self.year + 1, 1, 1)?)
.pred_opt()
}
pub fn week_view_path(&self) -> String {
let week = self
.naive_date()
.expect("could not get naive date")
.iso_week();
PathBuf::from("/")
.join(week_view::VIEW_PATH)
.join(format!("{}-{}.html", week.year(), week.week()))
.to_string_lossy()
.to_string()
}
pub fn day_view_path(&self) -> String {
PathBuf::from("/")
.join(day_view::VIEW_PATH)
.join(format!(
"{}-{:02}-{:02}.html",
self.year(),
self.month(),
self.parent_collection.today_date().day()
))
.to_string_lossy()
.to_string()
}
pub(crate) fn first_event(&self) -> Result<Option<&Rc<Event>>> {
let start_day = self.naive_date().ok_or(eyre!("could not get start_day"))?;
let end_day = self.last_day().ok_or(eyre!("could not get end_day"))?;
let first_event = self
.parent_collection
.events_by_day
.range((Included(start_day), Included(end_day)))
.into_iter()
.next()
.map(|(_first_date, events)| events.first())
.flatten();
Ok(first_event)
}
}
impl PartialEq<NaiveDate> for Month<'_> {
fn eq(&self, other: &NaiveDate) -> bool {
self.year == other.year() && self.month == other.month0() as u8
}
}
impl PartialOrd<NaiveDate> for Month<'_> {
fn partial_cmp(&self, other: &NaiveDate) -> Option<Ordering> {
match self.year.partial_cmp(&other.year()) {
Some(order) => match order {
Ordering::Equal => {
self.month.partial_cmp(&(other.month0() as u8))
}
Ordering::Less => Some(Ordering::Less),
Ordering::Greater => Some(Ordering::Greater),
},
None => None,
}
}
}