use std::collections::VecDeque;
use awint::awint_dag::triple_arena::{ptr_struct, Advancer, OrdArena};
use crate::ensemble::{Ensemble, PBack, PExternal, PLNode, PRNode, PTNode, Referent};
ptr_struct!(PRenderNode);
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum RenderNodeKind {
Equiv(PBack),
LNode(PLNode),
TNode(PTNode),
RNode(PRNode),
}
#[derive(Debug, Clone)]
pub struct RenderNode {
pub position: (i32, i32),
pub fixed: bool,
pub incidents: Vec<RenderNodeKind>,
}
pub type RenderArena = OrdArena<PRenderNode, RenderNodeKind, RenderNode>;
impl Ensemble {
pub fn debug_web<I: IntoIterator<Item = (PExternal, (i32, i32))>>(
&self,
fixed: I,
) -> RenderArena {
let mut map = OrdArena::new();
let mut front = VecDeque::new();
for (p_external, xy) in fixed.into_iter() {
let p_rnode = self.notary.get_rnode(p_external).unwrap().0;
let kind = RenderNodeKind::RNode(p_rnode);
front.push_back(kind);
let _ = map.insert(kind, RenderNode {
position: xy,
fixed: true,
incidents: vec![],
});
}
while let Some(kind) = front.pop_front() {
let mut edges = vec![];
match kind {
RenderNodeKind::Equiv(p_back) => {
let mut adv = self.backrefs.advancer_surject(p_back);
while let Some(p_ref) = adv.advance(&self.backrefs) {
match *self.backrefs.get_key(p_ref).unwrap() {
Referent::ThisEquiv => (),
Referent::ThisLNode(p_lnode) => {
edges.push(RenderNodeKind::LNode(p_lnode))
}
Referent::ThisTNode(p_tnode) => {
edges.push(RenderNodeKind::TNode(p_tnode))
}
Referent::ThisStateBit(..) => (),
Referent::Input(p_lnode) => edges.push(RenderNodeKind::LNode(p_lnode)),
Referent::Driver(p_tnode) => edges.push(RenderNodeKind::TNode(p_tnode)),
Referent::ThisRNode(p_rnode) => {
edges.push(RenderNodeKind::RNode(p_rnode))
}
}
}
}
RenderNodeKind::LNode(p_lnode) => {
let lnode = self.lnodes.get(p_lnode).unwrap();
edges.push(RenderNodeKind::Equiv(lnode.p_self));
lnode.inputs(|p| edges.push(RenderNodeKind::Equiv(p)));
}
RenderNodeKind::TNode(p_tnode) => {
let tnode = self.tnodes.get(p_tnode).unwrap();
edges.push(RenderNodeKind::Equiv(tnode.p_self));
edges.push(RenderNodeKind::Equiv(tnode.p_driver));
}
RenderNodeKind::RNode(p_rnode) => {
let rnode = self.notary.rnodes().get_val(p_rnode).unwrap();
if let Some(bits) = rnode.bits() {
for p in bits.iter().copied() {
if let Some(p) = p {
edges.push(RenderNodeKind::Equiv(p));
}
}
}
}
};
for edge in &mut edges {
if let RenderNodeKind::Equiv(p_back) = edge {
*p_back = self.backrefs.get_val(*p_back).unwrap().p_self_equiv;
}
}
let p = map.find_key(&kind).unwrap();
let position = map.get_val(p).unwrap().position;
for incident in edges {
if let Some(p) = map.find_key(&incident) {
map.get_val_mut(p).unwrap().incidents.push(kind);
} else {
let _ = map.insert(incident, RenderNode {
position,
fixed: false,
incidents: vec![kind],
});
front.push_back(incident);
}
}
}
for _ in 0..4 {
let mut adv = map.advancer();
while let Some(p0) = adv.advance(&map) {
let node = map.get_val(p0).unwrap();
if !(node.fixed || node.incidents.is_empty()) {
let mut sum = (0i64, 0i64);
for incident in &node.incidents {
let p1 = map.find_key(incident).unwrap();
let position = map.get_val(p1).unwrap().position;
sum.0 += i64::from(position.0);
sum.1 += i64::from(position.1);
}
let len = i64::try_from(node.incidents.len()).unwrap();
sum.0 /= len;
sum.1 /= len;
map.get_val_mut(p0).unwrap().position =
(i32::try_from(sum.0).unwrap(), i32::try_from(sum.1).unwrap());
}
}
}
map
}
}