use crate::{
error::BehaviorTreeError,
schema::{Expression, Node, NodeParameterId},
setup_node_parameter_variable,
variable::{VariableCell, VariableResolver},
BehaviorTree,
};
use std::{cell::RefCell, collections::HashMap, rc::Rc};
use uuid::Uuid;
pub struct TreeNode {
pub function: Uuid,
pub children: Option<Vec<TreeNode>>,
pub parameters: HashMap<Uuid, Expression>,
}
#[allow(unused)]
impl TreeNode {
pub fn action_node(function: Uuid) -> Self {
Self {
function,
children: None,
parameters: HashMap::new(),
}
}
pub fn control_node(function: Uuid, children: Vec<TreeNode>) -> Self {
Self {
function,
children: Some(children),
parameters: HashMap::new(),
}
}
pub fn collect(
self,
mut node_index: &mut HashMap<Uuid, Rc<Node>>,
mut variables: &mut HashMap<Uuid, VariableCell>,
mut node_parameters_variables: &mut HashMap<NodeParameterId, VariableCell>,
resolver: &VariableResolver,
names: &HashMap<Uuid, String>,
) -> Result<Rc<Node>, BehaviorTreeError> {
let node_id = Uuid::new_v4();
let children: Option<Vec<Uuid>> = if let Some(children) = self.children {
let mut ids = Vec::with_capacity(children.len());
for child in children {
let child_node = child.collect(
node_index,
variables,
node_parameters_variables,
resolver,
names,
)?;
let child_node_id = child_node.id;
assert_eq!(node_index.insert(child_node.id, child_node), None);
ids.push(child_node_id);
}
Some(ids)
} else {
None
};
let mut arguments = HashMap::new();
for (param_id, expression) in self.parameters {
let node_parameter = NodeParameterId {
node: node_id.to_owned(),
parameter: param_id.to_owned(),
};
setup_node_parameter_variable(
&node_parameter,
&expression,
variables,
node_parameters_variables,
resolver,
names,
)?;
arguments.insert(param_id, expression);
}
Ok(Rc::new(Node {
id: node_id,
function: self.function,
arguments,
children,
}))
}
pub fn into_behavior_tree(
self,
resolver: &VariableResolver,
names: &HashMap<Uuid, String>,
) -> Result<BehaviorTree, BehaviorTreeError> {
let mut node_index = HashMap::new();
let mut variables = HashMap::new();
let mut node_arg_variables = HashMap::new();
let root = self.collect(
&mut node_index,
&mut variables,
&mut node_arg_variables,
resolver,
names,
)?;
Ok(BehaviorTree {
root,
node_index,
variables: Rc::new(RefCell::new(variables)),
node_arg_variables: Rc::new(node_arg_variables),
})
}
}
impl TryInto<BehaviorTree> for TreeNode {
type Error = BehaviorTreeError;
fn try_into(self) -> Result<BehaviorTree, Self::Error> {
self.into_behavior_tree(&|_| None, &HashMap::new())
}
}