use specs::prelude::*;

#[derive(Component, Default, Clone)]
#[storage(HashMapStorage)]
pub struct Map {
    pub actors: BitSet,
}

#[derive(Component)]
#[storage(FlaggedStorage)]
pub struct MapID(Entity);

impl MapID {
    pub fn entity(&self) -> Entity { self.0 }
}

pub struct MapManager {
    inserted_id: ReaderId<InsertedFlag>,
    removed_id: ReaderId<RemovedFlag>,

    inserted: BitSet,
    removed: BitSet,
}

impl MapManager {
    pub fn new(world: &mut World) -> Self {
        world.register::<Map>();
        world.register::<MapID>();
        let mut storage = world.write_storage::<MapID>();
        Self {
            inserted_id: storage.track_inserted(),
            inserted: BitSet::new(),
            removed_id: storage.track_removed(),
            removed: BitSet::new(),
        }
    }
}

impl<'a> System<'a> for MapManager {
    type SystemData = (
        ReadStorage<'a, MapID>,
        WriteStorage<'a, Map>,
        Entities<'a>,
    );
    fn run(&mut self, (ids, mut maps, entities): Self::SystemData) {
        self.inserted.clear();
        self.removed.clear();

        ids.populate_inserted(&mut self.inserted_id, &mut self.inserted);
        ids.populate_removed(&mut self.removed_id, &mut self.removed);

        for (e, id, _) in (&*entities, &ids, &self.inserted).join() {
            let map = maps.get_mut(id.0).unwrap();
            map.actors.add(e.id());
        }

        for (e, id, _) in (&*entities, &ids, &self.removed).join() {
            let map = maps.get_mut(id.0).unwrap();
            map.actors.remove(e.id());
        }
    }
}