#![cfg_attr(not(feature = "std"), no_std)]
#![forbid(
    unsafe_code,
    clippy::cast_ptr_alignment,
    trivial_casts,
    unconditional_recursion
)]

extern crate alloc;
use alloc::{string::String, vec, vec::Vec};

mod serial;
pub use serial::Error as ParseError;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PackList {
    pub name: String,
    pub items: Vec<Item>,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Item {
    pub det: Option<ItemDetails>,
    pub text: String,
}

/// packlist item details
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ItemDetails {
    pub markers: Vec<Spaced<[char; 2]>>,
    pub multiplier: Option<Spaced<u32>>,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Spaced<T> {
    pub val: T,
    // white space folloing the value
    pub space: String,
}

impl Default for ItemDetails {
    fn default() -> Self {
        Self {
            markers: vec![Spaced {
                val: [' ', ' '],
                space: String::new(),
            }],
            multiplier: None,
        }
    }
}

pub trait Commands {
    fn reset_markers(&mut self);
}

pub mod prelude {
    pub use crate::Commands as _;
}

impl Commands for PackList {
    fn reset_markers(&mut self) {
        self.items.iter_mut().for_each(|i| i.reset_markers());
    }
}

impl Commands for Item {
    fn reset_markers(&mut self) {
        if let Some(x) = &mut self.det {
            x.reset_markers();
        }
    }
}

impl Commands for ItemDetails {
    fn reset_markers(&mut self) {
        self.markers.iter_mut().for_each(|i| i.val = [' ', ' ']);
    }
}