use graphlib_rust::Graph;
use ordered_hashmap::OrderedHashMap;
use crate::{GraphConfig, GraphEdge, GraphNode};
use crate::layout::order::barycenter::{barycenter, Barycenter};
use crate::layout::order::resolve_conflicts::{resolve_conflicts, ResolvedBaryEntry};
use crate::layout::order::sort::sort;
#[derive(Debug, Clone, Default)]
pub struct SubgraphResult {
pub vs: Vec<String>,
pub barycenter: f32,
pub weight: f32
}
pub fn sort_subgraph(
g: &Graph<GraphConfig, GraphNode, GraphEdge>,
v: &String,
cg: &Graph<GraphConfig, GraphNode,GraphEdge>,
bias_right: &bool
) -> SubgraphResult {
let mut movable = g.children(v);
let node = g.node(v);
let bl = if node.is_some() {
node.unwrap().border_left_.clone()
} else {
None
};
let br = if node.is_some() {
node.unwrap().border_right_.clone()
} else {
None
};
let mut subgraphs: OrderedHashMap<String, SubgraphResult> = OrderedHashMap::new();
if br.is_some() {
movable = movable.into_iter().filter(|w| {
w != &bl.clone().unwrap() && w != &br.clone().unwrap()
}).collect();
}
let mut barycenters = barycenter(g, &movable);
barycenters.iter_mut().for_each(|entry| {
if g.children(&entry.v).len() > 0 {
let subgraph_result = sort_subgraph(g, &entry.v, cg, bias_right);
subgraphs.insert(entry.v.clone(), subgraph_result.clone());
merge_barycenters(entry, &subgraph_result);
}
});
let mut entries = resolve_conflicts(&barycenters, cg);
expand_subgraphs(&mut entries, &subgraphs);
let mut result = sort(&entries, bias_right);
if bl.is_some() {
let bl_ = bl.clone().unwrap();
let br_ = br.clone().unwrap();
result.vs = vec![vec![bl_.clone()], result.vs.clone(), vec![br_.clone()]].concat();
let bl_preds = g.predecessors(&bl_).unwrap_or(vec![]);
if bl_preds.len() > 0 {
let bl_pred = g.node(bl_preds.first().unwrap()).unwrap();
let br_pred = g.node(g.predecessors(&br_).unwrap_or(vec![]).first().unwrap()).unwrap();
let bl_pred_order = bl_pred.order.clone().unwrap_or(0) as f32;
let br_pred_order = br_pred.order.clone().unwrap_or(0) as f32;
result.barycenter =
( result.barycenter * result.weight + bl_pred_order + br_pred_order ) / (result.weight + 2.0);
result.weight += 2.0;
}
}
return result;
}
fn expand_subgraphs(entries: &mut Vec<ResolvedBaryEntry>, subgraphs: &OrderedHashMap<String, SubgraphResult>) {
entries.iter_mut().for_each(|entry| {
let mut vs: Vec<String> = vec![];
entry.vs.iter().for_each(|v| {
if subgraphs.contains_key(v) {
let subgraph = subgraphs.get(v).unwrap();
subgraph.vs.iter().for_each(|v_| {
vs.push(v_.clone());
});
return ();
}
vs.push(v.clone());
});
entry.vs = vs;
});
}
fn merge_barycenters(target: &mut Barycenter, other: &SubgraphResult) {
let target_barycenter = target.barycenter.clone().unwrap_or(0.0);
if target.barycenter.is_some() && target_barycenter > 0.0 {
let target_weight = target.weight.clone().unwrap_or(0.0);
target.barycenter = Some(
(target_barycenter * target_weight + other.barycenter * other.weight)
/ (target_weight + other.weight)
);
target.weight = Some(target_weight + other.weight.clone());
} else {
target.barycenter = Some(other.barycenter.clone());
target.weight = Some(other.weight.clone());
}
}