use egui::Pos2;
use petgraph::{
prelude::GraphMap,
stable_graph::{EdgeIndex, EdgeReference, NodeIndex, StableGraph},
visit::{EdgeRef, IntoEdgeReferences, IntoNodeReferences},
Direction, EdgeType,
};
use crate::{metadata::Metadata, state_computed::StateComputed, transform, Edge, Node};
pub struct Graph<N: Clone, E: Clone, Ty: EdgeType> {
pub g: StableGraph<Node<N>, Edge<E>, Ty>,
}
impl<N: Clone, E: Clone, Ty: EdgeType> From<&StableGraph<N, E, Ty>> for Graph<N, E, Ty> {
fn from(value: &StableGraph<N, E, Ty>) -> Self {
transform::to_graph(value)
}
}
impl<'a, N: Clone, E: Clone, Ty: EdgeType> Graph<N, E, Ty> {
pub fn new(g: StableGraph<Node<N>, Edge<E>, Ty>) -> Self {
Self { g }
}
pub fn walk(
&self,
mut walker: impl FnMut(
&Self,
Option<&NodeIndex>,
Option<&Node<N>>,
Option<&EdgeIndex>,
Option<&Edge<E>>,
),
) {
self.nodes_iter()
.for_each(|(idx, n)| walker(self, Some(&idx), Some(n), None, None));
self.edges_iter()
.for_each(|(idx, e)| walker(self, None, None, Some(&idx), Some(e)));
}
pub fn node_by_pos(
&self,
comp: &'a StateComputed,
meta: &'a Metadata,
pos: Pos2,
) -> Option<(NodeIndex, &Node<N>)> {
let pos_in_graph = (pos - meta.pan).to_vec2() / meta.zoom;
self.nodes_iter().find(|(idx, n)| {
let comp_node = comp.node_state(idx).unwrap();
let dist_to_node = (n.location() - pos_in_graph).length();
let node_rad = comp_node.radius / meta.zoom;
dist_to_node <= node_rad
})
}
pub fn g(&mut self) -> &mut StableGraph<Node<N>, Edge<E>, Ty> {
&mut self.g
}
pub fn nodes_iter(&'a self) -> impl Iterator<Item = (NodeIndex, &Node<N>)> {
self.g.node_references()
}
pub fn edges_iter(&'a self) -> impl Iterator<Item = (EdgeIndex, &Edge<E>)> {
self.g.edge_references().map(|e| (e.id(), e.weight()))
}
pub fn node(&self, i: NodeIndex) -> Option<&Node<N>> {
self.g.node_weight(i)
}
pub fn edge(&self, i: EdgeIndex) -> Option<&Edge<E>> {
self.g.edge_weight(i)
}
pub fn edge_endpoints(&self, i: EdgeIndex) -> Option<(NodeIndex, NodeIndex)> {
self.g.edge_endpoints(i)
}
pub fn node_mut(&mut self, i: NodeIndex) -> Option<&mut Node<N>> {
self.g.node_weight_mut(i)
}
pub fn is_directed(&self) -> bool {
self.g.is_directed()
}
pub fn edges_num(&self, idx: NodeIndex) -> usize {
self.g.edges(idx).count()
}
pub fn edges_directed(
&self,
idx: NodeIndex,
dir: Direction,
) -> impl Iterator<Item = EdgeReference<Edge<E>>> {
self.g.edges_directed(idx, dir)
}
}