/*
    Appellation: memory <module>
    Contrib: @FL03
*/

mod impl_store;

use crate::core::LearnedRule;
use crate::features::{FeaturePattern, FeatureRelationship, PersistentFeature};
use std::collections::{HashMap, HashSet};

/// Memory system based on persistent homology
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(
    feature = "serde",
    derive(serde_derive::Deserialize, serde_derive::Serialize)
)]
pub struct TopologicalMemory {
    /// Collection of persistent features
    pub(crate) features: Vec<PersistentFeature>,
    /// Relationships between features
    pub(crate) relationships: Vec<FeatureRelationship>,
    /// a cache of learned rules for the driver
    pub(crate) rulespace: Vec<LearnedRule>,
    /// Recognized patterns
    pub(crate) patterns: Vec<FeaturePattern>,
    /// Properties of the memory store
    pub(crate) properties: HashMap<String, String>,
    /// Current time counter
    pub(crate) epoch: usize,
    /// Features indexed by dimension for quick access
    pub(crate) dimension_index: HashMap<usize, HashSet<usize>>,
    /// Features indexed by content
    pub(crate) content_index: HashMap<Vec<usize>, HashSet<usize>>,
    /// Features indexed by importance (bucketed)
    pub(crate) importance_index: HashMap<usize, HashSet<usize>>,
    /// Next feature ID
    pub(crate) next_id: usize,
    /// Next pattern ID
    pub(crate) next_pattern_id: usize,
}

impl TopologicalMemory {
    pub fn new() -> Self {
        TopologicalMemory {
            features: Vec::new(),

            relationships: Vec::new(),
            rulespace: Vec::new(),
            patterns: Vec::new(),
            properties: HashMap::new(),
            epoch: 0,
            dimension_index: HashMap::new(),
            content_index: HashMap::new(),
            importance_index: HashMap::new(),
            next_id: 0,
            next_pattern_id: 0,
        }
    }
    /// returns a copy of the internal time
    pub fn current_epoch(&self) -> usize {
        self.epoch
    }
    /// returns a reference to the features of the system
    pub const fn features(&self) -> &Vec<PersistentFeature> {
        &self.features
    }
    /// returns a mutable reference to the features of the system
    pub fn features_mut(&mut self) -> &mut Vec<PersistentFeature> {
        &mut self.features
    }
    /// returns the number of features in the system
    pub fn feature_count(&self) -> usize {
        self.features.len()
    }
    /// returns an immutable reference to the memory patterns
    pub const fn patterns(&self) -> &Vec<FeaturePattern> {
        &self.patterns
    }
    /// returns a mutable reference to the memory patterns
    pub fn patterns_mut(&mut self) -> &mut Vec<FeaturePattern> {
        &mut self.patterns
    }
    /// returns an immutable reference to the properties of the memory store
    pub const fn properties(&self) -> &HashMap<String, String> {
        &self.properties
    }
    /// returns a mutable reference to the properties of the memory store
    pub fn properties_mut(&mut self) -> &mut HashMap<String, String> {
        &mut self.properties
    }
    /// returns a reference to the relationships of the system
    pub const fn relationships(&self) -> &Vec<FeatureRelationship> {
        &self.relationships
    }
    /// returns a mutable reference to the relationships of the system
    pub fn relationships_mut(&mut self) -> &mut Vec<FeatureRelationship> {
        &mut self.relationships
    }
    /// returns an immutable reference to the learned rulespace
    pub const fn rulespace(&self) -> &Vec<LearnedRule> {
        &self.rulespace
    }
    /// returns a mutable reference to the memoized rulespace
    pub fn rulespace_mut(&mut self) -> &mut Vec<LearnedRule> {
        &mut self.rulespace
    }
    /// returns the total number of features
    pub fn features_count(&self) -> usize {
        self.features.len()
    }
    /// returns the number of patterns
    pub fn pattern_count(&self) -> usize {
        self.patterns.len()
    }
    /// returns the number of relationships
    pub fn relationship_count(&self) -> usize {
        self.relationships.len()
    }
    /// Get a float property, parsing from string
    pub fn get_property_float(&self, key: &str) -> Option<f32> {
        self.properties.get(key).and_then(|v| v.parse::<f32>().ok())
    }
    /// increment the current epoch
    pub fn next_epoch(&mut self) {
        self.epoch += 1;
    }
    /// Set a property in the memory store
    pub fn set_property(&mut self, key: &str, value: &str) {
        self.properties.insert(key.to_string(), value.to_string());
    }
}
