#![no_std]

pub mod backoff;
pub mod events;
pub mod tasks;
pub mod ego;
pub mod animation;
pub mod idle;
pub mod logging;
pub mod graphics;

#[cfg(feature="simulation")]
pub mod storage;

#[cfg(feature="simulation")]
pub mod simdata;

extern crate alloc;

use core::{iter::Sum, ops::{Div, Sub}, fmt::Debug};

#[derive(Debug, Clone, Copy)]
pub struct CircularBuffer<T, const SIZE: usize = 20> {
    data: [T; SIZE],
    next_index: usize,
    filled: bool
}

impl<T: Default + Copy, const SIZE: usize> Default for CircularBuffer<T, SIZE> {
    fn default() -> Self {
        Self {
            data: [Default::default(); SIZE],
            next_index: 0,
            filled: false
        }
    }
}

impl<T, const SIZE: usize> CircularBuffer<T, SIZE> {
    pub fn insert(&mut self, value: T) {
        self.data[self.next_index] = value;
        self.next_index += 1;
        if self.next_index == self.data.len() {
            self.next_index = 0;
            self.filled = true;
        }
    }

    pub fn data(&self) -> &[T; SIZE] {
        &self.data
    }

    pub fn is_filled(&self) -> bool {
        self.filled
    }

    pub fn mean(&self) -> T where T: for<'a> Sum<&'a T> + Div<f32, Output = T> {
        self.data.iter().sum::<T>() / self.data.len() as f32
    }

    pub fn derivative(&self) -> T where for<'a> &'a T: Sub<&'a T, Output = T>, T: Sum<T> + Div<f32, Output = T> {
        self.data.windows(2).map(|n| {
            &n[0] - &n[1]
        }).sum::<T>().div(self.data.len() as f32)
    }
}

#[derive(Debug, Default)]
pub struct Breaker<T> {
    tripped: bool,
    value: T
}

impl<T: PartialEq + Copy + Debug> Breaker<T> {
    pub fn set(&mut self, value: T) {
        if self.value != value {
            self.value = value;
            self.tripped = true;
        }
    }

    pub fn read_tripped(&mut self) -> Option<T> {
        if self.tripped {
            //info!("Tripped: {self:?}");
            self.tripped = false;
            Some(self.value)
        } else {
            None
        }
    }
}