use serde::{Deserialize, Serialize};
use std::cmp::{Eq, PartialEq};
use std::collections::{HashMap, HashSet};
use std::fmt;
use std::fmt::Debug;
use super::{TreeId, TreeMeta, TreeNode};
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Tree<ID: TreeId, TM: TreeMeta> {
triples: HashMap<ID, TreeNode<ID, TM>>, children: HashMap<ID, HashSet<ID>>, }
impl<ID: TreeId, TM: TreeMeta> Tree<ID, TM> {
pub fn new() -> Self {
Self {
triples: HashMap::<ID, TreeNode<ID, TM>>::new(), children: HashMap::<ID, HashSet<ID>>::new(), }
}
pub fn rm_child(&mut self, child_id: &ID) {
let result = self.triples.get(child_id);
if let Some(t) = result {
if let Some(map) = self.children.get_mut(t.parent_id()) {
map.remove(child_id);
if map.is_empty() {
self.children.remove(t.parent_id());
}
}
self.triples.remove(child_id);
}
}
pub fn rm_subtree(&mut self, parent_id: &ID, include_parent: bool) {
for c in self.children(parent_id) {
self.rm_subtree(&c, false);
self.rm_child(&c);
}
if include_parent {
self.rm_child(parent_id)
}
}
pub fn add_node(&mut self, child_id: ID, tt: TreeNode<ID, TM>) {
if let Some(n) = self.children.get_mut(tt.parent_id()) {
n.insert(child_id.to_owned());
} else {
let mut h: HashSet<ID> = HashSet::new();
h.insert(child_id.to_owned());
self.children.insert(tt.parent_id().to_owned(), h);
}
self.triples.insert(child_id, tt);
}
pub fn find(&self, child_id: &ID) -> Option<&TreeNode<ID, TM>> {
self.triples.get(child_id)
}
pub fn children(&self, parent_id: &ID) -> Vec<ID> {
if let Some(list) = self.children.get(parent_id) {
list.iter().cloned().collect()
} else {
Vec::<ID>::default()
}
}
pub fn walk<F>(&self, parent_id: &ID, mut f: F)
where
F: FnMut(&Self, &ID, usize),
{
let mut stack: Vec<ID> = Vec::new();
stack.push(parent_id.clone());
while !stack.is_empty() {
if let Some(next) = stack.pop() {
f(self, &next, stack.len());
for child in self.children(&next) {
stack.push(child)
}
}
}
}
pub fn is_ancestor(&self, child_id: &ID, ancestor_id: &ID) -> bool {
let mut target_id = child_id;
while let Some(n) = self.find(target_id) {
if n.parent_id() == ancestor_id {
return true;
}
target_id = n.parent_id();
}
false
}
pub fn num_nodes(&self) -> usize {
self.triples.len()
}
}
impl<ID: TreeId, TM: TreeMeta> IntoIterator for Tree<ID, TM> {
type Item = (ID, TreeNode<ID, TM>);
type IntoIter = std::collections::hash_map::IntoIter<ID, TreeNode<ID, TM>>;
fn into_iter(self) -> Self::IntoIter {
self.triples.into_iter()
}
}
impl<ID: TreeId + Debug, TM: TreeMeta + Debug> fmt::Display for Tree<ID, TM> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.print_tree(f)
}
}
impl<ID: TreeId + Debug, TM: TreeMeta + Debug> Tree<ID, TM> {
fn print_treenode(
&self,
f: &mut fmt::Formatter<'_>,
node_id: &ID,
depth: usize,
) -> fmt::Result {
let findresult = self.find(node_id);
let meta = match findresult {
Some(tn) => format!("{:?} [{:?}]", node_id, tn.metadata()),
None => format!("{:?}", node_id),
};
let mut result = writeln!(f, "{:indent$}{}", "", meta, indent = depth * 2);
for c in self.children(node_id) {
result = self.print_treenode(f, &c, depth + 1);
if result.is_err() {
break;
}
}
result
}
fn print_tree(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut r: fmt::Result = Ok(());
let mut seen: HashSet<ID> = Default::default();
for treenode in self.triples.values() {
let p = treenode.parent_id();
if self.triples.get(p).is_none() && !seen.contains(p) {
seen.insert(p.clone());
r = self.print_treenode(f, p, 0);
if r.is_err() {
break;
}
}
}
r
}
}