use super::messages::{Kind, Pair};
use crate::layout::PlacedNode;
use crate::layout::prim;
use std::collections::HashMap;
const BAR_W: f64 = 12.0;
const NEST_DX: f64 = 4.0;
pub(super) struct Bar {
participant: String,
open_row: usize,
close_row: usize,
depth: usize,
}
pub(super) fn bars(pairs: &[Pair]) -> Vec<Bar> {
let mut open: HashMap<&str, Vec<usize>> = HashMap::new();
let mut bars: Vec<Bar> = Vec::new();
for (row, p) in pairs.iter().enumerate() {
match p.kind() {
Kind::Call => {
let stack = open.entry(p.to).or_default();
bars.push(Bar {
participant: p.to.to_string(),
open_row: row,
close_row: pairs.len(),
depth: stack.len(),
});
stack.push(bars.len() - 1);
}
Kind::Return => {
if let Some(idx) = open.get_mut(p.from).and_then(Vec::pop) {
bars[idx].close_row = row;
}
}
Kind::Async | Kind::Self_ => {}
}
}
bars
}
pub(super) fn edge(
bars: &[Bar],
id: &str,
row: usize,
lifeline_cx: f64,
toward: f64,
) -> Option<f64> {
let bar = bars
.iter()
.filter(|b| b.participant == id && b.open_row <= row && row <= b.close_row)
.max_by_key(|b| b.depth)?;
let bar_cx = lifeline_cx + bar.depth as f64 * NEST_DX;
let half = BAR_W / 2.0;
Some(if toward < bar_cx {
bar_cx - half
} else {
bar_cx + half
})
}
pub(super) fn draw(
bars: &[Bar],
lifeline_x: &HashMap<String, f64>,
row_y: impl Fn(usize) -> f64,
paint: &HashMap<String, super::Apparatus>,
) -> Vec<PlacedNode> {
bars.iter()
.filter_map(|b| {
let cx = lifeline_x.get(&b.participant)? + b.depth as f64 * NEST_DX;
let a = paint.get(&b.participant)?;
let (top, bot) = (row_y(b.open_row), row_y(b.close_row));
let mut bar = prim::rect(
cx,
(top + bot) / 2.0,
BAR_W,
(bot - top).max(1.0),
a.fill.clone(),
1.0,
);
prim::outline(&mut bar, a.stroke.clone(), a.width);
Some(bar)
})
.collect()
}