extern crate alloc;
use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use crate::kairos::Kairos;
use crate::metis::{Anchor, DotStore, Locus, Rhapsody};
use super::Dot;
pub(super) fn reference_order(rhapsody: &Rhapsody) -> Vec<Dot> {
enum Frame {
Visit(Dot),
Emit(Dot),
}
let mut loci: BTreeMap<Dot, Locus> = BTreeMap::new();
let mut frontier: Vec<Dot> = rhapsody.dots().collect();
while let Some(dot) = frontier.pop() {
if loci.contains_key(&dot) {
continue;
}
if let Some(locus) = rhapsody.locus(dot) {
let _ = loci.insert(dot, locus);
if let Some(Ok(anchor)) = locus.anchor.dot().map(Dot::try_from) {
frontier.push(anchor);
}
}
}
let mut children: BTreeMap<Anchor, Vec<Dot>> = BTreeMap::new();
for (&dot, locus) in &loci {
children.entry(locus.anchor).or_default().push(dot);
}
for bucket in children.values_mut() {
bucket.sort_by(|a, b| {
let (ra, rb): (Kairos, Kairos) = (loci[a].rank, loci[b].rank);
rb.cmp(&ra).then_with(|| a.cmp(b))
});
}
let mut order = Vec::new();
let mut stack: Vec<Frame> = children
.get(&Anchor::Origin)
.map(|roots| roots.iter().rev().map(|&d| Frame::Visit(d)).collect())
.unwrap_or_default();
while let Some(frame) = stack.pop() {
match frame {
Frame::Emit(dot) => {
if rhapsody.is_visible(dot) {
order.push(dot);
}
}
Frame::Visit(dot) => {
if let Some(kids) = children.get(&Anchor::After(dot.into())) {
for &kid in kids.iter().rev() {
stack.push(Frame::Visit(kid));
}
}
stack.push(Frame::Emit(dot));
if let Some(kids) = children.get(&Anchor::Before(dot.into())) {
for &kid in kids {
stack.push(Frame::Visit(kid));
}
}
}
}
}
order
}