use crate::visualize::Visualize;
use id_tree::{NodeId, Tree};
use std::collections::{BTreeMap, HashMap};
pub type Embedding = Vec<PlacedTreeItem>;
#[derive(Debug, Clone, Default)]
pub struct PlacedTreeItem {
pub y_order: usize,
pub x_center: usize,
pub x_extent: usize,
pub x_extent_children: usize,
pub text: String,
pub is_emphasized: bool,
pub parent: Option<usize>,
pub ord: usize,
}
impl From<ItemEmbeddingData> for PlacedTreeItem {
fn from(e: ItemEmbeddingData) -> Self {
Self {
y_order: e.y_order,
x_center: e.x_center,
x_extent: e.x_extent,
x_extent_children: e.x_extent_children,
text: e.text,
is_emphasized: e.is_emphasized,
parent: e.parent,
ord: e.ord,
}
}
}
#[derive(Debug, Clone, Default)]
struct ItemEmbeddingData {
y_order: usize,
x_center: usize,
x_extent: usize,
x_extent_of_children: usize,
x_extent_children: usize,
text: String,
is_emphasized: bool,
parent: Option<usize>,
ord: usize,
node_id: Option<NodeId>,
}
struct EmbeddingHelperData(BTreeMap<usize, ItemEmbeddingData>, HashMap<NodeId, usize>);
impl EmbeddingHelperData {
fn new() -> Self {
Self(BTreeMap::new(), HashMap::new())
}
fn get_by_ord(&self, ord: usize) -> Option<&ItemEmbeddingData> {
self.0.get(&ord)
}
fn get_mut_by_ord(&mut self, ord: usize) -> Option<&mut ItemEmbeddingData> {
self.0.get_mut(&ord)
}
fn get_by_node_id(&self, node_id: &NodeId) -> Option<&ItemEmbeddingData> {
self.1.get(node_id).and_then(|n| self.0.get(n))
}
fn get_mut_by_node_id(&mut self, node_id: &NodeId) -> Option<&mut ItemEmbeddingData> {
let ord = self.1.get(node_id).cloned();
ord.and_then(move |n| self.0.get_mut(&n))
}
fn insert(&mut self, ord: usize, item: ItemEmbeddingData) {
item.node_id.as_ref().map(|n| self.1.insert(n.clone(), ord));
self.0.insert(ord, item);
}
}
pub struct Embedder<T>
where
T: Visualize,
{
_1: std::marker::PhantomData<T>,
}
impl<T> Embedder<T>
where
T: Visualize,
{
pub fn embed(tree: &Tree<T>) -> Embedding {
let mut items = Self::create_initial_embedding_data(tree);
debug_assert_eq!(items.0.len(), items.1.len());
Self::apply_y_order(tree, &mut items);
Self::apply_x_center(tree, &mut items);
Self::transfer_result(items)
}
fn create_initial_embedding_data(tree: &Tree<T>) -> EmbeddingHelperData {
fn create_from_node<T: Visualize>(
node_id: &NodeId,
ord: usize,
tree: &Tree<T>,
items: &EmbeddingHelperData,
) -> ItemEmbeddingData {
let node = tree.get(node_id).unwrap();
let text = node.data().visualize();
let y_order = 0;
let x_center = 0;
let x_extent = text.len() + 1;
let x_extent_of_children = node.children().iter().fold(0, |acc, child_node_id| {
if let Some(placed_item) = items.get_by_node_id(child_node_id) {
acc + placed_item.x_extent_children
} else {
panic!("Child node should have already visited!");
}
});
let x_extent_children = std::cmp::max(x_extent, x_extent_of_children);
let is_emphasized = node.data().emphasize();
let parent = None;
let node_id = Some(node_id.clone());
ItemEmbeddingData {
y_order,
x_center,
x_extent,
x_extent_of_children,
x_extent_children,
text,
is_emphasized,
parent,
ord,
node_id,
}
}
let mut items = EmbeddingHelperData::new();
if let Some(root_node_id) = tree.root_node_id() {
for (ord, node_id) in tree
.traverse_post_order_ids(root_node_id)
.unwrap()
.enumerate()
{
let new_item = create_from_node(&node_id, ord, tree, &items);
items.insert(ord, new_item);
}
}
items
}
fn apply_y_order(tree: &Tree<T>, items: &mut EmbeddingHelperData) {
if let Some(root_node_id) = tree.root_node_id() {
for node_id in tree.traverse_pre_order_ids(root_node_id).unwrap() {
let level = tree.ancestor_ids(&node_id).unwrap().count();
let parent = tree
.ancestor_ids(&node_id)
.unwrap()
.next()
.map(|id| items.get_by_node_id(id).unwrap().ord);
let item = items.get_mut_by_node_id(&node_id).unwrap();
item.y_order = level;
item.parent = parent;
}
};
}
fn apply_x_center(tree: &Tree<T>, items: &mut EmbeddingHelperData) {
fn x_center_layer(layer: usize, items: &mut EmbeddingHelperData) {
let node_ids_in_layer = items.0.iter().fold(Vec::new(), |mut acc, (ord, item)| {
if item.y_order == layer {
acc.push(*ord)
}
acc
});
let parents_in_layer = node_ids_in_layer
.iter()
.map(|ord| items.get_by_ord(*ord).unwrap().parent)
.collect::<Vec<Option<usize>>>();
for p in parents_in_layer {
let nodes_in_layer_per_parent = node_ids_in_layer
.iter()
.filter_map(|ord| {
if items.get_by_ord(*ord).unwrap().parent == p {
Some(*ord)
} else {
None
}
})
.collect::<Vec<usize>>();
let mut moving_x_center = {
if let Some(parent_ord) = p {
if let Some(placed_parent_item) = items.get_by_ord(parent_ord) {
placed_parent_item.x_center
- placed_parent_item.x_extent_of_children / 2
} else {
panic!("Some item expected here!")
}
} else {
debug_assert_eq!(layer, 0);
debug_assert_eq!(node_ids_in_layer.len(), 1);
0
}
};
for ord in nodes_in_layer_per_parent {
if let Some(placed_item) = items.get_mut_by_ord(ord) {
placed_item.x_center = moving_x_center + placed_item.x_extent_children / 2;
moving_x_center += placed_item.x_extent_children;
}
}
}
}
for l in 0..tree.height() + 1 {
x_center_layer(l, items);
}
}
fn transfer_result(items: EmbeddingHelperData) -> Embedding {
let len = items.0.len();
items
.0
.into_iter()
.fold(Embedding::with_capacity(len), |mut acc, e| {
acc.push(e.1.into());
acc
})
}
}