use crate::frequencies::Frequency;
use crate::recurrences::errors::RecurrenceInvalid;
use crate::recurrences::validations::{validate_duration, validate_recurrence_period};
use chrono::{DateTime, Duration, Utc};
use std::str::FromStr;
pub const MAX_DATE: &str = "9999-12-31T23:59:59Z";
#[derive(Debug, Clone)]
pub struct Recurrence {
pub frequency: Frequency,
pub start: DateTime<Utc>,
pub current_date: Option<DateTime<Utc>>,
pub end: DateTime<Utc>,
pub duration: Duration,
}
impl Recurrence {
pub fn new(
frequency: Frequency,
start: DateTime<Utc>,
end: Option<DateTime<Utc>>,
duration: Option<Duration>,
) -> Result<Self, RecurrenceInvalid> {
let end = end.unwrap_or_else(|| DateTime::<Utc>::from_str(MAX_DATE).unwrap());
if frequency.is_valid().is_err() {
return Err(RecurrenceInvalid {
message: format!("{}", frequency.is_valid().unwrap_err()),
});
}
validate_recurrence_period(&start, &end)?;
let duration = duration.unwrap_or_else(|| Duration::seconds(0));
validate_duration(&frequency, &duration)?;
Ok(Recurrence {
frequency,
start,
current_date: Some(start),
end,
duration,
})
}
pub fn set_current_date(&mut self, current_date: Option<DateTime<Utc>>) {
self.current_date = current_date;
}
}
impl Iterator for Recurrence {
type Item = DateTime<Utc>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(current_date) = self.current_date {
if current_date > self.end {
return None;
}
let next_event = self.frequency.next_event(¤t_date);
self.set_current_date(next_event);
return if self.frequency.contains(¤t_date) {
Some(current_date)
} else {
self.next()
};
}
None
}
}