#include "CInput.hpp"

#include "../CKernel.hpp"

#include <iostream>

CInput::CInput(CKernel* kernel) :
    m_kernel(kernel),
    m_event(),
    m_mouse(),
    m_keyboard(),
    m_controllers(){
    m_keyboard.addObserver(this);
}

CInput::~CInput(void) {
    for (std::map<unsigned int, CController*>::iterator it = m_controllers.begin(); it != m_controllers.end(); ++it) {
        delete it->second;
    }
}

void CInput::updateEvent(void) {
    // Reset the mouse relative pos.
    m_mouse.reset();

    // For each event in the SDL event queue.
    while(SDL_PollEvent(&m_event) == 1) {

        // Switch on the event type.
        switch(m_event.type) {
            unsigned int id;
            CController* controller;

            // On key button pressed.
            case SDL_KEYDOWN:
                m_keyboard.onKeyDown(m_event.key.keysym.scancode);
                break;

            // On key button released.
            case SDL_KEYUP:
                m_keyboard.onKeyUp(m_event.key.keysym.scancode);
                break;

            // On mouse button pressed.
            case SDL_MOUSEBUTTONDOWN:
                m_mouse.onButtonDown(m_event.button.button);
                break;

            // On mouse button released.
            case SDL_MOUSEBUTTONUP:
                m_mouse.onButtonUp(m_event.button.button);
                break;

            // On mouse cursor moved.
            case SDL_MOUSEMOTION:
                m_mouse.onMove(m_event.motion.x, m_event.motion.y, m_event.motion.xrel, m_event.motion.yrel);
                break;

            // On mouse wheel moved.
            case SDL_MOUSEWHEEL:
                m_mouse.onWheel(m_event.wheel.x, m_event.wheel.y);
                break;

            // On joystick unplugged.
            case SDL_JOYDEVICEREMOVED:
                id = m_event.jdevice.which;
                controller = m_controllers[id];
                delete controller;
                m_controllers.erase(id);
                break;

            // On joystick plugged.
            case SDL_JOYDEVICEADDED:
                try {
                    // Give a test id for opening.
                    id = m_event.jdevice.which;
                    CController* controller = new CController(id);
                    // Get the final id.
                    id = controller->getId();
                    // Push the controller in the list.
                    m_controllers.insert(std::pair<unsigned int, CController*>(id, controller));
                }
                catch (const CException& e) {
                    HandleException(e, false);
                }
                break;

            // On joystick axis moved.
            case SDL_JOYAXISMOTION:
                controller = m_controllers[m_event.jaxis.which];
                controller->onAxis(m_event.jaxis.axis, m_event.jaxis.value);
                break;

            // On joystick hat moved.
            case SDL_JOYHATMOTION:
                controller = m_controllers[m_event.jhat.which];
                controller->onHat(m_event.jhat.hat, m_event.jhat.value);
            break;

            // On joystick button pressed.
            case SDL_JOYBUTTONDOWN:
                controller = m_controllers[m_event.jaxis.which];
                controller->onButtonDown(m_event.jbutton.button);
            break;

            // On joystick button released.
            case SDL_JOYBUTTONUP:
                controller = m_controllers[m_event.jaxis.which];
                controller->onButtonUp(m_event.jbutton.button);
            break;

            // Case of window event.
            case SDL_WINDOWEVENT:

                // If the window is closed.
                if (m_event.window.event == SDL_WINDOWEVENT_CLOSE) {
                    m_kernel->quit();
                }

                // If the window is focused.
                if (m_event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) {
                    m_kernel->focus();
                }
                break;

            default:
                break;
        }
    }
}

CKeyboard* CInput::getKeyboard(void) {
    return &m_keyboard;
}

CMouse* CInput::getMouse(void) {
    return &m_mouse;
}

CController* CInput::getController(unsigned int id) {
    return m_controllers[id];
}

std::map<unsigned int, CController*> CInput::getControllers(void) {
    return m_controllers;
}

void CInput::onKKeyDown(unsigned int which) {
    // 40 is enter.
    if (which == 40) {
        // If 226 is pressed.
        if (m_keyboard.getKey(226)) {
            m_kernel->fullscreen();
        }
    }

    // 227 is command/windows/meta.
    if (which == 227) {
        m_kernel->desktop();
    }
}

void CInput::onKKeyUp(unsigned int which) {
    (void)which;
}