1use super::*;
2use core::mem;
3
4pub struct PageManager<'a, D> {
68    display: D,
69    page: Box<dyn PageInterface<D> + 'a>,
70    left: Link<Box<dyn PageInterface<D> + 'a>>,
71    right: Link<Box<dyn PageInterface<D> + 'a>>,
72    up: Link<Box<dyn PageInterface<D> + 'a>>,
73    down: Link<Box<dyn PageInterface<D> + 'a>>,
74    startup: Option<Box<dyn PageInterface<D> + 'a>>,
75    shutdown: Option<Box<dyn PageInterface<D> + 'a>>,
76    state: PageManagerState,
77}
78
79type Link<T> = Option<Box<Node<T>>>;
80
81struct Node<T> {
82    page: T,
83    left: Link<T>,
84    right: Link<T>,
85    down: Link<T>,
86    up: Link<T>,
87}
88
89enum PageManagerState {
90    Startup,
91    Operational,
92    Shutdown,
93}
94
95impl<'a, D> PageManager<'a, D> {
96    pub fn new(display: D, home: Box<dyn PageInterface<D> + 'a>) -> Self {
106        PageManager::<D> {
107            display,
108            page: home,
109            left: None,
110            right: None,
111            up: None,
112            down: None,
113            startup: None,
114            shutdown: None,
115            state: PageManagerState::Startup,
116        }
117    }
118
119    pub fn update(&mut self) -> Result<(), PageError> {
124        let iter = Box::new(SubPageIterator {
126            left: self.down.as_deref(),
127        });
128        let navigation = self.page.update(Some(Box::new(iter.map(|p| p.title()))))?;
129
130        if navigation != PageNavigation::Update {
132            self.dispatch(navigation)?;
133        }
134
135        self.page.display(&mut self.display);
136        Ok(())
137    }
138
139    pub fn register(&mut self, page: Box<dyn PageInterface<D> + 'a>) {
148        self.push_left(page, None, None);
149        self.activate_left();
150    }
151
152    pub fn register_sub(&mut self, page: Box<dyn PageInterface<D> + 'a>) {
161        self.push_down(page, None, None);
162        self.activate_down();
163    }
164
165    pub fn register_startup(&mut self, page: Box<dyn PageInterface<D> + 'a>) {
174        self.startup = Some(page);
175    }
176
177    pub fn register_shutdown(&mut self, page: Box<dyn PageInterface<D> + 'a>) {
186        self.shutdown = Some(page);
187    }
188
189    fn push_left(
190        &mut self,
191        page: Box<dyn PageInterface<D> + 'a>,
192        up: Link<Box<dyn PageInterface<D> + 'a>>,
193        down: Link<Box<dyn PageInterface<D> + 'a>>,
194    ) {
195        let new_node = Box::new(Node {
196            page,
197            left: self.left.take(),
198            right: None,
199            down,
200            up,
201        });
202        self.left = Some(new_node);
203    }
204
205    fn push_right(
206        &mut self,
207        page: Box<dyn PageInterface<D> + 'a>,
208        up: Link<Box<dyn PageInterface<D> + 'a>>,
209        down: Link<Box<dyn PageInterface<D> + 'a>>,
210    ) {
211        let new_node = Box::new(Node {
212            page,
213            left: None,
214            right: self.right.take(),
215            up,
216            down,
217        });
218        self.right = Some(new_node);
219    }
220
221    fn pop_left(
222        &mut self,
223    ) -> Option<(
224        Box<dyn PageInterface<D> + 'a>,
225        Link<Box<dyn PageInterface<D> + 'a>>,
226        Link<Box<dyn PageInterface<D> + 'a>>,
227    )> {
228        self.left.take().map(|node| {
229            let mut node = node;
230            self.left = node.left;
231            (node.page, node.up.take(), node.down.take())
232        })
233    }
234
235    fn pop_right(
236        &mut self,
237    ) -> Option<(
238        Box<dyn PageInterface<D> + 'a>,
239        Link<Box<dyn PageInterface<D> + 'a>>,
240        Link<Box<dyn PageInterface<D> + 'a>>,
241    )> {
242        self.right.take().map(|node| {
243            let mut node = node;
244            self.right = node.right;
245            (node.page, node.up.take(), node.down.take())
246        })
247    }
248
249    fn activate_left(&mut self) -> bool {
252        match self.pop_left() {
253            None => false,
254            Some((page, up, down)) => {
255                let page = mem::replace(&mut self.page, page);
256                let new_up = self.up.take();
257                let new_down = self.down.take();
258                self.push_right(page, new_up, new_down);
259                self.up = up;
260                self.down = down;
261                true
262            }
263        }
264    }
265
266    fn activate_right(&mut self) -> bool {
269        match self.pop_right() {
270            None => false,
271            Some((page, up, down)) => {
272                let page = mem::replace(&mut self.page, page);
273                let new_up = self.up.take();
274                let new_down = self.down.take();
275                self.push_left(page, new_up, new_down);
276                self.up = up;
277                self.down = down;
278                true
279            }
280        }
281    }
282
283    fn activate_most_right(&mut self) {
284        while self.activate_right() {}
285    }
286
287    fn push_down(
288        &mut self,
289        page: Box<dyn PageInterface<D> + 'a>,
290        left: Link<Box<dyn PageInterface<D> + 'a>>,
291        right: Link<Box<dyn PageInterface<D> + 'a>>,
292    ) {
293        let new_node = Box::new(Node {
294            page,
295            up: None,
296            down: self.down.take(),
297            left,
298            right,
299        });
300        self.down = Some(new_node);
301    }
302
303    fn push_up(
304        &mut self,
305        page: Box<dyn PageInterface<D> + 'a>,
306        left: Link<Box<dyn PageInterface<D> + 'a>>,
307        right: Link<Box<dyn PageInterface<D> + 'a>>,
308    ) {
309        let new_node = Box::new(Node {
310            page,
311            up: self.up.take(),
312            down: None,
313            left,
314            right,
315        });
316        self.up = Some(new_node);
317    }
318
319    fn pop_down(
320        &mut self,
321    ) -> Option<(
322        Box<dyn PageInterface<D> + 'a>,
323        Link<Box<dyn PageInterface<D> + 'a>>,
324        Link<Box<dyn PageInterface<D> + 'a>>,
325    )> {
326        self.down.take().map(|node| {
327            let mut node = node;
328            self.down = node.down;
329            (node.page, node.left.take(), node.right.take())
330        })
331    }
332
333    fn pop_up(
334        &mut self,
335    ) -> Option<(
336        Box<dyn PageInterface<D> + 'a>,
337        Link<Box<dyn PageInterface<D> + 'a>>,
338        Link<Box<dyn PageInterface<D> + 'a>>,
339    )> {
340        self.up.take().map(|node| {
341            let mut node = node;
342            self.up = node.up;
343            (node.page, node.left.take(), node.right.take())
344        })
345    }
346
347    fn activate_down(&mut self) -> bool {
348        match self.pop_down() {
349            None => false,
350            Some((page, left, right)) => {
351                let page = mem::replace(&mut self.page, page);
352                let new_left = self.left.take();
353                let new_right = self.right.take();
354                self.push_up(page, new_left, new_right);
355                self.left = left;
356                self.right = right;
357                true
358            }
359        }
360    }
361
362    fn activate_up(&mut self) -> bool {
363        self.activate_most_right();
364        match self.pop_up() {
365            None => false,
366            Some((page, left, right)) => {
367                let page = mem::replace(&mut self.page, page);
368                let new_left = self.left.take();
369                let new_right = self.right.take();
370                self.push_down(page, new_left, new_right);
371                self.left = left;
372                self.right = right;
373                true
374            }
375        }
376    }
377
378    fn activate_home(&mut self) {
379        while self.activate_up() {}
380        self.activate_most_right();
381    }
382
383    pub fn dispatch_interaction(
393        &mut self,
394        interaction: Interaction,
395    ) -> Result<PageNavigation, PageError> {
396        let navigation = match self.state {
397            PageManagerState::Startup => match &mut self.startup {
398                None => self.page.dispatch(interaction),
399                Some(x) => x.dispatch(interaction),
400            },
401            PageManagerState::Operational => self.page.dispatch(interaction),
402            PageManagerState::Shutdown => match &mut self.shutdown {
403                None => self.page.dispatch(interaction),
404                Some(x) => x.dispatch(interaction),
405            },
406        };
407        self.dispatch(navigation)
408    }
409
410    pub fn dispatch(&mut self, navigation: PageNavigation) -> Result<PageNavigation, PageError> {
419        let mut navigation = navigation;
420        match navigation {
421            PageNavigation::SystemStart => {
422                self.activate_home(); match &mut self.startup {
424                    Some(page) => {
425                        navigation = page.update(None)?;
426                        page.display(&mut self.display);
427                    }
428                    None => (),
429                }
430            }
431            PageNavigation::SystemStop => match &mut self.shutdown {
432                Some(page) => {
433                    navigation = page.update(None)?;
434                    page.display(&mut self.display);
435                }
436                None => (),
437            },
438            PageNavigation::Left => {
439                if !self.activate_left() {
441                    self.activate_most_right();
442                }
443                self.update()?;
444                navigation = PageNavigation::Update;
445            }
446            PageNavigation::Right => {
447                self.activate_right();
448                self.update()?;
449                navigation = PageNavigation::Update;
450            }
451            PageNavigation::Home => {
452                self.activate_home();
453                self.update()?;
454                navigation = PageNavigation::Update;
455            }
456            PageNavigation::Up => {
457                self.activate_up();
458                self.update()?;
459                navigation = PageNavigation::Update;
460            }
461            PageNavigation::NthSubpage(index) => {
462                self.activate_down();
463                let mut index: usize = index;
464                while index > 1 {
465                    self.activate_left();
466                    index -= 1;
467                }
468                self.update()?;
469                navigation = PageNavigation::Update;
470            }
471            PageNavigation::Update => {
472                self.update()?;
473            }
474        };
475
476        match navigation {
478            PageNavigation::SystemStart => self.state = PageManagerState::Startup,
479            PageNavigation::SystemStop => self.state = PageManagerState::Shutdown,
480            _ => self.state = PageManagerState::Operational,
481        }
482
483        Ok(navigation)
484    }
485}
486
487impl<'a, D> Drop for PageManager<'a, D> {
488    fn drop(&mut self) {
490        let mut cur_horizontal = self.left.take();
492        while let Some(mut boxed_node) = cur_horizontal {
493            cur_horizontal = boxed_node.left.take();
494        }
495        let mut cur_horizontal = self.right.take();
497        while let Some(mut boxed_node) = cur_horizontal {
498            cur_horizontal = boxed_node.left.take();
499        }
500    }
501}
502
503pub struct SubPageIterator<'a, P> {
504    left: Option<&'a Node<P>>,
505}
506
507impl<'a, D> PageManager<'a, D> {
508    pub fn sub_iter(&self) -> SubPageIterator<Box<dyn PageInterface<D> + 'a>> {
509        SubPageIterator {
510            left: self.down.as_deref(),
511        }
512    }
513}
514
515impl<'a, D> Iterator for SubPageIterator<'a, Box<dyn PageInterface<D> + 'a>> {
516    type Item = &'a Box<dyn PageInterface<D> + 'a>;
517    fn next(&mut self) -> Option<Self::Item> {
518        self.left.map(|node| {
519            self.left = node.left.as_deref();
520            &node.page
521        })
522    }
523}
524
525#[cfg(test)]
526mod tests;