//! Some generic traits for thealpha and  betanetwork are defined here.

use std::cell::RefMut;
use std::collections::VecDeque;
use std::fmt::Debug;
use std::rc::Rc;

use generational_arena::Arena;
use generational_indextree::{Arena as TreeArena, Node};

use phreak_facts::FactCore;

use crate::actions::{BetaNodeId, ScheduledAction, TokenId};
use crate::betanode::BetaNode;
use crate::nodes::alphanode::AlphaNode;
use crate::segment::Segment;
use crate::token::*;

/// Trait for nodes with delayed actions in a queue
pub(crate) trait ScheduledExecution {
    /// Add a new action to the queue of scheduled actions
    fn schedule_action(&self, priority: usize, action: ScheduledAction);
}

/// Same trait as ScheduledExecution, but at Cell level
pub(crate) trait ScheduledExecutionCell {
    /// Add a new action to the queue of scheduled actions
    fn schedule_action(&mut self, priority: usize, action: ScheduledAction);
    fn clear_scheduled_actions(&mut self);

    fn get_fields_mut(&mut self) -> (&[(usize, ScheduledAction)], &mut VecDeque<TokenId>);
}

/// This trait needs to be implemented by callbacks given to a production node
pub trait ProductionCallback: Debug {
    fn activate(&self);
    fn deactivate(&self);
}

/// A node is actionable if it knows how to handle ScheduledAction objects.
pub(crate) trait Actionable<C: ScheduledExecutionCell> {
    fn print_debug(&self,
                   action: &ScheduledAction,
                   self_id: BetaNodeId,
                   betanodes: &TreeArena<BetaNode>,
    );

    fn get_cell(&self) -> RefMut<C>;

    /// Message from alphamemory to a linked betanode that a new fact was inserted
    fn fact_inserted(&self,
                     priority: usize,
                     rc: &Rc<FactCore>,
                     self_id: BetaNodeId,
                     celltokens: &mut VecDeque<TokenId>,
                     betanodes: &TreeArena<BetaNode>,
                     segments: &TreeArena<Segment>,
                     tokens: &mut TreeArena<Token>,
                     pending: &[(usize, ScheduledAction)],
                     nil_fact: &Rc<FactCore>,
    );

    /// Message from an alphamemory to a linked betanode that a fact was removed
    fn fact_removed(&self,
                    priority: usize,
                    rc: &Rc<FactCore>,
                    self_id: BetaNodeId,
                    celltokens: &mut VecDeque<TokenId>,
                    betanodes: &TreeArena<BetaNode>,
                    tokens: &mut TreeArena<Token>,
                    segments: &TreeArena<Segment>,
                    pending: &[(usize, ScheduledAction)],
                    nil_fact: &Rc<FactCore>,
    );

    /// Message from a betanode that a new token was added to or activated in its storage
    fn parent_token_inserted(&self,
                             priority: usize,
                             token_id: TokenId,
                             self_id: BetaNodeId,
                             celltokens: &mut VecDeque<TokenId>,
                             betanodes: &TreeArena<BetaNode>,
                             segments: &TreeArena<Segment>,
                             tokens: &mut TreeArena<Token>,
                             alphanodes: &Arena<AlphaNode>,
                             pending: &[(usize, ScheduledAction)],
                             nil_fact: &Rc<FactCore>,
    );

    /// Message from a betanode that a token was removed from or deactivated in its storage
    fn parent_token_removed(&self,
                            priority: usize,
                            token_id: TokenId,
                            self_id: BetaNodeId,
                            celltokens: &mut VecDeque<TokenId>,
                            betanodes: &TreeArena<BetaNode>,
                            segments: &TreeArena<Segment>,
                            tokens: &mut TreeArena<Token>,
                            pending: &[(usize, ScheduledAction)],
                            nil_fact: &Rc<FactCore>,
    );

    /// A joinnode had made a match and notifies the child betanode
    fn insert_token(&self,
                    priority: usize,
                    token_id: TokenId,
                    self_id: BetaNodeId,
                    celltokens: &mut VecDeque<TokenId>,
                    betanodes: &TreeArena<BetaNode>,
                    segments: &TreeArena<Segment>,
                    tokens: &mut TreeArena<Token>,
                    pending: &[(usize, ScheduledAction)],
                    nil_fact: &Rc<FactCore>,
    );

    /// token parent_id has been removed from the memory and all it's children need to be
    /// removed as well
    fn delete_token_chain(&self,
                          priority: usize,
                          parent_id: TokenId,
                          sub_id: TokenId,
                          celltokens: &mut VecDeque<TokenId>,
                          betanodes: &TreeArena<BetaNode>,
                          tokens: &mut TreeArena<Token>,
                          pending: &[(usize, ScheduledAction)],
                          nil_fact: &Rc<FactCore>,
    );

    /// token token_id has become inactive and all it's children need to be removed
    fn delete_child_tokens(&self,
                           priority: usize,
                           token_id: TokenId,
                           self_id: BetaNodeId,
                           celltokens: &mut VecDeque<TokenId>,
                           tokens: &mut TreeArena<Token>,
                           betanodes: &TreeArena<BetaNode>,
                           pending: &[(usize, ScheduledAction)],
                           nil_fact: &Rc<FactCore>,
    );

    /// a token in an ncc node has become empty and will spawn child-tokens
    fn activate_token(&self,
                      _priority: usize,
                      _token_id: TokenId,
                      _self_id: BetaNodeId,
                      _celltokens: &mut VecDeque<TokenId>,
                      _tokens: &mut TreeArena<Token>,
                      _betanodes: &TreeArena<BetaNode>,
                      _pending: &[(usize, ScheduledAction)],
                      _nil_fact: &Rc<FactCore>,
    ) {
        unimplemented!()
    }

    fn init_new_node(&self,
                     self_id: BetaNodeId,
                     node: &Node<BetaNode>,
                     tokens: &mut TreeArena<Token>,
                     betanodes: &TreeArena<BetaNode>,
                     alphanodes: &Arena<AlphaNode>,
                     nil_fact: &Rc<FactCore>,
    );
}
