use std::collections::{HashMap, HashSet};
use std::time::{ Duration, Instant };
use crate::traits::{ node::Node, node_tree::NodeTree, node_getter::NodeGetter, instanceable::Instanceable };
use super::logger::*;
use super::node_base::NodeStatus;
use super::rid::{ RID, RIDHolder };
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ProcessMode {
Inherit,
Always,
Pausable,
Inverse,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TreeStatus {
Process(TreeProcess),
QueuedTermination(TreeProcess),
Terminating,
Terminated
}
impl TreeStatus {
pub fn is_active(&self) -> bool {
match self {
Self::Terminated => false,
_ => true
}
}
pub fn has_terminated(&self) -> bool {
match self {
Self::Terminated => true,
_ => false
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TreeProcess {
Running,
Paused
}
#[derive(Debug, Clone)]
pub enum NodeIdentity {
UniqueName(String),
NodePath
}
impl NodeIdentity {
pub fn does_not_match(&self, name: &str) -> bool {
match self {
Self::UniqueName(this_name) => this_name != name,
Self::NodePath => true
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TerminationReason {
TreeExit,
RemovedAsChild,
Freed
}
#[derive(Debug)]
pub struct NodeTreeBase {
logger: Logger,
nodes: RIDHolder<*mut dyn Node>,
identity: HashMap<RID, NodeIdentity>,
singletons: HashMap<String, RID>,
status: TreeStatus,
last_frame: Instant
}
impl NodeTreeBase {
const ROOT_RID: RID = 0;
unsafe fn new(logger_verbosity: LoggerVerbosity) -> Self {
let nodes: RIDHolder<*mut dyn Node> = RIDHolder::new();
let node_tree: NodeTreeBase = NodeTreeBase {
logger: Logger::new(logger_verbosity),
nodes,
identity: HashMap::new(),
singletons: HashMap::new(),
status: TreeStatus::Process(TreeProcess::Running),
last_frame: Instant::now()
};
node_tree
}
unsafe fn initialize<I: Instanceable>(&mut self, outer: *mut dyn NodeTree, scene: I) {
let mut initialization_history: Vec<RID> = Vec::new();
scene.iterate(|parent, node, is_owner| {
if let Some(parent) = parent {
let parent: &mut dyn Node = unsafe { &mut *parent };
let rid: RID = unsafe { parent.add_child_from_ptr(node, is_owner, true) };
initialization_history.push(rid);
} else {
self.identity.insert(Self::ROOT_RID, NodeIdentity::NodePath);
initialization_history.push(Self::ROOT_RID);
let root: &mut dyn Node = unsafe { &mut *node };
unsafe {
root.set_rid(Self::ROOT_RID);
root.set_owner(Self::ROOT_RID);
root.set_tree(outer);
}
self.logger.post_manual(
SystemCall::Named("NodeTree".to_string()),
Log::Debug(&format!(
"Node \"{}\" added to the scene as the root of the NodeTree! Unique ID of \"{}\" generated!",
root.name(), root.rid()
)));
self.nodes.push(node);
}
});
for rid in initialization_history.into_iter().rev() {
let node: &mut dyn Node = unsafe { self.get_node_mut(rid).unwrap_unchecked() };
if node.has_just_loaded() {
node.loaded();
unsafe {
node.mark_as_final();
}
}
node.ready();
}
}
pub fn process(&mut self) -> TreeStatus {
if !self.status.is_active() {
return self.status;
}
let now: Instant = Instant::now();
let elapsed: Duration = now.duration_since(self.last_frame);
let delta: f32 = elapsed.as_secs_f32();
self.last_frame = now;
for node in self.get_nodes_mut(&self.root().top_down(true)) {
unsafe {
node.unwrap_unchecked().set_status(NodeStatus::Normal);
}
}
self.process_tail(Self::ROOT_RID, delta, ProcessMode::Pausable);
match self.status {
TreeStatus::QueuedTermination(_) => self.status = TreeStatus::Terminating,
TreeStatus::Terminating => self.status = TreeStatus::Terminated,
_ => ()
}
self.status
}
pub fn root(&self) -> &dyn Node {
unsafe {
&**self.nodes.retrieve(Self::ROOT_RID).unwrap_unchecked()
}
}
pub fn root_mut(&mut self) -> &mut dyn Node {
unsafe {
&mut **self.nodes.modify(Self::ROOT_RID).unwrap_unchecked()
}
}
pub fn get_node_raw(&self, rid: RID) -> Option<*const dyn Node> {
self.nodes.retrieve(rid).map(|node| *node as *const dyn Node)
}
pub fn get_node(&self, rid: RID) -> Option<&dyn Node> {
self.nodes.retrieve(rid).map(|node| unsafe { &**node })
}
pub fn get_nodes(&self, rids: &[RID]) -> Vec<Option<&dyn Node>> {
rids.iter()
.map(|rid| self.nodes.retrieve(*rid).map(|node| unsafe { &**node })).collect::<Vec<_>>()
}
pub fn get_all_valid_nodes(&self, rids: &[RID]) -> Vec<&dyn Node> {
rids.iter()
.filter_map(|rid| self.nodes.retrieve(*rid).map(|node| unsafe { &**node })).collect::<Vec<_>>()
}
pub fn get_node_mut_raw(&self, rid: RID) -> Option<*mut dyn Node> {
self.nodes.retrieve(rid).copied()
}
pub fn get_node_mut(&mut self, rid: RID) -> Option<&mut dyn Node> {
self.nodes.modify(rid).map(|node| unsafe { &mut **node })
}
pub fn get_nodes_mut(&mut self, rids: &[RID]) -> Vec<Option<&mut dyn Node>> {
if rids.len() != rids.iter().collect::<HashSet<_>>().len() {
panic!("Duplicate RIDs found!");
}
rids.iter()
.map(|rid| self.nodes.retrieve(*rid).map(|node| unsafe { &mut **node })).collect::<Vec<_>>()
}
pub fn get_all_valid_nodes_mut(&mut self, rids: &[RID]) -> Vec<&mut dyn Node> {
if rids.len() != rids.iter().collect::<HashSet<_>>().len() {
panic!("Duplicate RIDs found!");
}
rids.iter()
.filter_map(|rid| self.nodes.retrieve(*rid).map(|node| unsafe { &mut **node })).collect::<Vec<_>>()
}
pub fn queue_termination(&mut self) {
match self.status {
TreeStatus::Process(process) => self.status = TreeStatus::QueuedTermination(process),
_ => ()
}
}
pub fn terminate(&mut self) {
self.status = TreeStatus::Terminated;
}
fn process_tail(&mut self, node_rid: RID, delta: f32, inherited_process_mode: ProcessMode) {
let status: TreeStatus = self.status;
let node: &mut dyn Node = self.get_node_mut(node_rid).unwrap();
let mut process_mode: ProcessMode = node.process_mode();
if process_mode == ProcessMode::Inherit {
process_mode = inherited_process_mode;
}
match status {
TreeStatus::Process(process) | TreeStatus::QueuedTermination(process) => {
match process {
TreeProcess::Running => {
match process_mode {
ProcessMode::Inherit => panic!("Inherited process mode not set!"),
ProcessMode::Always => node.process(delta),
ProcessMode::Pausable => node.process(delta),
ProcessMode::Inverse => ()
}
},
TreeProcess::Paused => {
match process_mode {
ProcessMode::Inherit => panic!("Inherited process mode not set!"),
ProcessMode::Always => node.process(delta),
ProcessMode::Pausable => (),
ProcessMode::Inverse => node.process(delta)
}
}
}
}
TreeStatus::Terminating => node.terminal(TerminationReason::TreeExit),
TreeStatus::Terminated => ()
}
for child_node in node.children().into_iter().map(|c| c.rid()).collect::<Vec<_>>() {
self.process_tail(child_node, delta, process_mode);
if self.status == TreeStatus::Terminated {
break;
}
}
}
pub unsafe fn register_node(&mut self, node: *mut dyn Node) -> RID {
let rid: RID = self.nodes.push(node);
self.identity.insert(rid, NodeIdentity::NodePath);
rid
}
pub unsafe fn unregister_node(&mut self, rid: RID) -> Option<Box<dyn Node>> {
let mut singleton_name: Option<String> = None;
for (name, singleton_rid) in &self.singletons {
if *singleton_rid == rid {
singleton_name = Some(name.to_string());
}
}
if let Some(singleton_name) = singleton_name {
self.singletons.remove(&singleton_name);
}
let node: Option<*mut dyn Node> = self.nodes.take(rid);
self.identity.remove(&rid);
node.map(|ptr| unsafe {
Box::from_raw(ptr)
})
}
pub fn register_as_singleton(&mut self, rid: RID, name: String) -> Option<bool> {
self.nodes.retrieve(rid)?;
if !self.identity.values().all(|x| x.does_not_match(&name)) {
return Some(false);
}
self.identity.insert(rid, NodeIdentity::UniqueName(name.clone()));
self.singletons.insert(name, rid);
Some(true)
}
pub fn get_node_rid<P: NodeGetter>(&self, absolute_path: P, caller: Option<RID>) -> Option<RID> {
absolute_path.get_from(self, caller)
}
pub fn get_node_identity(&self, rid: RID) -> Option<NodeIdentity> {
self.identity.get(&rid).map(|identity| identity.to_owned())
}
pub fn set_default_header_on_panic(&mut self, msg: &str) {
self.logger.set_default_header_on_panic(msg);
}
pub fn set_default_footer_on_panic(&mut self, msg: &str) {
self.logger.set_default_footer_on_panic(msg);
}
pub fn post(&mut self, calling: RID, log: Log) {
let ptr: *mut NodeTreeBase = self;
unsafe {
if self.logger.post(calling, log, ptr) {
self.terminate();
}
}
}
pub fn get_log(&self) -> &str {
self.logger.to_str()
}
}
impl <'a> NodeGetter for &'a str {
fn get_from(&self, tree: &NodeTreeBase, caller: Option<RID>) -> Option<RID> {
self.to_string().get_from(tree, caller)
}
}
impl NodeGetter for String {
fn get_from(&self, tree: &NodeTreeBase, _caller: Option<RID>) -> Option<RID> {
tree.singletons.get(self).copied()
}
}
pub fn initialize_base<T: NodeTree, I: Instanceable>(tree: &mut Box<T>, scene: I, verbosity: LoggerVerbosity) {
let base: NodeTreeBase = unsafe { NodeTreeBase::new(verbosity) };
unsafe {
tree.set_base(base);
let tree_ptr: *mut dyn NodeTree = tree.as_dyn_raw_mut();
tree.base_mut().initialize(tree_ptr, scene);
}
}