use std::collections::BTreeMap;
use crate::runtime::geometry::CanvasBounds;
use jellyflow_core::core::{CanvasRect, Graph, GroupId, NodeId};
use jellyflow_core::ops::GraphOp;
use super::candidates::DragCandidate;
use super::constraints::candidate_bounds_at;
use super::types::NodeDragItem;
pub(super) fn parent_expansion_ops(
graph: &Graph,
candidates: &[DragCandidate],
items: &[NodeDragItem],
) -> Vec<GraphOp> {
let item_targets = items
.iter()
.map(|item| (item.node, item.to))
.collect::<BTreeMap<NodeId, _>>();
let mut expanded_by_parent = BTreeMap::<GroupId, CanvasRect>::new();
for candidate in candidates {
if !candidate.expand_parent {
continue;
}
let Some(parent) = candidate.parent else {
continue;
};
let Some(target) = item_targets.get(&candidate.node).copied() else {
continue;
};
let Some(parent_rect) = graph.groups.get(&parent).map(|group| group.rect) else {
continue;
};
let Some(child_bounds) = candidate_bounds_at(*candidate, target) else {
continue;
};
let current_rect = expanded_by_parent
.get(&parent)
.copied()
.unwrap_or(parent_rect);
let Some(expanded_rect) = expand_rect(current_rect, child_bounds.to_rect()) else {
continue;
};
expanded_by_parent.insert(parent, expanded_rect);
}
expanded_by_parent
.into_iter()
.filter_map(|(id, to)| {
let from = graph.groups.get(&id)?.rect;
(from != to).then_some(GraphOp::SetGroupRect { id, from, to })
})
.collect()
}
fn expand_rect(parent: CanvasRect, child: CanvasRect) -> Option<CanvasRect> {
let parent_bounds = CanvasBounds::from_rect(parent)?;
let child_bounds = CanvasBounds::from_rect(child)?;
Some(parent_bounds.union(child_bounds).to_rect())
}