use chrono::NaiveDate;
use crate::calendar::events::{Event, EventList};
pub struct ListOptions {
pub show_ids: bool,
pub from_date: NaiveDate,
pub to_date: NaiveDate,
pub query: Option<String>,
pub limit: Option<usize>,
}
impl Default for ListOptions {
fn default() -> Self {
let today = chrono::Local::now().date_naive();
ListOptions {
show_ids: false,
from_date: today,
to_date: today + chrono::Duration::days(30),
query: None,
limit: None,
}
}
}
pub fn show_events(events: &EventList, options: &ListOptions) {
let mut filtered_events = filter_events(events, options);
filtered_events.sort_by(|a, b| a.start.cmp(&b.start));
if let Some(limit) = options.limit {
filtered_events.truncate(limit);
}
for event in &filtered_events {
print_event(event, options.show_ids);
}
}
fn filter_events<'a>(events: &'a EventList, options: &ListOptions) -> Vec<&'a Event> {
let current_time = chrono::Local::now().naive_local().time();
let from_datetime = options.from_date.and_time(current_time);
let to_datetime = options.to_date.and_time(current_time);
events.all().iter()
.filter(|event| {
event.start >= from_datetime && event.start <= to_datetime
})
.filter(|event| {
if let Some(query) = &options.query {
fuzzy_match(&event.name, query) ||
event.location.as_ref().map_or(false, |loc| fuzzy_match(loc, query)) ||
event.description.as_ref().map_or(false, |desc| fuzzy_match(desc, query))
} else {
true
}
})
.collect()
}
fn print_event(event: &Event, show_id: bool) {
let day_of_week = event.start.format("%a");
let date = event.start.format("%d %b");
let start_time = event.start.format("%H:%M");
let end_time = event.end.format("%H:%M");
let location_part = event
.location
.as_ref()
.map_or(String::new(), |loc| format!(" in {}", loc));
if show_id {
println!(
"{}: {} {} {}-{} - {}{}",
event.id, day_of_week, date, start_time, end_time, event.name, location_part
);
} else {
println!(
"{} {} {}-{} - {}{}",
day_of_week, date, start_time, end_time, event.name, location_part
);
}
}
fn fuzzy_match(text: &str, pattern: &str) -> bool {
let text = text.to_lowercase();
let pattern = pattern.to_lowercase();
let mut text_chars = text.chars();
for p in pattern.chars() {
if !text_chars.any(|c| c == p) {
return false;
}
}
true
}