//! Game project.
use fyrox::{
    asset::manager::ResourceManager,
    core::pool::Handle,
    engine::GraphicsContext,
    event::{Event, WindowEvent},
    gui::message::UiMessage,
    plugin::{Plugin, PluginConstructor, PluginContext, PluginRegistrationContext},
    scene::{
        graph::Graph, Scene
    }
};
use std::path::Path;
mod map;
mod player;
mod enemy;
mod enemy_spawn;
mod msg;

use map::build_map;
use player::Player;
use enemy::Enemy;
use enemy_spawn::EnemySpawn;
use msg::Message;


pub struct GameConstructor;

impl PluginConstructor for GameConstructor {
    fn register(&self, context: PluginRegistrationContext) {
        // Register your scripts here.
        let script_constructors = &context.serialization_context.script_constructors;
        script_constructors.add::<Enemy>("Enemy");
        script_constructors.add::<Player>("Player");
    }

    fn create_instance(&self, scene_path: Option<&str>, context: PluginContext) -> Box<dyn Plugin> {
        Box::new(Game::new(scene_path, context))
    }
}

pub struct Game {
    scene: Handle<Scene>,
}

impl Game {
    pub fn new(scene_path: Option<&str>, context: PluginContext) -> Self {
        context
            .async_scene_loader
            .request(scene_path.unwrap_or("data/scene.rgs"));

        Self {
            scene: Handle::NONE,
        }
    }
}

impl Plugin for Game {
    fn on_deinit(&mut self, _context: PluginContext) {
        // Do a cleanup here.
    }

    fn update(&mut self, _context: &mut PluginContext) {
        // Add your global update code here.
    }

    fn on_os_event(&mut self, event: &Event<()>, context: PluginContext) {
        if let Event::Resumed {} = event {
            if let GraphicsContext::Initialized(ref graphics_context) = context.graphics_context {
                let window_size = graphics_context.window.inner_size();
                for script_scene in &context.script_processor.scripted_scenes {
                    script_scene.message_sender.send_global(Message::Resize {
                        width: window_size.width,
                        height: window_size.height
                    });
                }
            }
        }
        if let Event::WindowEvent { event, .. } = event {
            if let WindowEvent::Resized(size) = event {
                for script_scene in &context.script_processor.scripted_scenes {
                    script_scene.message_sender.send_global(Message::Resize {
                        width: size.width,
                        height: size.height
                    });
                }
            }
        }
    }

    fn on_ui_message(&mut self, _context: &mut PluginContext, _message: &UiMessage) {
        // Handle UI events here.
    }

    fn on_scene_begin_loading(&mut self, _path: &Path, ctx: &mut PluginContext) {
        if self.scene.is_some() {
            ctx.scenes.remove(self.scene);
        }
    }

    fn on_scene_loaded(
        &mut self,
        _path: &Path,
        scene: Handle<Scene>,
        _data: &[u8],
        context: &mut PluginContext,
    ) {
        self.scene = scene;

        let graph: &mut Graph = &mut context.scenes[self.scene].graph;
        let resource_manager: &ResourceManager = &context.resource_manager;
        build_map(graph, resource_manager);
        EnemySpawn::new().spawn_enemy(graph, resource_manager, 0.0);
    }
}
