Skip to main content

gw2timers/
schedule.rs

1//! Represents the schedule of a single event in a maps' [meta]
2
3use std::{fmt::Debug, ops::Add};
4
5use chrono::{Duration, NaiveTime, Timelike};
6
7use crate::event::EventInstance;
8
9/// The schedule of a map meta event
10#[derive(Clone)]
11pub struct EventSchedule {
12    /// The name of the event
13    pub name: &'static str,
14
15    /// The offset from UTC 00:00 the first event occurs
16    pub offset: NaiveTime,
17
18    /// How often the event occurs
19    pub frequency: Duration,
20
21    /// How long the event lasts
22    pub length: Duration,
23}
24
25impl EventSchedule {
26    pub fn iter(&self) -> Iter {
27        Iter::new(self, Duration::zero())
28    }
29}
30
31impl IntoIterator for EventSchedule {
32    type Item = EventInstance;
33    type IntoIter = IntoIter;
34
35    fn into_iter(self) -> Self::IntoIter {
36        IntoIter::new(self, Duration::zero())
37    }
38}
39
40impl Debug for EventSchedule {
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        write!(
43            f,
44            "{}: offset: {}, freq: {}m, len: {}m",
45            self.name,
46            self.offset,
47            self.frequency.num_minutes(),
48            self.length.num_minutes()
49        )
50    }
51}
52
53/// An iterator that gives the next occuring [EventInstance] in an [EventSchedule]
54///
55/// The first call to `next()` will return the currently active event (i.e. the requested time is
56/// between the [EventInstance]'s start and end time), if applicable, or the next event if there
57/// isn't one currently active
58pub struct IntoIter {
59    event_schedule: EventSchedule,
60    offset: Duration,
61}
62
63impl IntoIter {
64    // Creates a new iterator starting from the previous occurance of the event
65    fn new(event_schedule: EventSchedule, current_time: Duration) -> IntoIter {
66        // Must use Durations instead of NaiveTime because the event_end_time might be over 24 hours
67        IntoIter {
68            event_schedule,
69            offset: current_time,
70        }
71    }
72
73    /// Skip to a certain time of day
74    pub fn time(mut self, time: NaiveTime) -> Self {
75        self.offset = Duration::seconds(time.num_seconds_from_midnight() as i64);
76        self
77    }
78
79    /// Skip forward an amount of time
80    pub fn fast_forward(mut self, amount: Duration) -> Self {
81        self.offset = self.offset.add(amount);
82        self
83    }
84
85    /// Get the event happening now, if any, at the current iteration of the iterator.
86    pub fn now(&self) -> Option<EventInstance> {
87        let time = self.offset.num_minutes();
88        let offset = self.event_schedule.offset.num_seconds_from_midnight() as i64 / 60;
89        let freq = self.event_schedule.frequency.num_minutes();
90        let length = self.event_schedule.length.num_minutes();
91        let i = time / freq;
92        let relative_time = time - i * freq;
93
94        if relative_time < offset || relative_time >= offset + length {
95            return None;
96        }
97
98        let offset = Duration::minutes(offset + i * freq);
99
100        Some(EventInstance {
101            schedule: self.event_schedule.clone(),
102            start_time: offset,
103        })
104    }
105}
106
107impl Iterator for IntoIter {
108    type Item = EventInstance;
109
110    fn next(&mut self) -> Option<EventInstance> {
111        let time = self.offset.num_minutes();
112        let offset = self.event_schedule.offset.num_seconds_from_midnight() as i64 / 60;
113        let freq = self.event_schedule.frequency.num_minutes();
114        let i = time / freq;
115        let relative_time = time - i * freq;
116
117        let offset = if relative_time < offset {
118            offset
119        } else {
120            offset + freq
121        };
122
123        self.offset = Duration::minutes(offset + i * freq);
124
125        Some(EventInstance {
126            schedule: self.event_schedule.clone(),
127            start_time: self.offset,
128        })
129    }
130}
131
132pub struct Iter<'a> {
133    event_schedule: &'a EventSchedule,
134    offset: Duration,
135}
136
137impl<'a> Iter<'_> {
138    // Creates a new iterator starting from the previous occurance of the event
139    fn new(event_schedule: &'a EventSchedule, current_time: Duration) -> Iter {
140        // Must use Durations instead of NaiveTime because the event_end_time might be over 24 hours
141        Iter {
142            event_schedule,
143            offset: current_time,
144        }
145    }
146
147    /// Skip to a certain time of day
148    pub fn time(mut self, time: NaiveTime) -> Self {
149        self.offset = Duration::seconds(time.num_seconds_from_midnight() as i64);
150        self
151    }
152
153    /// Skip forward an amount of time
154    pub fn fast_forward(mut self, amount: Duration) -> Self {
155        self.offset = self.offset.add(amount);
156        self
157    }
158
159    /// Get the event happening now, if any, at the current iteration of the iterator.
160    pub fn now(&self) -> Option<EventInstance> {
161        let time = self.offset.num_minutes();
162        let offset = self.event_schedule.offset.num_seconds_from_midnight() as i64 / 60;
163        let freq = self.event_schedule.frequency.num_minutes();
164        let length = self.event_schedule.length.num_minutes();
165        let i = time / freq;
166        let relative_time = time - i * freq;
167
168        if relative_time < offset || relative_time >= offset + length {
169            return None;
170        }
171
172        let offset = Duration::minutes(offset + i * freq);
173        Some(EventInstance {
174            schedule: self.event_schedule.clone(),
175            start_time: offset,
176        })
177    }
178}
179
180impl Iterator for Iter<'_> {
181    type Item = EventInstance;
182
183    fn next(&mut self) -> Option<EventInstance> {
184        let time = self.offset.num_minutes();
185        let offset = self.event_schedule.offset.num_seconds_from_midnight() as i64 / 60;
186        let freq = self.event_schedule.frequency.num_minutes();
187        let i = time / freq;
188        let relative_time = time - i * freq;
189
190        let offset = if relative_time < offset {
191            offset
192        } else {
193            offset + freq
194        };
195
196        self.offset = Duration::minutes(offset + i * freq);
197
198        Some(EventInstance {
199            schedule: self.event_schedule.clone(),
200            start_time: self.offset,
201        })
202    }
203}
204
205pub struct IterMut<'a> {
206    event_schedule: &'a mut EventSchedule,
207    offset: Duration,
208}
209
210impl<'a> IterMut<'_> {
211    // Creates a new iterator starting from the previous occurance of the event
212    fn new(event_schedule: &'a mut EventSchedule, current_time: Duration) -> IterMut {
213        // Must use Durations instead of NaiveTime because the event_end_time might be over 24 hours
214        IterMut {
215            event_schedule,
216            offset: current_time,
217        }
218    }
219
220    /// Skip to a certain time of day
221    pub fn time(mut self, time: NaiveTime) -> Self {
222        self.offset = Duration::seconds(time.num_seconds_from_midnight() as i64);
223        self
224    }
225
226    /// Skip forward an amount of time
227    pub fn fast_forward(mut self, amount: Duration) -> Self {
228        self.offset = self.offset.add(amount);
229        self
230    }
231
232    /// Get the event happening now, if any, at the current iteration of the iterator.
233    pub fn now(&self) -> Option<EventInstance> {
234        let time = self.offset.num_minutes();
235        let offset = self.event_schedule.offset.num_seconds_from_midnight() as i64 / 60;
236        let freq = self.event_schedule.frequency.num_minutes();
237        let length = self.event_schedule.length.num_minutes();
238        let i = time / freq;
239        let relative_time = time - i * freq;
240
241        if relative_time < offset || relative_time >= offset + length {
242            return None;
243        }
244
245        let offset = Duration::minutes(offset + i * freq);
246        Some(EventInstance {
247            schedule: self.event_schedule.clone(),
248            start_time: offset,
249        })
250    }
251}
252
253impl Iterator for IterMut<'_> {
254    type Item = EventInstance;
255
256    fn next(&mut self) -> Option<EventInstance> {
257        let time = self.offset.num_minutes();
258        let offset = self.event_schedule.offset.num_seconds_from_midnight() as i64 / 60;
259        let freq = self.event_schedule.frequency.num_minutes();
260        let i = time / freq;
261        let relative_time = time - i * freq;
262
263        let offset = if relative_time < offset {
264            offset
265        } else {
266            offset + freq
267        };
268
269        self.offset = Duration::minutes(offset + i * freq);
270
271        Some(EventInstance {
272            schedule: self.event_schedule.clone(),
273            start_time: self.offset,
274        })
275    }
276}