use std::collections::HashSet;
use crate::{graph::FlowGraph, types::path::Path};
pub(crate) fn mermaid_graph(graph: &FlowGraph, path: Option<&Path>) -> String {
let mut edge_ids_to_color: Vec<usize> = Vec::new();
let mut number_of_links = 0;
let mut reverse_edges_in_path = HashSet::new();
let mut delegations_in_path = HashSet::new();
if let Some(path) = &path {
delegations_in_path = path
.edges
.iter()
.filter_map(|edge| {
let delegation = edge.delegation()?;
Some((delegation.issuer().clone(), delegation.target().clone()))
})
.collect();
reverse_edges_in_path = path
.edges
.iter()
.filter_map(|edge| {
let reverse_edge = edge.reverse()?;
Some((reverse_edge.issuer.clone(), reverse_edge.target.clone()))
})
.collect();
}
let mut checked_nodes = HashSet::new();
let mut out: String = "flowchart TD\n".into();
for certification in &graph.target_node().certifications {
out.push_str(&format!(
" {} ==> binding\n",
&certification.inner.issuer
));
if let Some(path) = &path
&& *certification == path.certification
{
edge_ids_to_color.push(number_of_links);
}
number_of_links += 1;
}
out.push_str(&format!(
" binding([{}, {}])\n",
&graph.target_node().binding.cert,
&graph
.target_node()
.binding
.identity
.to_string()
.replace("<", "")
.replace(">", "")
.replace("@", "\\@")
.replace("(", "_")
.replace(")", "_")
.replace("\"", "'")
));
out.push('\n');
for node in graph.nodes().values() {
if !checked_nodes.contains(&node.id) {
if graph.trust_anchors().contains_key(&node.id) {
out.push_str(&format!(
" {}@{{ shape: diamond, label: \"{}(t:{})\" }}\n",
&node.id,
&node.id,
node.available_amount()
));
} else {
out.push_str(&format!(
" {}@{{ shape: rounded, label: \"{}(t:{})\" }}\n",
&node.id,
&node.id,
node.available_amount()
));
}
checked_nodes.insert(node.id.clone());
}
for delegation in &node.delegations {
let regexes = if !delegation.regexes().is_empty() {
let mut regexes = delegation
.regexes()
.iter()
.map(|r| {
r.to_string()
.strip_prefix("<[^>]+[@.]")
.unwrap()
.strip_suffix(">$")
.unwrap()
.replace("\\", "")
})
.collect::<Vec<_>>()
.join(",");
regexes.insert(0, '/');
regexes
} else {
"".to_string()
};
out.push_str(&format!(
" {} -->|t:{} d:{}{}| {}\n",
delegation.issuer(),
delegation.trust_amount(),
u8::from(delegation.trust_depth()),
regexes,
delegation.target(),
));
if delegations_in_path
.contains(&(delegation.issuer().clone(), delegation.target().clone()))
{
edge_ids_to_color.push(number_of_links);
}
number_of_links += 1;
}
for reverse_edge in &node.reverse_edges {
out.push_str(&format!(
" {} -.->|t:{} d:{}| {}\n",
&reverse_edge.issuer,
reverse_edge.trust_amount,
u8::from(reverse_edge.trust_depth),
&reverse_edge.target,
));
if reverse_edges_in_path
.contains(&(reverse_edge.issuer.clone(), reverse_edge.target.clone()))
{
edge_ids_to_color.push(number_of_links);
}
number_of_links += 1;
}
}
out.push('\n');
for id in edge_ids_to_color {
out.push_str(&format!(
"linkStyle {id} stroke:#e74c3c,stroke-width:1px;\n"
));
}
out
}