use wasm_bindgen::prelude::*;

mod point;
pub use point::*;
mod space_colonization;
pub use space_colonization::*;
mod math;
mod spatial_index;

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = window)]
    fn performance() -> web_sys::Performance;
}

#[derive(Debug, PartialEq, Eq, Hash)]
pub struct Attractor {
    pub position: Point,
    pub dead: bool,
}

impl Attractor {
    pub fn new(position: Point) -> Attractor {
        Attractor {
            position,
            dead: false,
        }
    }
}

/// A Node of the graph that is connected to one or more other nodes
///
/// Use cases :
///  - Rendering
///    - Must be easy and fast to find connections
///    - Must know the number of descendent generations to calculate vein thickness
///  - Growing
///    - Must be easy and fast to find nodes in a cell
///    - Probably worth marking nodes as dead when no attractor is in range
#[derive(Debug, PartialEq, Eq)]
pub struct Node {
    /// When a Node is born it is growing
    /// it stops growing when there is no attractor in range
    pub growing: bool,
    pub position: Point,
    pub children: Vec<Node>,
}

pub struct Attraction {
    node: *mut Node,
    distance: f64,
}
impl Attraction {
    fn new(node: &mut Node, distance: f64) -> Attraction {
        Self { node, distance }
    }
}

impl std::hash::Hash for Node {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.position.hash(state);
    }
}

impl Node {
    pub fn render<G>(&self, render_id: f64, render_fn: G)
    where
        G: Copy + Fn(&Node, &Node),
    {
        for child in self.children.iter() {
            render_fn(self, &child);
        }

        for child in self.children.iter() {
            child.render(render_id, render_fn);
        }
    }

    pub fn new(position: Point) -> Self {
        Self {
            position,
            growing: true,
            children: Vec::new().into(),
        }
    }
}
