use qecs_core::{
    Component, Id, IdWithIndex, Valid, StoreBase, ComponentStore, ComponentStoreIter,
    _ComponentStore, 
};

use vec_map::{self, VecMap};

use std::marker::PhantomData;
use std::iter;

pub struct VecMapStore<ID, C> {
    storage: VecMap<C>,
    _phantom: PhantomData<ID>,
}

impl<ID, C> From<VecMap<C>> for VecMapStore<ID, C>
    where ID: IdWithIndex, C: Component
{
    fn from(storage: VecMap<C>) -> Self {
        VecMapStore{ storage: storage, _phantom: PhantomData }
    }
}

impl<ID, C> Default for VecMapStore<ID, C>
    where ID: IdWithIndex, C: Component
{
    fn default() -> Self {
        Self::from(VecMap::default())
    }
}

impl<ID, C> StoreBase for VecMapStore<ID, C>
    where ID: IdWithIndex, C: Component
{
    type Id = ID;

    fn len(&self) -> usize { self.storage.len() }

    fn is_assigned<'id>(&self, id: Valid<'id, Self::Id>) -> bool {
        self.storage.contains_key(&id.index())
    }

    fn assign_cloned<'id>(
        &mut self, 
        dest: Valid<'id, Self::Id>,
        src: Valid<'id, Self::Id>,
    ) -> bool {
        match self.get(src).map(|c| c.clone()) {
            Some(com) => { self.assign(dest, com); true },
            None => false,
        }
    }

    fn release_drop<'id>(&mut self, id: Valid<'id, Self::Id>) -> bool {
        self.release(id).is_some()
    }

    fn clear(&mut self){ self.storage.clear() }
}

pub type Components<'a, C> = vec_map::Values<'a, C>;

pub type ComponentsMut<'a, C>
= iter::Map<vec_map::IterMut<'a, C>, fn((usize, &'a mut C)) -> &'a mut C>;

impl<'a, ID, C> _ComponentStore<'a> for VecMapStore<ID, C>
    where ID: IdWithIndex, C: Component
{
    type _Component = C;
    
    type Components = Components<'a, C>;
    
    type ComponentsMut = ComponentsMut<'a, C>;
}

impl<ID, C> ComponentStore for VecMapStore<ID, C>
    where ID: IdWithIndex, C: Component
{
    type Component = C;

    fn assign<'id, T>(&mut self, id: Valid<'id, Self::Id>, com: T) -> Option<Self::Component>
        where T: Into<Self::Component>
    {
        self.storage.insert(id.index(), com.into())
    }

    fn release<'id>(&mut self, id: Valid<'id, Self::Id>) -> Option<Self::Component> {
        self.storage.remove(&id.index())
    }

    fn get<'id>(&self, id: Valid<'id, Self::Id>) -> Option<&Self::Component> {
        self.storage.get(&id.index())
    }

    fn get_mut<'id>(&mut self, id: Valid<'id, Self::Id>) -> Option<&mut Self::Component> {
        self.storage.get_mut(&id.index())
    }

    fn components<'a>(&'a self) -> <Self as _ComponentStore<'a>>::Components {
        self.storage.values()
    }

    fn components_mut<'a>(&'a mut self) -> <Self as _ComponentStore<'a>>::ComponentsMut {
        fn map_fn<'a, C>((_, com): (usize, &'a mut C)) -> &'a mut C {
            com
        }

        self.storage.iter_mut().map(map_fn)
    }
}

impl<'id, ID, C, T> Extend<(Valid<'id, ID>, T)> for VecMapStore<ID, C> 
    where ID: IdWithIndex, C: Component, T: Into<C>
{
    fn extend<I>(&mut self, iterable: I)
        where I: IntoIterator<Item = (Valid<'id, ID>, T)>
    {
        for (id, com) in iterable {
            self.assign(id, com.into());
        }
    }
}

impl<'a, ID, C> IntoIterator for &'a VecMapStore<ID, C>
    where ID: IdWithIndex, C: Component
{
    type Item = <Self::IntoIter as Iterator>::Item;
    type IntoIter = Components<'a, C>;
    fn into_iter(self) -> Self::IntoIter { self.components() }
}

impl<'a, ID, C> IntoIterator for &'a mut VecMapStore<ID, C>
    where ID: IdWithIndex, C: Component
{
    type Item = <Self::IntoIter as Iterator>::Item;
    type IntoIter = ComponentsMut<'a, C>;
    fn into_iter(self) -> Self::IntoIter { self.components_mut() }
}

#[test]
fn test(){
    use qecs_core::{Component, Id, Valid};

    // id-type

    #[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
    struct MyId(u8);

    impl Component for MyId {}
    impl Id for MyId {}
    impl IdWithIndex for MyId {
        fn max_index() -> usize { 255 }
        fn index(&self) -> usize { self.0 as usize }
    }

    fn validate(id: MyId) -> Valid<'static, MyId> {
        unsafe { Valid::new(id) }
    }

    // component-type

    #[derive(Debug, Clone, PartialEq, Eq)]
    struct MyComponent(String);
    
    impl Component for MyComponent {}

    // store-type

    qecs_newtype!(type MyStore: VecMapStore<MyId, MyComponent>);

    // code

    let mut mystore: MyStore = MyStore::default();

    let entity_a = validate(MyId(0));
    let entity_b = validate(MyId(1));

    let com_a = MyComponent(String::from("foo"));
    let com_b = MyComponent(String::from("bar"));

    assert!(mystore.assign(entity_a, com_a.clone()).is_none());
    assert_eq!(&mystore.assign(entity_a, com_b).unwrap(), &com_a);
    
    assert!(mystore.assign_cloned(entity_b, entity_a));
    assert_eq!(mystore.get(entity_a).unwrap(), mystore.get(entity_b).unwrap());

    assert_eq!(mystore.components().count(), 2);
    
    mystore.clear();

    assert!(!mystore.is_assigned(entity_a));
    assert!(!mystore.is_assigned(entity_b));
}
