use std::collections::{BTreeMap, BTreeSet};
use crate::model::{Edge, EdgeId, Element, Model};
use crate::path::ElementPath;
#[derive(Clone, Debug, PartialEq)]
pub struct DisclosedModel {
model: Model,
closed_containers: BTreeSet<ElementPath>,
lifted_origins: BTreeMap<EdgeId, BTreeSet<EdgeId>>,
}
impl DisclosedModel {
pub fn every_layer_of(model: &Model) -> Vec<Self> {
let containers = model
.elements
.keys()
.filter(|path| model.is_container(path));
let container_depths = containers.map(ElementPath::depth);
let deepest_container_depth = container_depths.max().unwrap_or(0);
let layers = 0..=deepest_container_depth;
layers.map(|layer| Self::at_layer(model, layer)).collect()
}
fn at_layer(model: &Model, layer: usize) -> Self {
let deepest_shown_depth = layer + 1;
let shown_elements: BTreeMap<ElementPath, Element> = model
.elements
.iter()
.filter(|(path, _element)| path.depth() <= deepest_shown_depth)
.map(|(path, element)| {
let shown_path = path.clone();
let shown_element = element.clone();
(shown_path, shown_element)
})
.collect();
let closed_containers = shown_elements
.keys()
.filter(|path| {
let is_at_deepest_shown_depth = path.depth() == deepest_shown_depth;
let is_container = model.is_container(path);
is_at_deepest_shown_depth && is_container
})
.cloned()
.collect();
let title = model.title.clone();
let subtitle = model.subtitle.clone();
let view = model.view;
let description = model.description.clone();
let legend = model.legend.clone();
let edges = BTreeMap::new();
let mut disclosed_model = Model {
title,
subtitle,
view,
description,
legend,
elements: shown_elements,
edges,
};
let mut lifted_edges_by_shown_pair: BTreeMap<
(ElementPath, ElementPath),
Vec<(&EdgeId, &Edge)>,
> = BTreeMap::new();
for (id, edge) in &model.edges {
let from = id.from();
let to = id.to();
let shown_from = from.truncated_to_depth(deepest_shown_depth);
let shown_to = to.truncated_to_depth(deepest_shown_depth);
let is_from_shown = shown_from == *from;
let is_to_shown = shown_to == *to;
let is_between_shown_endpoints = is_from_shown && is_to_shown;
if is_between_shown_endpoints {
let shown_id = id.clone();
let shown_edge = edge.clone();
disclosed_model.edges.insert(shown_id, shown_edge);
continue;
}
let is_inside_one_shown_element = shown_from == shown_to;
if is_inside_one_shown_element {
continue;
}
let shown_pair = (shown_from, shown_to);
let lifted_edges = lifted_edges_by_shown_pair.entry(shown_pair).or_default();
lifted_edges.push((id, edge));
}
let mut lifted_origins = BTreeMap::new();
for ((shown_from, shown_to), lifted_edges) in lifted_edges_by_shown_pair {
let merged_edge = match lifted_edges.as_slice() {
[(only_id, only_edge)] => {
let mut lifted_edge = (*only_edge).clone();
let is_target_lifted = only_id.to() != &shown_to;
if is_target_lifted {
lifted_edge.badge = false;
}
lifted_edge
}
_several_edges => Edge::new(),
};
let merged_id = disclosed_model.insert_edge_with_next_free_ordinal(
shown_from,
shown_to,
merged_edge,
);
let origins = lifted_edges
.into_iter()
.map(|(id, _edge)| id.clone())
.collect();
lifted_origins.insert(merged_id, origins);
}
Self {
model: disclosed_model,
closed_containers,
lifted_origins,
}
}
pub fn model(&self) -> &Model {
&self.model
}
pub fn closed_containers(&self) -> &BTreeSet<ElementPath> {
&self.closed_containers
}
pub fn lifted_origins(&self) -> &BTreeMap<EdgeId, BTreeSet<EdgeId>> {
&self.lifted_origins
}
}