use graphlib_rust::Graph;
use ordered_hashmap::OrderedHashMap;
use crate::{GraphConfig, GraphEdge, GraphNode};
use crate::layout::order::barycenter::Barycenter;
#[derive(Debug, Clone)]
pub struct ResolvedBaryEntry {
pub indegree: i32,
pub _in: Vec<ResolvedBaryEntry>,
pub _out: Vec<ResolvedBaryEntry>,
pub vs: Vec<String>,
pub i: usize,
pub barycenter: Option<f32>,
pub weight: Option<f32>,
pub merged: Option<bool>
}
pub fn resolve_conflicts (entries: &Vec<Barycenter>, cg: &Graph<GraphConfig, GraphNode, GraphEdge>) -> Vec<ResolvedBaryEntry> {
let mut mapped_entries: OrderedHashMap<String, ResolvedBaryEntry> = OrderedHashMap::new();
for (i, entry) in entries.iter().enumerate() {
let mut mapped_entry = ResolvedBaryEntry {
indegree: 0,
_in: vec![],
_out: vec![],
vs: vec![entry.v.clone()],
i,
barycenter: None,
weight: None,
merged: None,
};
if mapped_entry.barycenter.is_some() {
mapped_entry.barycenter = entry.barycenter.clone();
mapped_entry.weight = entry.weight.clone();
}
mapped_entries.insert(entry.v.clone(), mapped_entry);
}
cg.edges().iter().for_each(|e| {
let entry_v_ = mapped_entries.get(&e.v);
let entry_w_ = mapped_entries.get(&e.w).cloned();
if entry_v_.is_some() && entry_w_.is_some() {
if let Some(entry_w) = mapped_entries.get_mut(&e.w) {
entry_w.indegree += 1;
}
if let Some(entry_v) = mapped_entries.get_mut(&e.v) {
entry_v._out.push(entry_w_.clone().unwrap());
}
}
});
let mut source_set: Vec<ResolvedBaryEntry> = mapped_entries.values().filter(|entry| {
entry.indegree == 0
}).cloned().collect();
return do_resolve_conflicts(&mut source_set);
}
fn do_resolve_conflicts(source_set: &mut Vec<ResolvedBaryEntry>) -> Vec<ResolvedBaryEntry> {
let mut entries: Vec<ResolvedBaryEntry> = vec![];
let mut source_hash: OrderedHashMap<usize, ResolvedBaryEntry> = OrderedHashMap::new();
source_set.iter().for_each(|entry| {
source_hash.insert(entry.i.clone(), entry.clone());
});
fn handle_in(v_idx: &usize, u_idx: &usize, source_hash: &mut OrderedHashMap<usize, ResolvedBaryEntry>) {
let v_entry = source_hash.get(v_idx).unwrap();
let u_entry = source_hash.get(u_idx).unwrap();
if u_entry.merged.is_some() {
return ();
}
if u_entry.barycenter.is_none()
|| v_entry.barycenter.is_none()
|| u_entry.barycenter.clone().unwrap_or(0.0) >= v_entry.barycenter.clone().unwrap_or(0.0) {
merge_entries(v_idx, u_idx, source_hash);
}
}
fn handle_out(v_idx: &usize, w_idx: &usize, source_hash: &mut OrderedHashMap<usize, ResolvedBaryEntry>, source_set: &mut Vec<ResolvedBaryEntry>) {
let v_entry = source_hash.get(v_idx).cloned().unwrap();
let w_entry = source_hash.get_mut(w_idx).unwrap();
w_entry._in.push(v_entry);
w_entry.indegree -= 1;
if w_entry.indegree == 0 {
source_set.push(w_entry.clone());
}
}
while source_set.len() > 0 {
let entry_ = source_set.pop().unwrap();
let entry = source_hash.get(&entry_.i).unwrap();
let _in = entry._in.clone();
let out = entry_._out.clone();
_in.iter().rev().for_each(|u_entry| {
handle_in(&entry_.i, &u_entry.i, &mut source_hash);
});
out.iter().for_each(|w_entry| {
handle_out(&entry_.i, &w_entry.i, &mut source_hash, source_set);
});
entries.push(source_hash.get(&entry_.i).cloned().unwrap());
}
return entries.into_iter().filter(|entry| {
!entry.merged.clone().unwrap_or(false)
}).collect();
}
fn merge_entries(target_idx: &usize, source_idx: &usize, source_hash: &mut OrderedHashMap<usize, ResolvedBaryEntry>) {
let mut sum = 0.0;
let mut weight = 0.0;
let target_ = source_hash.get(target_idx).cloned().unwrap();
if target_.weight.is_some() {
let target_weight = target_.weight.clone().unwrap_or(0.0);
let target_barycenter = target_.barycenter.clone().unwrap_or(0.0);
sum += target_barycenter * target_weight;
weight += target_weight;
}
let source_ = source_hash.get(source_idx).cloned().unwrap();
if source_.weight.is_some() {
let source_weight = source_.weight.clone().unwrap_or(0.0);
let source_barycenter = source_.barycenter.clone().unwrap_or(0.0);
sum += source_barycenter * source_weight;
weight += source_weight;
}
let mut target_vs = source_.vs.clone();
target_vs.append(&mut target_.vs.clone());
let target = source_hash.get_mut(target_idx).unwrap();
target.vs = target_vs;
target.barycenter = Some(sum / weight);
target.weight = Some(weight);
target.i = std::cmp::min(source_.i.clone(), target_.i.clone());
let source = source_hash.get_mut(source_idx).unwrap();
source.merged = Some(true);
}