use super::*;
use core::mem;
pub struct PageManager<'a, D> {
display: D,
page: Box<dyn PageInterface<D> + 'a>,
left: Link<Box<dyn PageInterface<D> + 'a>>,
right: Link<Box<dyn PageInterface<D> + 'a>>,
up: Link<Box<dyn PageInterface<D> + 'a>>,
down: Link<Box<dyn PageInterface<D> + 'a>>,
startup: Option<Box<dyn PageInterface<D> + 'a>>,
shutdown: Option<Box<dyn PageInterface<D> + 'a>>,
state: PageManagerState,
}
type Link<T> = Option<Box<Node<T>>>;
struct Node<T> {
page: T,
left: Link<T>,
right: Link<T>,
down: Link<T>,
up: Link<T>,
}
enum PageManagerState {
Startup,
Operational,
Shutdown,
}
impl<'a, D> PageManager<'a, D> {
pub fn new(display: D, home: Box<dyn PageInterface<D> + 'a>) -> Self {
PageManager::<D> {
display,
page: home,
left: None,
right: None,
up: None,
down: None,
startup: None,
shutdown: None,
state: PageManagerState::Startup,
}
}
pub fn update(&mut self) -> Result<(), PageError> {
let iter = Box::new(SubPageIterator {
left: self.down.as_deref(),
});
let navigation = self.page.update(Some(Box::new(iter.map(|p| p.title()))))?;
if navigation != PageNavigation::Update {
self.dispatch(navigation)?;
}
self.page.display(&mut self.display);
Ok(())
}
pub fn register(&mut self, page: Box<dyn PageInterface<D> + 'a>) {
self.push_left(page, None, None);
self.activate_left();
}
pub fn register_sub(&mut self, page: Box<dyn PageInterface<D> + 'a>) {
self.push_down(page, None, None);
self.activate_down();
}
pub fn register_startup(&mut self, page: Box<dyn PageInterface<D> + 'a>) {
self.startup = Some(page);
}
pub fn register_shutdown(&mut self, page: Box<dyn PageInterface<D> + 'a>) {
self.shutdown = Some(page);
}
fn push_left(
&mut self,
page: Box<dyn PageInterface<D> + 'a>,
up: Link<Box<dyn PageInterface<D> + 'a>>,
down: Link<Box<dyn PageInterface<D> + 'a>>,
) {
let new_node = Box::new(Node {
page,
left: self.left.take(),
right: None,
down,
up,
});
self.left = Some(new_node);
}
fn push_right(
&mut self,
page: Box<dyn PageInterface<D> + 'a>,
up: Link<Box<dyn PageInterface<D> + 'a>>,
down: Link<Box<dyn PageInterface<D> + 'a>>,
) {
let new_node = Box::new(Node {
page,
left: None,
right: self.right.take(),
up,
down,
});
self.right = Some(new_node);
}
fn pop_left(
&mut self,
) -> Option<(
Box<dyn PageInterface<D> + 'a>,
Link<Box<dyn PageInterface<D> + 'a>>,
Link<Box<dyn PageInterface<D> + 'a>>,
)> {
self.left.take().map(|node| {
let mut node = node;
self.left = node.left;
(node.page, node.up.take(), node.down.take())
})
}
fn pop_right(
&mut self,
) -> Option<(
Box<dyn PageInterface<D> + 'a>,
Link<Box<dyn PageInterface<D> + 'a>>,
Link<Box<dyn PageInterface<D> + 'a>>,
)> {
self.right.take().map(|node| {
let mut node = node;
self.right = node.right;
(node.page, node.up.take(), node.down.take())
})
}
fn activate_left(&mut self) -> bool {
match self.pop_left() {
None => false,
Some((page, up, down)) => {
let page = mem::replace(&mut self.page, page);
let new_up = self.up.take();
let new_down = self.down.take();
self.push_right(page, new_up, new_down);
self.up = up;
self.down = down;
true
}
}
}
fn activate_right(&mut self) -> bool {
match self.pop_right() {
None => false,
Some((page, up, down)) => {
let page = mem::replace(&mut self.page, page);
let new_up = self.up.take();
let new_down = self.down.take();
self.push_left(page, new_up, new_down);
self.up = up;
self.down = down;
true
}
}
}
fn activate_most_right(&mut self) {
while self.activate_right() {}
}
fn push_down(
&mut self,
page: Box<dyn PageInterface<D> + 'a>,
left: Link<Box<dyn PageInterface<D> + 'a>>,
right: Link<Box<dyn PageInterface<D> + 'a>>,
) {
let new_node = Box::new(Node {
page,
up: None,
down: self.down.take(),
left,
right,
});
self.down = Some(new_node);
}
fn push_up(
&mut self,
page: Box<dyn PageInterface<D> + 'a>,
left: Link<Box<dyn PageInterface<D> + 'a>>,
right: Link<Box<dyn PageInterface<D> + 'a>>,
) {
let new_node = Box::new(Node {
page,
up: self.up.take(),
down: None,
left,
right,
});
self.up = Some(new_node);
}
fn pop_down(
&mut self,
) -> Option<(
Box<dyn PageInterface<D> + 'a>,
Link<Box<dyn PageInterface<D> + 'a>>,
Link<Box<dyn PageInterface<D> + 'a>>,
)> {
self.down.take().map(|node| {
let mut node = node;
self.down = node.down;
(node.page, node.left.take(), node.right.take())
})
}
fn pop_up(
&mut self,
) -> Option<(
Box<dyn PageInterface<D> + 'a>,
Link<Box<dyn PageInterface<D> + 'a>>,
Link<Box<dyn PageInterface<D> + 'a>>,
)> {
self.up.take().map(|node| {
let mut node = node;
self.up = node.up;
(node.page, node.left.take(), node.right.take())
})
}
fn activate_down(&mut self) -> bool {
match self.pop_down() {
None => false,
Some((page, left, right)) => {
let page = mem::replace(&mut self.page, page);
let new_left = self.left.take();
let new_right = self.right.take();
self.push_up(page, new_left, new_right);
self.left = left;
self.right = right;
true
}
}
}
fn activate_up(&mut self) -> bool {
self.activate_most_right();
match self.pop_up() {
None => false,
Some((page, left, right)) => {
let page = mem::replace(&mut self.page, page);
let new_left = self.left.take();
let new_right = self.right.take();
self.push_down(page, new_left, new_right);
self.left = left;
self.right = right;
true
}
}
}
fn activate_home(&mut self) {
while self.activate_up() {}
self.activate_most_right();
}
pub fn dispatch_interaction(
&mut self,
interaction: Interaction,
) -> Result<PageNavigation, PageError> {
let navigation = match self.state {
PageManagerState::Startup => match &mut self.startup {
None => self.page.dispatch(interaction),
Some(x) => x.dispatch(interaction),
},
PageManagerState::Operational => self.page.dispatch(interaction),
PageManagerState::Shutdown => match &mut self.shutdown {
None => self.page.dispatch(interaction),
Some(x) => x.dispatch(interaction),
},
};
self.dispatch(navigation)
}
pub fn dispatch(&mut self, navigation: PageNavigation) -> Result<PageNavigation, PageError> {
let mut navigation = navigation;
match navigation {
PageNavigation::SystemStart => {
self.activate_home(); match &mut self.startup {
Some(page) => {
navigation = page.update(None)?;
page.display(&mut self.display);
}
None => (),
}
}
PageNavigation::SystemStop => match &mut self.shutdown {
Some(page) => {
navigation = page.update(None)?;
page.display(&mut self.display);
}
None => (),
},
PageNavigation::Left => {
if !self.activate_left() {
self.activate_most_right();
}
self.update()?;
navigation = PageNavigation::Update;
}
PageNavigation::Right => {
self.activate_right();
self.update()?;
navigation = PageNavigation::Update;
}
PageNavigation::Home => {
self.activate_home();
self.update()?;
navigation = PageNavigation::Update;
}
PageNavigation::Up => {
self.activate_up();
self.update()?;
navigation = PageNavigation::Update;
}
PageNavigation::NthSubpage(index) => {
self.activate_down();
let mut index: usize = index;
while index > 1 {
self.activate_left();
index -= 1;
}
self.update()?;
navigation = PageNavigation::Update;
}
PageNavigation::Update => {
self.update()?;
}
};
match navigation {
PageNavigation::SystemStart => self.state = PageManagerState::Startup,
PageNavigation::SystemStop => self.state = PageManagerState::Shutdown,
_ => self.state = PageManagerState::Operational,
}
Ok(navigation)
}
}
impl<'a, D> Drop for PageManager<'a, D> {
fn drop(&mut self) {
let mut cur_horizontal = self.left.take();
while let Some(mut boxed_node) = cur_horizontal {
cur_horizontal = boxed_node.left.take();
}
let mut cur_horizontal = self.right.take();
while let Some(mut boxed_node) = cur_horizontal {
cur_horizontal = boxed_node.left.take();
}
}
}
pub struct SubPageIterator<'a, P> {
left: Option<&'a Node<P>>,
}
impl<'a, D> PageManager<'a, D> {
pub fn sub_iter(&self) -> SubPageIterator<Box<dyn PageInterface<D> + 'a>> {
SubPageIterator {
left: self.down.as_deref(),
}
}
}
impl<'a, D> Iterator for SubPageIterator<'a, Box<dyn PageInterface<D> + 'a>> {
type Item = &'a Box<dyn PageInterface<D> + 'a>;
fn next(&mut self) -> Option<Self::Item> {
self.left.map(|node| {
self.left = node.left.as_deref();
&node.page
})
}
}
#[cfg(test)]
mod tests;