#![allow(dead_code)]

use hibitset::BitSetLike;
use shrev::EventChannel;
use specs::{
    storage::{TryDefault, UnprotectedStorage},
    world::Index,
    Component, DenseVecStorage,
};

pub struct FlaggedStorage<C, T = DenseVecStorage<C>>
where
    C: Send + Sync + 'static,
{
    channel: EventChannel<ComponentEvent<C>>,
    storage: T,
}

pub enum ComponentEvent<C>
where
    C: Send + Sync + 'static,
{
    Inserted(Index),
    Modified(Index, C),
    Removed(Index, C),
}

impl<C, T> FlaggedStorage<C, T>
where
    C: Send + Sync + 'static,
{
    pub fn channel(&self) -> &EventChannel<ComponentEvent<C>> {
        &self.channel
    }

    pub fn channel_mut(&mut self) -> &mut EventChannel<ComponentEvent<C>> {
        &mut self.channel
    }
}

impl<C, T> Default for FlaggedStorage<C, T>
where
    C: Send + Sync + 'static,
    T: TryDefault,
{
    fn default() -> Self {
        FlaggedStorage {
            channel: EventChannel::new(),
            storage: T::unwrap_default(),
        }
    }
}

impl<C: Component + Clone, T: UnprotectedStorage<C>> UnprotectedStorage<C> for FlaggedStorage<C, T>
where
    C: Send + Sync + 'static,
{
    unsafe fn clean<B>(&mut self, has: B)
    where
        B: BitSetLike,
    {
        self.storage.clean(has);
    }

    unsafe fn get(&self, id: Index) -> &C {
        self.storage.get(id)
    }

    unsafe fn get_mut(&mut self, id: Index) -> &mut C {
        let ret = self.storage.get_mut(id);

        self.channel
            .single_write(ComponentEvent::Modified(id, ret.clone()));

        ret
    }

    unsafe fn insert(&mut self, id: Index, comp: C) {
        self.storage.insert(id, comp);

        self.channel.single_write(ComponentEvent::Inserted(id));
    }

    unsafe fn remove(&mut self, id: Index) -> C {
        let c = self.storage.remove(id);

        self.channel
            .single_write(ComponentEvent::Removed(id, c.clone()));

        c
    }
}
