use crate::components::{MoveEvent, Position, Viewshed};
use crate::map::Map;

use rltk::Point;
use specs::prelude::*;

fn clamp<T: PartialOrd>(low: T, high: T, val: T) -> T {
    if val < low {
        low
    } else if val > high {
        high
    } else {
        val
    }
}

pub struct HandleMoveEvent;

impl<'a> System<'a> for HandleMoveEvent {
    type SystemData = (
        WriteStorage<'a, MoveEvent>,
        WriteStorage<'a, Position>,
        WriteStorage<'a, Viewshed>,
        WriteExpect<'a, Point>,
        ReadExpect<'a, Map>,
    );

    fn run(&mut self, (mut move_events, mut pos, mut viewshed, mut point, map): Self::SystemData) {
        for (&event, pos, viewshed) in (&move_events, &mut pos, &mut viewshed).join() {
            let MoveEvent {
                destination,
                tgt_x,
                tgt_y,
            } = event;
            if !map.blocked[destination] {
                viewshed.dirty = true;
                pos.x = tgt_x;
                pos.y = tgt_y;
                point.x = clamp(0, 79, tgt_x);
                point.y = clamp(0, 49, tgt_y);
            }
        }
        move_events.clear();
    }
}
