use chrono::{NaiveDate, Datelike};
use crate::RuleContext;
use shaum_types::FastingStatus;
pub struct DaudIterator<'a> {
current: NaiveDate,
context: &'a RuleContext,
is_fasting_turn: bool,
}
impl<'a> DaudIterator<'a> {
pub fn new(start: NaiveDate, context: &'a RuleContext) -> Self {
Self {
current: start,
context,
is_fasting_turn: true, }
}
}
impl Iterator for DaudIterator<'_> {
type Item = NaiveDate;
fn next(&mut self) -> Option<Self::Item> {
loop {
if self.current.year() > 2100 { return None; }
let date = self.current;
self.current = self.current.succ_opt()?;
let analysis = crate::check(date, self.context).ok()?;
use shaum_types::DaudStrategy;
if analysis.primary_status == FastingStatus::Haram {
if self.is_fasting_turn {
match self.context.daud_strategy {
DaudStrategy::Skip => {
self.is_fasting_turn = false;
},
DaudStrategy::Postpone => {
}
}
continue;
} else {
self.is_fasting_turn = true;
continue;
}
}
if self.is_fasting_turn {
self.is_fasting_turn = false;
return Some(date);
} else {
self.is_fasting_turn = true;
continue;
}
}
}
}
pub fn generate_daud_schedule(
start: NaiveDate,
end: NaiveDate,
context: &RuleContext
) -> Vec<NaiveDate> {
DaudIterator::new(start, context)
.take_while(|d| *d <= end)
.collect()
}
pub struct DaudScheduleBuilder {
start: NaiveDate,
end: Option<NaiveDate>,
postpone_on_haram: bool,
context: RuleContext,
}
impl DaudScheduleBuilder {
pub fn new(start: NaiveDate) -> Self {
Self {
start,
end: None,
postpone_on_haram: false,
context: RuleContext::default(),
}
}
pub fn until(mut self, end: NaiveDate) -> Self {
self.end = Some(end);
self
}
pub fn postpone_on_haram(mut self) -> Self {
self.postpone_on_haram = true;
self
}
pub fn skip_haram_days(mut self) -> Self {
self.postpone_on_haram = false;
self
}
pub fn with_context(mut self, ctx: RuleContext) -> Self {
self.context = ctx;
self
}
pub fn build(self) -> Vec<Result<NaiveDate, shaum_types::ShaumError>> {
let mut results = Vec::new();
let iter = DaudIterator::new(self.start, &self.context);
let end = self.end.unwrap_or_else(|| self.start.checked_add_signed(chrono::Duration::days(365)).unwrap());
for date in iter.take_while(|d| *d <= end) {
results.push(Ok(date));
}
results
}
}