use ahash::HashMap;
use super::{CTreeNode, CTreeNodeID, ControlNode, ControlTree};
use crate::prelude::*;
impl<D: Decorator + From<StandardDecorator>> ControlTree<D> {
pub fn add_subtree_as_last_child(&mut self, from: CTreeNodeID, subtree: impl Into<Self>) {
self.add_subtree_with_priority(from, usize::MAX, subtree)
}
pub fn add_subtree_as_first_child(&mut self, from: CTreeNodeID, subtree: impl Into<Self>) {
self.add_subtree_with_priority(from, 0, subtree)
}
pub fn add_subtree_with_priority(
&mut self,
from: CTreeNodeID,
priority: usize,
subtree: impl Into<Self>,
) {
let subtree_root =
self.add_floating_node(ControlNode::decorator(StandardDecorator::subtree()));
let siblings = self.tree.entry(from).or_default();
let index = priority.min(siblings.len());
siblings.insert(index, subtree_root);
let ControlTree { nodes, tree } = subtree.into();
let mut old_to_new = HashMap::default();
nodes.into_iter().filter(|n| !n.is_root()).for_each(|node| {
let old_id = node.id().unwrap();
let new_id = self.add_floating_node(node);
old_to_new.insert(old_id, new_id);
});
tree.into_iter()
.filter(|(p, _)| old_to_new.contains_key(p)) .for_each(|(old_parent, children)| {
let new_children = children
.into_iter()
.flat_map(|old_child| old_to_new.get(&old_child));
self.tree
.entry(old_parent)
.or_default()
.extend(new_children);
});
}
}
impl<D: Decorator> ControlTree<D> {
pub fn add_child(
&mut self,
parent_id: CTreeNodeID,
child: impl Into<CTreeNode<D>>,
) -> ShrubberyResult<CTreeNodeID> {
self.add_child_with_priority(parent_id, child, usize::MAX)
}
pub fn add_child_with_priority(
&mut self,
parent_id: CTreeNodeID,
child: impl Into<CTreeNode<D>>,
priority: usize,
) -> ShrubberyResult<CTreeNodeID> {
let id = self.add_child_unchecked_with_priority(parent_id, child, priority);
self.recurse_children_check_cycles(parent_id, vec![])
.map(|_| id)
.map_err(|e| {
self.remove(id);
e
})
}
pub(crate) fn add_child_unchecked(
&mut self,
parent_id: CTreeNodeID,
child: impl Into<CTreeNode<D>>,
) -> CTreeNodeID {
self.add_child_unchecked_with_priority(parent_id, child, usize::MAX)
}
pub(crate) fn add_child_unchecked_with_priority(
&mut self,
parent_id: CTreeNodeID,
child: impl Into<CTreeNode<D>>,
priority: usize,
) -> CTreeNodeID {
let mut child = child.into();
let id: CTreeNodeID = if let Some(id) = child.id() {
id
} else {
self.nodes.len().into()
};
child.set_id(id);
self.nodes.insert(id.0, child);
let siblings = self.tree.entry(parent_id).or_default();
let index = priority.min(siblings.len());
siblings.insert(index, id);
self.tree.entry(id).or_default();
id
}
pub fn remove(&mut self, id: CTreeNodeID) {
self.tree.values_mut().for_each(|v| v.retain(|c| c != &id));
self.tree.remove(&id);
}
}