use std::{any::Any, collections::BTreeSet};
use nanoid::nanoid;
use serde::{Deserialize, Serialize};
use crate::{SField, SFunc};
use super::{IntoDataRef, IntoNodeRef, SData, SDataRef, SGraph, SNodeRef};
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SNode {
pub id: String,
pub name: String,
pub parent: Option<SNodeRef>,
pub children: BTreeSet<SNodeRef>,
pub data: BTreeSet<SDataRef>,
#[serde(skip)]
pub dirty: BTreeSet<String>,
}
impl SNode {
pub fn new_id(name: &str, id: &str) -> Self {
Self {
id: id.to_owned(),
name: name.to_owned(),
..Default::default()
}
}
pub fn new(name: &str) -> Self {
Self {
id: format!("obj{}", nanoid!()),
name: name.to_owned(),
..Default::default()
}
}
pub fn invalidate(&mut self, symbol: &str) {
self.dirty.insert(symbol.to_owned());
}
pub fn invalidate_all(&mut self) {
self.invalidate("all");
}
pub fn validate_all(&mut self) -> bool {
self.validate("all")
}
pub fn dirty(&self, symbol: &str) -> bool {
self.dirty.contains(symbol)
}
pub fn validate(&mut self, symbol: &str) -> bool {
self.dirty.remove(symbol)
}
pub fn has_dirty(&self) -> bool {
self.dirty.len() > 0
}
pub fn has_child(&self, child: &impl IntoNodeRef) -> bool {
let nref = child.node_ref();
self.children.contains(&nref)
}
pub(crate) fn put_child(&mut self, child: &impl IntoNodeRef) {
let new_child = self.children.insert(child.node_ref());
if new_child {
self.invalidate_all();
}
}
pub(crate) fn remove_child(&mut self, child: &impl IntoNodeRef) -> bool {
let removed = self.children.remove(&child.node_ref());
if removed { self.invalidate_all(); }
removed
}
pub fn has_data(&self, data: &impl IntoDataRef) -> bool {
self.data.contains(&data.data_ref())
}
pub(crate) fn put_data(&mut self, data: &impl IntoDataRef) -> bool {
let new_data = self.data.insert(data.data_ref());
if new_data {
self.invalidate_all();
}
new_data
}
pub(crate) fn remove_data(&mut self, data: &impl IntoDataRef) -> bool {
let removed = self.data.remove(&data.data_ref());
if removed { self.invalidate_all(); }
removed
}
pub fn data<'a, T: Any>(&self, graph: &'a SGraph) -> Vec<&'a T> {
let mut res = Vec::new();
for dref in &self.data {
if let Some(data) = SData::get::<T>(graph, dref) {
res.push(data);
}
}
res
}
pub fn data_recursive<'a, T: Any>(&self, graph: &'a SGraph) -> Vec<&'a T> {
let mut res = self.data::<T>(graph);
for child in &self.children {
if let Some(child) = child.node(graph) {
res.append(&mut child.data_recursive::<T>(graph));
}
}
res
}
pub fn data_refs<T: Any>(&self, graph: &SGraph) -> Vec<SDataRef> {
let mut res = Vec::new();
for dref in &self.data {
if let Some(data) = dref.data(graph) {
if data.is_type_of::<T>() {
res.push(dref.clone());
}
}
}
res
}
pub fn data_refs_recursive<T: Any>(&self, graph: &SGraph) -> Vec<SDataRef> {
let mut res = self.data_refs::<T>(graph);
for child in &self.children {
if let Some(child) = child.node(graph) {
res.append(&mut child.data_refs_recursive::<T>(graph));
}
}
res
}
pub fn dump(&self, graph: &SGraph, level: i32, data: bool) -> String {
let mut res = String::new();
let mut ident = String::from("\n");
for _ in 0..level { ident.push('\t'); }
res.push_str(&format!("{}{} ({}) {{", &ident, &self.name, &self.id));
if level < 1 { res = res.replace('\n', ""); }
if data {
let mut ident = String::from("\n");
for _ in 0..(level + 1) { ident.push('\t'); }
let mut iident = String::from("\n");
for _ in 0..(level + 2) { iident.push('\t'); }
for data_ref in &self.data {
if let Some(data) = data_ref.data(graph) {
res.push_str(&format!("{}data ({}) {{", &ident, &data.id));
if let Some(field) = data.get_data::<SField>() {
res.push_str(&format!("{}{:?}", &iident, field));
} else if let Some(func) = data.get_data::<SFunc>() {
res.push_str(&format!("{}{:?}", &iident, func));
}
res.push_str(&format!("{}}}", &ident));
}
}
res.push('\n');
}
for child_ref in &self.children {
if let Some(child) = child_ref.node(graph) {
res.push_str(&child.dump(graph, level + 1, data));
}
}
res.push_str(&format!("{}}}", &ident));
res
}
}