use chrono::Datelike;
use color_eyre::eyre::Result;
use std::{
fs::create_dir_all,
path::{Path, PathBuf},
rc::Rc,
};
use crate::{
configuration::{config::Config, types::calendar_view::CalendarView},
model::{
calendar_collection::CalendarCollection,
day::Day,
event::{Event, EventContext},
},
};
pub(crate) const YMD_FORMAT: &str = "%Y-%m-%d";
pub type DaySlice<'a> = &'a [Option<Day>];
pub(crate) const VIEW_PATH: &str = "day";
const PAGE_TITLE: &str = "Day Page";
#[derive(Debug)]
pub struct DayView<'a> {
calendars: &'a CalendarCollection,
output_dir: PathBuf,
}
impl DayView<'_> {
pub fn new(calendars: &CalendarCollection) -> DayView<'_> {
let output_dir = calendars
.base_dir()
.join(&calendars.config.output_dir)
.join(VIEW_PATH);
DayView {
calendars,
output_dir,
}
}
fn config(&self) -> &Config {
&self.calendars.config
}
fn output_dir(&self) -> &Path {
&self.output_dir
}
pub fn create_html_pages(&self) -> Result<()> {
create_dir_all(self.output_dir())?;
let mut index_written = false;
for window in self.calendars.days_to_show()?.windows(3) {
let next_day_opt = &window[2];
let mut index_paths = vec![];
if !index_written {
if let Some(next_day) = next_day_opt {
if next_day.start_datetime.date_naive() > self.calendars.today_date() {
index_written = true;
index_paths.push(self.output_dir().join(PathBuf::from("index.html")));
if self.config().default_calendar_view == CalendarView::Day {
index_paths
.push(self.config().output_dir.join(PathBuf::from("index.html")));
}
}
} else {
index_written = true;
index_paths.push(self.output_dir().join(PathBuf::from("index.html")));
if self.config().default_calendar_view == CalendarView::Day {
index_paths
.push(self.config().output_dir.join(PathBuf::from("index.html")));
}
}
}
self.write_view(&window, index_paths.as_slice())?;
}
Ok(())
}
fn write_view(&self, day_slice: &DaySlice, index_paths: &[PathBuf]) -> Result<()> {
let previous_day = &day_slice[0].as_ref();
let current_day = day_slice[1]
.as_ref()
.expect("Current week is None. This should never happen.");
let next_day = day_slice[2].as_ref();
let day = current_day.start;
let empty_vec = vec![];
let events: &Vec<Rc<Event>> = self.calendars.events_by_day.get(&day).unwrap_or(&empty_vec);
println!("day: {}", day);
for event in events {
println!(
" event: ({} {} {}) {} {}",
event.start().weekday(),
event.year(),
event.week(),
event.summary(),
event.start(),
);
}
let file_name = format!("{}.html", day.format(YMD_FORMAT));
let previous_file_name =
previous_day.map(|previous_day| format!("{}.html", previous_day.format(YMD_FORMAT)));
let next_file_name =
next_day.map(|next_day| format!("{}.html", next_day.format(YMD_FORMAT)));
let mut context = self.calendars.template_context();
context.insert("month_view_path", ¤t_day.month_view_path());
context.insert("week_view_path", ¤t_day.week_view_path());
context.insert("event_view_path", &events.first().map(|e| e.file_path()));
context.insert("current_view", VIEW_PATH);
context.insert("page_title", PAGE_TITLE);
context.insert(
"view_date",
¤t_day
.format(&self.config().day_view_format)
.to_string(),
);
context.insert("year", &day.year());
context.insert("month", &day.month());
context.insert("month_name", ¤t_day.month());
context.insert("day", &day.day());
context.insert(
"events",
&events
.iter()
.map(|e| e.context(self.config()))
.collect::<Vec<EventContext>>(),
);
let base_url_path: unix_path::PathBuf =
self.calendars.config.base_url_path.path_buf().clone();
let binding = self.output_dir().join(PathBuf::from(&file_name));
let mut file_paths = vec![&binding];
file_paths.extend(index_paths);
for file_path in file_paths {
let view_path = base_url_path.join("day");
context.insert(
"previous_file_name",
&previous_file_name.as_ref().map(|path| view_path.join(path)),
);
context.insert(
"next_file_name",
&next_file_name.as_ref().map(|path| view_path.join(path)),
);
self.calendars
.write_template("day.html", &context, file_path)?;
}
Ok(())
}
}