1use chrono::{NaiveDate, Datelike};
2use crate::RuleContext;
3use shaum_types::FastingStatus;
4
5pub struct DaudIterator<'a> {
7 current: NaiveDate,
8 context: &'a RuleContext,
9 is_fasting_turn: bool,
10}
11
12impl<'a> DaudIterator<'a> {
13 pub fn new(start: NaiveDate, context: &'a RuleContext) -> Self {
14 Self {
15 current: start,
16 context,
17 is_fasting_turn: true, }
19 }
20}
21
22impl Iterator for DaudIterator<'_> {
23 type Item = NaiveDate;
24
25 fn next(&mut self) -> Option<Self::Item> {
26 loop {
27 if self.current.year() > 2100 { return None; }
29
30 let date = self.current;
31 self.current = self.current.succ_opt()?;
32
33 let analysis = crate::check(date, self.context).ok()?;
35 use shaum_types::DaudStrategy;
36
37 if analysis.primary_status == FastingStatus::Haram {
38 if self.is_fasting_turn {
40 match self.context.daud_strategy {
42 DaudStrategy::Skip => {
43 self.is_fasting_turn = false;
45 },
46 DaudStrategy::Postpone => {
47 }
50 }
51 continue;
52 } else {
53 self.is_fasting_turn = true;
56 continue;
57 }
58 }
59
60 if self.is_fasting_turn {
61 self.is_fasting_turn = false;
62 return Some(date);
63 } else {
64 self.is_fasting_turn = true;
65 continue;
66 }
67 }
68 }
69}
70
71pub fn generate_daud_schedule(
73 start: NaiveDate,
74 end: NaiveDate,
75 context: &RuleContext
76) -> Vec<NaiveDate> {
77 DaudIterator::new(start, context)
78 .take_while(|d| *d <= end)
79 .collect()
80}
81
82pub struct DaudScheduleBuilder {
84 start: NaiveDate,
85 end: Option<NaiveDate>,
86 postpone_on_haram: bool,
87 context: RuleContext,
88}
89
90impl DaudScheduleBuilder {
91 pub fn new(start: NaiveDate) -> Self {
92 Self {
93 start,
94 end: None,
95 postpone_on_haram: false,
96 context: RuleContext::default(),
97 }
98 }
99
100 pub fn until(mut self, end: NaiveDate) -> Self {
101 self.end = Some(end);
102 self
103 }
104
105 pub fn postpone_on_haram(mut self) -> Self {
106 self.postpone_on_haram = true;
107 self
108 }
109
110 pub fn skip_haram_days(mut self) -> Self {
111 self.postpone_on_haram = false;
112 self
113 }
114
115 pub fn with_context(mut self, ctx: RuleContext) -> Self {
116 self.context = ctx;
117 self
118 }
119
120 pub fn build(self) -> Vec<Result<NaiveDate, shaum_types::ShaumError>> {
121 let mut results = Vec::new();
122 let iter = DaudIterator::new(self.start, &self.context);
124
125 let end = self.end.unwrap_or_else(|| self.start.checked_add_signed(chrono::Duration::days(365)).unwrap());
126
127 for date in iter.take_while(|d| *d <= end) {
130 results.push(Ok(date));
131 }
132 results
133 }
134}