use parking_lot::Mutex;
use shared::core::geometry::{Bounds2i, Point2i};
use shared::utils::containers::Array2D;
use std::collections::HashSet;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;

pub struct InternCache<T> {
    cache: Mutex<HashSet<Arc<T>>>,
}

impl<T> InternCache<T>
where
    T: Eq + Clone,
{
    pub fn new() -> Self {
        Self {
            cache: Mutex::new(HashSet::new()),
        }
    }

    pub fn lookup(&self, value: T) -> Arc<T> {
        let mut lock = self.cache.lock().unwrap();

        if let Some(existing) = lock.get(&value) {
            return existing.clone();
        }

        let new_item = Arc::new(value);
        lock.insert(new_item.clone());
        new_item
    }
}

pub struct Array2DBuffer<T> {
    pub view: Array2D<T>,
    _storage: Vec<T>,
}

impl<T> Deref for Array2DBuffer<T> {
    type Target = Array2D<T>;
    fn deref(&self) -> &Self::Target {
        &self.view
    }
}

impl<T> DerefMut for Array2DBuffer<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.view
    }
}

impl<T> Array2DBuffer<T> {
    fn from_vec(extent: Bounds2i, mut storage: Vec<T>) -> Self {
        let width = extent.p_max.x - extent.p_min.x;
        let view = Array2D {
            extent,
            values: storage.as_mut_ptr(),
            stride: width,
        };
        Self {
            view,
            _storage: storage,
        }
    }
}

impl<T: Default + Clone> Array2DBuffer<T> {
    pub fn new(extent: Bounds2i) -> Self {
        let n = extent.area() as usize;
        let storage = vec![T::default(); n];
        Self::from_vec(extent, storage)
    }

    pub fn new_dims(nx: i32, ny: i32) -> Self {
        let extent = Bounds2i::new(Point2i::new(0, 0), Point2i::new(nx, ny));
        Self::new(extent)
    }

    pub fn new_filled(nx: i32, ny: i32, val: T) -> Self {
        let extent = Bounds2i::new(Point2i::new(0, 0), Point2i::new(nx, ny));
        let n = (nx * ny) as usize;
        let storage = vec![val; n];
        Self::from_vec(extent, storage)
    }
}
