use crate::components::*;
use crate::consts;

use specs::world::{Builder, WorldExt};
use std::path::Path;

#[derive(Debug, Default)]
pub struct KeySet {
    keys: std::collections::HashSet<winit::VirtualKeyCode>,
}

impl KeySet {
    pub fn new() -> KeySet {
        KeySet {
            keys: std::collections::HashSet::new(),
        }
    }

    pub fn contains(&self, kc: &winit::VirtualKeyCode) -> bool {
        self.keys.contains(kc)
    }

    pub fn insert(&mut self, kc: winit::VirtualKeyCode) {
        self.keys.insert(kc);
    }

    pub fn remove(&mut self, kc: &winit::VirtualKeyCode) {
        self.keys.remove(kc);
    }
}

#[derive(Debug, Copy, Clone)]
enum DrawLayer {
    Background,
    Foreground,
    Decoration,
}

static DRAW_LAYERS: [DrawLayer; 3] = [
    DrawLayer::Background,
    DrawLayer::Foreground,
    DrawLayer::Decoration,
];

pub fn world_from_file<P: AsRef<Path>>(w: &mut specs::World, path: P) {
    let tiled::Map {
        layers, tilesets, ..
    } = tiled::parse_file(path.as_ref()).unwrap();

    for (phase, layer) in DRAW_LAYERS.iter().zip(layers) {
        for (row, y) in layer.tiles.iter().zip(0..) {
            for (&n, x) in row.iter().zip(0..) {
                if n != 0 {
                    let x = x as f32 * consts::TILE_SIZE;
                    let y = y as f32 * consts::TILE_SIZE;
                    let u = ((n - 1) % 32) as u8;
                    let v = ((n - u as u32 - 1) / 32) as u8;
                    let is_blocking = tilesets[0].tiles[(n - 1) as usize].properties["pass"]
                        == consts::TILED_FALSE;
                    let mut e = w
                        .create_entity_unchecked()
                        .with(Position { x, y })
                        .with(Sprite { u, v });
                    e = match phase {
                        DrawLayer::Background => e.with(Background),
                        DrawLayer::Foreground => e.with(Foreground),
                        DrawLayer::Decoration => e.with(Decoration),
                    };

                    let e = if is_blocking {
                        let mut h = w.write_resource::<World>();
                        let entity = e.entity;
                        e.with(Blocking::new_box(entity, &mut h))
                    } else {
                        e
                    };
                    e.build();
                }
            }
        }
    }

    let e = w
        .create_entity_unchecked()
        .with(Position {
            x: 3.0 * consts::TILE_SIZE,
            y: 3.0 * consts::TILE_SIZE,
        })
        .with(Sprite { u: 8, v: 0 })
        .with(Velocity { dx: 0.0, dy: 0.0 })
        .with(Foreground)
        .with(Controlled)
        .with(Collision {
            has_collision: false,
        });

    let entity = e.entity;
    e.with({
        let mut h = w.write_resource::<World>();
        Blocking::new_ball(entity, &mut h)
    })
    .build();
}
