use graphlib_rust::Graph;
use graphlib_rust::graph::GRAPH_NODE;
use ordered_hashmap::OrderedHashMap;
use crate::{GraphConfig, GraphEdge, GraphNode};
pub fn parent_dummy_chains(g: &mut Graph<GraphConfig, GraphNode, GraphEdge>) {
let post_order_nums: OrderedHashMap<String, (i32, i32)> = postorder(g);
let dummy_chains = g.graph().dummy_chains.clone().unwrap_or(vec![]);
let empty_string = "".to_string();
let empty_node = GraphNode::default();
for v_ in dummy_chains.iter() {
let mut v = v_.clone();
let mut node = g.node(&v).unwrap();
let edge_obj = node.edge_obj.clone().unwrap();
let path_data = find_path(g, &post_order_nums, &edge_obj.v, &edge_obj.w);
let path = path_data.0;
let lca = &path_data.1;
let mut path_idx = 0;
if path.len() == 0 {
continue;
}
let mut path_v = path.get(path_idx).unwrap();
let mut ascending = true;
while v != edge_obj.w {
node = g.node(&v).unwrap();
if ascending {
path_v = path.get(path_idx).unwrap_or(lca);
while
path_v != lca &&
g.node(path_v).unwrap_or(&empty_node).max_rank.clone().unwrap_or(0) < node.rank.clone().unwrap_or(0) {
path_idx += 1;
if let Some(path_v_) = path.get(path_idx) {
path_v = path_v_;
} else {
break;
}
}
if path_v == lca {
ascending = false
}
}
if !ascending {
path_v = path.get(path_idx + 1).unwrap_or(&empty_string);
while path_idx < path.len() - 1 &&
g.node(path_v).unwrap().min_rank.clone().unwrap_or(0) <= node.rank.clone().unwrap_or(0) {
path_idx += 1;
path_v = path.get(path_idx + 1).unwrap_or(&empty_string);
}
}
let _ = g.set_parent(&v, Some(path_v.clone()));
v = g.successors(&v).unwrap_or(vec![]).get(0).unwrap_or(&empty_string).clone();
}
}
}
fn find_path(g: &Graph<GraphConfig, GraphNode, GraphEdge>, post_order_nums: &OrderedHashMap<String, (i32, i32)>, v: &String, w: &String) -> (Vec<String>, String) {
let mut v_path: Vec<String> = vec![];
let mut w_path: Vec<String> = vec![];
let v_post_order_num = post_order_nums.get(v).cloned().unwrap_or((0, 0));
let w_post_order_num = post_order_nums.get(w).cloned().unwrap_or((0, 0));
let low = std::cmp::min(v_post_order_num.0, w_post_order_num.0);
let lim = std::cmp::min(v_post_order_num.1, w_post_order_num.1);
let mut _parent = v;
while let Some(parent) = g.parent(_parent) {
_parent = parent;
v_path.push(parent.clone());
if let Some(post_order_num) = post_order_nums.get(parent) {
if post_order_num.0 <= low && lim <= post_order_num.1 {
break;
}
} else {
break;
}
}
let lca = _parent;
let mut parent = g.parent(w).unwrap_or(lca);
while parent != lca {
w_path.push(parent.clone());
parent = g.parent(parent).unwrap_or(lca);
}
w_path.reverse();
v_path.append(&mut w_path);
return (v_path, lca.clone());
}
fn postorder(g: &Graph<GraphConfig, GraphNode, GraphEdge>) -> OrderedHashMap<String, (i32, i32)> {
let mut result: OrderedHashMap<String, (i32, i32)> = OrderedHashMap::new();
let mut lim = 0;
fn dfs(v: &String, g: &Graph<GraphConfig, GraphNode, GraphEdge>, lim: &mut i32, result: &mut OrderedHashMap<String, (i32, i32)>) {
let low = lim.clone();
g.children(&v).iter().for_each(|v_| {
dfs(v_, g, lim, result);
});
result.insert(v.clone(), (low, lim.clone()));
*lim += 1;
}
g.children(&GRAPH_NODE.to_string()).iter().for_each(|v| {
dfs(v, g, &mut lim, &mut result);
});
return result;
}