Documentation
use rstar::primitives::GeomWithData;
use rstar::{Envelope, PointDistance, RTreeObject};
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::marker::PhantomData;

use crate::index::Index;

pub struct RStar<K, V, Q: RTreeObject, F: Fn(K, V) -> Q>(
    rstar::RTree<GeomWithData<Q, K>>,
    F,
    PhantomData<V>,
);

impl<K, V, Q, F> RStar<K, V, Q, F>
where
    Q: RTreeObject + PointDistance + Clone,
    K: Clone,
    F: Fn(K, V) -> Q,
{
    pub fn new(f: F) -> Self {
        RStar(rstar::RTree::new(), f, PhantomData)
    }
    pub fn nearest_neighbor(&self, q: &<Q::Envelope as Envelope>::Point) -> Option<(Q, K)> {
        self.0
            .nearest_neighbor(q)
            .map(|g| (g.geom().to_owned(), g.data.clone()))
    }
}

impl<K, V, Q, F> Index<K, V> for RStar<K, V, Q, F>
where
    K: Eq + Ord + Serialize + DeserializeOwned + Clone + PartialEq,
    V: Serialize + DeserializeOwned,
    Q: RTreeObject + PartialEq + PointDistance,
    F: Fn(K, V) -> Q,
{
    fn insert(&mut self, key: K, value: V) {
        self.0
            .insert(GeomWithData::new(self.1(key.clone(), value), key));
    }

    fn remove(&mut self, key: K, value: V) {
        self.0
            .remove(&GeomWithData::new(self.1(key.clone(), value), key));
    }
}
#[cfg(test)]
mod tests {
    use crate::{index::JSStoreWithIndex, rtree::RStar};
    #[test]
    fn test() {
        let mut x: JSStoreWithIndex<i32, (i32, i32), _> =
            JSStoreWithIndex::new("testrtree.json", RStar::new(|_k, v| v)).unwrap();
        x.insert(0, (1, 1)).unwrap();
        x.insert(1, (2, 2)).unwrap();
        x.insert(2, (3, 3)).unwrap();
        let result = x.index().nearest_neighbor(&(4, 4));
        assert_eq!(result, Some(((3, 3), 2)));
        drop(x);
    }
}