use super::*;
pub(super) fn state_is_hidden(ctx: &StateRenderCtx<'_>, id: &str) -> bool {
ctx.hidden_prefixes
.iter()
.any(|p| id == p || id.starts_with(&format!("{p}----")))
}
pub(super) fn state_strip_note_group<'a>(
ctx: &'a StateRenderCtx<'_>,
mut parent: Option<&'a str>,
) -> Option<&'a str> {
while let Some(pid) = parent {
let Some(pn) = ctx.nodes_by_id.get(pid).copied() else {
return Some(pid);
};
if pn.shape == "noteGroup" {
parent = ctx.parent.get(pid).copied();
continue;
}
return Some(pid);
}
None
}
pub(super) fn state_leaf_context_raw<'a>(ctx: &'a StateRenderCtx<'_>, id: &str) -> Option<&'a str> {
let mut p = ctx.parent.get(id).copied();
loop {
let pid = state_strip_note_group(ctx, p)?;
let Some(pn) = ctx.nodes_by_id.get(pid).copied() else {
return Some(pid);
};
if pn.is_group && pn.shape != "noteGroup" {
return Some(pid);
}
p = ctx.parent.get(pid).copied();
}
}
pub(super) fn state_insertion_context_raw<'a>(
ctx: &'a StateRenderCtx<'_>,
cluster_id: &str,
) -> Option<&'a str> {
state_leaf_context_raw(ctx, cluster_id)
}
pub(super) fn state_endpoint_context_raw<'a>(
ctx: &'a StateRenderCtx<'_>,
id: &str,
) -> Option<&'a str> {
if let Some(n) = ctx.nodes_by_id.get(id).copied() {
if n.is_group && n.shape != "noteGroup" {
return state_insertion_context_raw(ctx, id);
}
}
state_leaf_context_raw(ctx, id)
}
pub(super) fn state_context_chain_raw<'a>(
ctx: &'a StateRenderCtx<'_>,
mut c: Option<&'a str>,
) -> Vec<Option<&'a str>> {
let mut out = Vec::new();
loop {
out.push(c);
let Some(id) = c else {
break;
};
c = state_insertion_context_raw(ctx, id);
}
out
}
pub(super) fn state_edge_context_raw<'a>(
ctx: &'a StateRenderCtx<'_>,
edge: &StateSvgEdge,
) -> Option<&'a str> {
let a = state_endpoint_context_raw(ctx, edge.start.as_str());
let b = state_endpoint_context_raw(ctx, edge.end.as_str());
let ca = state_context_chain_raw(ctx, a);
let cb = state_context_chain_raw(ctx, b);
for anc in cb {
if ca.contains(&anc) {
return anc;
}
}
None
}
pub(super) fn state_leaf_context<'a>(ctx: &'a StateRenderCtx<'_>, id: &str) -> Option<&'a str> {
let mut p = ctx.parent.get(id).copied();
loop {
let pid = state_strip_note_group(ctx, p)?;
let Some(pn) = ctx.nodes_by_id.get(pid).copied() else {
return Some(pid);
};
if pn.is_group && pn.shape != "noteGroup" {
if ctx.nested_roots.contains(pid) {
return Some(pid);
}
p = ctx.parent.get(pid).copied();
continue;
}
p = ctx.parent.get(pid).copied();
}
}
pub(super) fn state_insertion_context<'a>(
ctx: &'a StateRenderCtx<'_>,
cluster_id: &str,
) -> Option<&'a str> {
state_leaf_context(ctx, cluster_id)
}
pub(super) fn state_endpoint_context<'a>(ctx: &'a StateRenderCtx<'_>, id: &str) -> Option<&'a str> {
if let Some(n) = ctx.nodes_by_id.get(id).copied() {
if n.is_group && n.shape != "noteGroup" {
return state_insertion_context(ctx, id);
}
}
state_leaf_context(ctx, id)
}
pub(super) fn state_context_chain<'a>(
ctx: &'a StateRenderCtx<'_>,
mut c: Option<&'a str>,
) -> Vec<Option<&'a str>> {
let mut out = Vec::new();
loop {
out.push(c);
let Some(id) = c else {
break;
};
c = state_insertion_context(ctx, id);
}
out
}
pub(super) fn state_edge_context<'a>(
ctx: &'a StateRenderCtx<'_>,
edge: &StateSvgEdge,
) -> Option<&'a str> {
let a = state_endpoint_context(ctx, edge.start.as_str());
let b = state_endpoint_context(ctx, edge.end.as_str());
let ca = state_context_chain(ctx, a);
let cb = state_context_chain(ctx, b);
for anc in cb {
if ca.contains(&anc) {
return anc;
}
}
None
}
pub(super) fn state_is_shadowed_self_loop_edge(
ctx: &StateRenderCtx<'_>,
edge_index: usize,
edge: &StateSvgEdge,
root: Option<&str>,
) -> bool {
if edge.start != edge.end {
return false;
}
if state_edge_context(ctx, edge) != root {
return false;
}
for later in ctx.edges.iter().skip(edge_index + 1) {
if later.start != later.end {
continue;
}
if later.start != edge.start || later.end != edge.end {
continue;
}
if state_is_hidden(ctx, later.start.as_str())
|| state_is_hidden(ctx, later.end.as_str())
|| state_is_hidden(ctx, later.id.as_str())
{
continue;
}
if state_edge_context(ctx, later) != root {
continue;
}
return true;
}
false
}