use crate::input::{Input, InputStatistics};
use amethyst_core::ecs::{Read, System, World, WorldExt, Write};
use amethyst_input::{BindingTypes, InputHandler};
use std::marker::PhantomData;

/// Updates input statistics, ideally called at the start of every frame
pub struct InputManagementSystem<B: BindingTypes> {
    phantom_bindings: PhantomData<B>,
}

impl<B: BindingTypes> Default for InputManagementSystem<B> {
    fn default() -> Self {
        Self {
            phantom_bindings: Default::default(),
        }
    }
}

impl<'s, B: BindingTypes> System<'s> for InputManagementSystem<B> {
    type SystemData = (Read<'s, InputHandler<B>>, Write<'s, Input<B>>);

    fn run(&mut self, (input_handler, mut input): Self::SystemData) {
        for action in input_handler.bindings.actions() {
            let action_is_down = input_handler.action_is_down(action).unwrap_or(false);
            input.actions.update_statistics(action, action_is_down);
        }

        for axis in input_handler.bindings.axes() {
            let action_is_down = if let Some(value) = input_handler.axis_value(axis) {
                let stats = input.axes.statistics.get_mut(axis).unwrap();
                stats.set_axis_value(value)
            } else {
                false
            };

            input.axes.update_statistics(axis, action_is_down);
        }
    }

    fn setup(&mut self, world: &mut World) {
        let mut result = Input::<B>::default();

        {
            let input = world.read_resource::<InputHandler<B>>();
            for action in input.bindings.actions() {
                result
                    .actions
                    .statistics
                    .insert(action.clone(), InputStatistics::default());
            }
            for axis in input.bindings.axes() {
                result
                    .axes
                    .statistics
                    .insert(axis.clone(), InputStatistics::default());
            }
        }
        world.insert(result);
    }
}
