use ggez::event::EventHandler;
use ggez::{Context, GameResult};

use specs::world::WorldExt;

use crate::{components, resources, sys};

/// The shared values that the game state needs, specifically as the specs world
pub struct MyGame {
    pub world: specs::World,
}

impl MyGame {
    // setup the necessary initial state for `MyGame`, inserting the
    // relevant resources into it
    pub fn setup(ctx: &mut Context) -> GameResult<MyGame> {
        let mut world = specs::World::new();
        components::register(&mut world);

        world.insert(ncollide2d::world::CollisionWorld::<f32, specs::Entity>::new(0.1));
        resources::world_from_file(&mut world, "assets/main.tmx");

        let image = ggez::graphics::Image::new(ctx, "/spritesheet.png")?;
        let mut sprites = ggez::graphics::spritebatch::SpriteBatch::new(image);
        sprites.set_filter(ggez::graphics::FilterMode::Nearest);
        world.insert(sprites);
        world.insert(resources::KeySet::new());

        Ok(MyGame { world })
    }
}

impl EventHandler for MyGame {
    fn update(&mut self, _ctx: &mut Context) -> GameResult<()> {
        sys::input::systems(self);
        sys::physics::systems(self);
        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        sys::drawing::systems(self, ctx)
    }

    fn key_down_event(
        &mut self,
        ctx: &mut Context,
        keycode: winit::VirtualKeyCode,
        _keymod: ggez::event::KeyMods,
        _repeat: bool,
    ) {
        if keycode == winit::VirtualKeyCode::Escape {
            ggez::event::quit(ctx);
        }
        self.world
            .write_resource::<resources::KeySet>()
            .insert(keycode);
    }

    fn key_up_event(
        &mut self,
        _ctx: &mut Context,
        keycode: winit::VirtualKeyCode,
        _keymod: ggez::event::KeyMods,
    ) {
        self.world
            .write_resource::<resources::KeySet>()
            .remove(&keycode);
    }
}
