/*
    Appellation: features <module>
    Contrib: @FL03
*/
use eryon::prelude::{DecrementMut, IncrementMut};

/// Represents a topological feature that persists across transformations
#[derive(Clone, Debug, PartialEq, PartialOrd)]
#[cfg_attr(
    feature = "serde",
    derive(serde_derive::Deserialize, serde_derive::Serialize)
)]
pub struct PersistentFeature<T = f32> {
    pub(crate) id: usize,
    pub(crate) birth: usize,
    pub(crate) content: Vec<usize>,
    pub(crate) death: Option<usize>,
    pub(crate) dimension: usize,
    pub(crate) importance: T,
    pub(crate) occurrences: usize,
}

impl<T> PersistentFeature<T> {
    pub fn from_parts(
        id: usize,
        birth: usize,
        content: Vec<usize>,
        dimension: usize,
        importance: T,
    ) -> Self {
        Self {
            id,
            birth,
            content: Vec::from_iter(content),
            death: None,
            dimension,
            importance,
            occurrences: 1,
        }
    }
    gsw! {
        id: usize,
        birth: usize,
        dimension: usize,
        occurrences: usize,
    }
    gsw! {
        importance: &T,
    }
    /// returns an immutable reference to the features content
    pub const fn content(&self) -> &Vec<usize> {
        &self.content
    }
    /// returns a mutable reference to the feature's content
    pub fn content_mut(&mut self) -> &mut Vec<usize> {
        &mut self.content
    }
    /// get the death time of this feature; None if still active
    pub const fn death(&self) -> Option<usize> {
        self.death
    }
    /// set the content of the feature
    pub fn set_content<I>(&mut self, content: I)
    where
        I: IntoIterator<Item = usize>,
    {
        self.content = Vec::from_iter(content);
    }
    /// set the death of the feature
    pub fn set_death(&mut self, death: usize) {
        self.death = Some(death);
    }
    /// consumes the current instance to create another with the given content
    pub fn with_content<I>(self, iter: I) -> Self
    where
        I: IntoIterator<Item = usize>,
    {
        Self {
            content: Vec::from_iter(iter),
            ..self
        }
    }
    /// consumes the current instance to create another with the given death time
    pub fn with_death(self, death: Option<usize>) -> Self {
        Self { death, ..self }
    }
    /// check if the feature contains a given content
    pub fn contains(&self, content: &usize) -> bool {
        self.content.contains(content)
    }
    /// check if the feature does not have a death time
    pub fn is_alive(&self) -> bool {
        self.death.is_none()
    }
    /// check if a feature has died
    pub fn is_dead(&self) -> bool {
        self.death.is_some()
    }
    /// returns the number of elements in the content
    pub fn content_len(&self) -> usize {
        self.content.len()
    }
    /// decrement the number of occurrences
    pub fn decrement_occurrences(&mut self) {
        self.occurrences_mut().decrement_mut()
    }
    /// Increment the occurrence count
    pub fn increment_occurrences(&mut self) {
        self.occurrences_mut().increment_mut();
    }
}

impl core::ops::Index<usize> for PersistentFeature {
    type Output = usize;

    fn index(&self, index: usize) -> &Self::Output {
        &self.content[index]
    }
}

impl core::ops::IndexMut<usize> for PersistentFeature {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        &mut self.content[index]
    }
}
