#include "Sdl3Input.hpp"
#include "SDL3/SDL.h"

void TSE::SDL3::Sdl3Input::Init()
{
        Instance = new Sdl3Input();
}

void TSE::SDL3::Sdl3Input::Delete()
{
    delete(Instance);
}

void TSE::SDL3::Sdl3Input::KeyCallback(uint key, int action, ushort mods)
{
    switch (action)
    {
    case 1: //down
        for(auto handler : ((Sdl3Input*)instance())->keyHandler)
        {
            handler->OnKeyDown(SDL3ToTSEKeycode(key), SDL3ToTSEModifier(mods));
        }
        break;
    case 0: //up
        for(auto handler : ((Sdl3Input*)instance())->keyHandler)
        {
            handler->OnKeyUp(SDL3ToTSEKeycode(key), SDL3ToTSEModifier(mods));
        }
        break;
    case 2: //hold
        for(auto handler : ((Sdl3Input*)instance())->keyHandler)
        {
            handler->OnKeyHold(SDL3ToTSEKeycode(key), SDL3ToTSEModifier(mods));
        }
        break;
    }
}

void TSE::SDL3::Sdl3Input::MouseButtonCallback(int button, int action)
{
    SDL_Keymod mods = SDL_GetModState();
    switch (action)
    {
    case 1: //down
        for(auto handler : ((Sdl3Input*)instance())->cursorHandler)
        {
            handler->OnMouseButtonDown(SDL3ToTSEMouseBtn(button), SDL3ToTSEModifier(mods));
        }
        break;
    case 0: //up
        for(auto handler : ((Sdl3Input*)instance())->cursorHandler)
        {
            handler->OnMouseButtonUp(SDL3ToTSEMouseBtn(button), SDL3ToTSEModifier(mods));
        }
        break;
    case 2: //hold
        for(auto handler : ((Sdl3Input*)instance())->cursorHandler)
        {
            handler->OnMouseButtonHold(SDL3ToTSEMouseBtn(button), SDL3ToTSEModifier(mods));
        }
        break;
    }
}

void TSE::SDL3::Sdl3Input::CursorPosCallback(float xpos, float ypos)
{
    for(auto handler : ((Sdl3Input*)instance())->cursorHandler)
    {
        handler->OnMousePosition(Vector2(xpos, ypos));
    }
}

void TSE::SDL3::Sdl3Input::ScrollCallback(float xoffset, float yoffset)
{
    for(auto handler : ((Sdl3Input*)instance())->cursorHandler)
    {
        handler->OnMouseScroll(Vector2(xoffset, yoffset));
    }
}

void TSE::SDL3::Sdl3Input::CharCallback(std::string msg)
{
    for(auto handler : ((Sdl3Input*)instance())->keyHandler)
    {
        handler->OnChar(msg);
    }
}

TSE::Key TSE::SDL3::Sdl3Input::SDL3ToTSEKeycode(uint code)
{
    switch (code)
    {
        case SDLK_SPACE:         return Key::Space;
        case SDLK_APOSTROPHE:    return Key::Apostrophe;
        case SDLK_COMMA:         return Key::Comma;
        case SDLK_MINUS:         return Key::Minus;
        case SDLK_PERIOD:        return Key::Period;
        case SDLK_SLASH:         return Key::Slash;

        case SDLK_0:             return Key::Alpha0;
        case SDLK_1:             return Key::Alpha1;
        case SDLK_2:             return Key::Alpha2;
        case SDLK_3:             return Key::Alpha3;
        case SDLK_4:             return Key::Alpha4;
        case SDLK_5:             return Key::Alpha5;
        case SDLK_6:             return Key::Alpha6;
        case SDLK_7:             return Key::Alpha7;
        case SDLK_8:             return Key::Alpha8;
        case SDLK_9:             return Key::Alpha9;

        case SDLK_SEMICOLON:     return Key::SemiColon;
        case SDLK_EQUALS:        return Key::Equal;

        case SDLK_A:             return Key::A;
        case SDLK_B:             return Key::B;
        case SDLK_C:             return Key::C;
        case SDLK_D:             return Key::D;
        case SDLK_E:             return Key::E;
        case SDLK_F:             return Key::F;
        case SDLK_G:             return Key::G;
        case SDLK_H:             return Key::H;
        case SDLK_I:             return Key::I;
        case SDLK_J:             return Key::J;
        case SDLK_K:             return Key::K;
        case SDLK_L:             return Key::L;
        case SDLK_M:             return Key::M;
        case SDLK_N:             return Key::N;
        case SDLK_O:             return Key::O;
        case SDLK_P:             return Key::P;
        case SDLK_Q:             return Key::Q;
        case SDLK_R:             return Key::R;
        case SDLK_S:             return Key::S;
        case SDLK_T:             return Key::T;
        case SDLK_U:             return Key::U;
        case SDLK_V:             return Key::V;
        case SDLK_W:             return Key::W;
        case SDLK_X:             return Key::X;
        case SDLK_Y:             return Key::Y;
        case SDLK_Z:             return Key::Z;

        case SDLK_LEFTBRACKET:   return Key::LeftBracket;
        case SDLK_BACKSLASH:     return Key::Backslash;
        case SDLK_RIGHTBRACKET:  return Key::RightBracket;
        case SDLK_GRAVE:         return Key::GraveAccent;

        case SDLK_ESCAPE:        return Key::Escape;
        case SDLK_RETURN:        return Key::Enter;
        case SDLK_TAB:           return Key::Tab;
        case SDLK_BACKSPACE:     return Key::Backspace;
        case SDLK_INSERT:        return Key::Insert;
        case SDLK_DELETE:        return Key::Delete;

        case SDLK_RIGHT:         return Key::Right;
        case SDLK_LEFT:          return Key::Left;
        case SDLK_DOWN:          return Key::Down;
        case SDLK_UP:            return Key::Up;

        case SDLK_PAGEUP:        return Key::PageUp;
        case SDLK_PAGEDOWN:      return Key::PageDown;
        case SDLK_HOME:          return Key::Home;
        case SDLK_END:           return Key::End;

        case SDLK_CAPSLOCK:      return Key::CapsLock;
        case SDLK_SCROLLLOCK:    return Key::ScrollLock;
        case SDLK_NUMLOCKCLEAR:  return Key::NumLock;
        case SDLK_PRINTSCREEN:   return Key::PrintScreen;
        case SDLK_PAUSE:         return Key::Pause;

        case SDLK_F1:            return Key::F1;
        case SDLK_F2:            return Key::F2;
        case SDLK_F3:            return Key::F3;
        case SDLK_F4:            return Key::F4;
        case SDLK_F5:            return Key::F5;
        case SDLK_F6:            return Key::F6;
        case SDLK_F7:            return Key::F7;
        case SDLK_F8:            return Key::F8;
        case SDLK_F9:            return Key::F9;
        case SDLK_F10:           return Key::F10;
        case SDLK_F11:           return Key::F11;
        case SDLK_F12:           return Key::F12;
        case SDLK_F13:           return Key::F13;
        case SDLK_F14:           return Key::F14;
        case SDLK_F15:           return Key::F15;
        case SDLK_F16:           return Key::F16;
        case SDLK_F17:           return Key::F17;
        case SDLK_F18:           return Key::F18;
        case SDLK_F19:           return Key::F19;
        case SDLK_F20:           return Key::F20;
        case SDLK_F21:           return Key::F21;
        case SDLK_F22:           return Key::F22;
        case SDLK_F23:           return Key::F23;
        case SDLK_F24:           return Key::F24;

        case SDLK_KP_0:          return Key::Numpad0;
        case SDLK_KP_1:          return Key::Numpad1;
        case SDLK_KP_2:          return Key::Numpad2;
        case SDLK_KP_3:          return Key::Numpad3;
        case SDLK_KP_4:          return Key::Numpad4;
        case SDLK_KP_5:          return Key::Numpad5;
        case SDLK_KP_6:          return Key::Numpad6;
        case SDLK_KP_7:          return Key::Numpad7;
        case SDLK_KP_8:          return Key::Numpad8;
        case SDLK_KP_9:          return Key::Numpad9;

        case SDLK_KP_PERIOD:     return Key::NumpadDecimal;
        case SDLK_KP_DIVIDE:     return Key::NumpadDivide;
        case SDLK_KP_MULTIPLY:   return Key::NumpadMultiply;
        case SDLK_KP_MINUS:      return Key::NumpadSubtract;
        case SDLK_KP_PLUS:       return Key::NumpadAdd;
        case SDLK_KP_ENTER:      return Key::NumpadEnter;
        case SDLK_KP_EQUALS:     return Key::NumpadEqual;

        case SDLK_LSHIFT:        return Key::LeftShift;
        case SDLK_LCTRL:         return Key::LeftControl;
        case SDLK_LALT:          return Key::LeftAlt;
        case SDLK_LGUI:          return Key::LeftSuper;

        case SDLK_RSHIFT:        return Key::RightShift;
        case SDLK_RCTRL:         return Key::RightControl;
        case SDLK_RALT:          return Key::RightAlt;
        case SDLK_RGUI:          return Key::RightSuper;

        case SDLK_MENU:          return Key::Menu;

        default:                 return Key::Unknown;
    }
}

TSE::MouseBtn TSE::SDL3::Sdl3Input::SDL3ToTSEMouseBtn(int btn)
{
    switch (btn)
    {
    case 1:
        return Button1;
        break;
    case 2:
        return Button3;
        break;
    case 3:
        return Button2;
        break;
    case 4:
        return Button4;
        break;
    case 5:
        return Button5;
        break;
    
    default:
        return Button8;
    }
}

TSE::Modifier TSE::SDL3::Sdl3Input::SDL3ToTSEModifier(ushort mod)
{
    int res = None;
    if((mod & SDL_KMOD_LSHIFT) == SDL_KMOD_LSHIFT || (mod & SDL_KMOD_RSHIFT) == SDL_KMOD_RSHIFT) res = res | ShiftMod;
    if((mod & SDL_KMOD_LCTRL) == SDL_KMOD_LCTRL || (mod & SDL_KMOD_RCTRL) == SDL_KMOD_RCTRL) res = res | ControlMod;
    if((mod & SDL_KMOD_LALT) == SDL_KMOD_LALT || (mod & SDL_KMOD_RALT) == SDL_KMOD_RALT) res = res | AltMod;
    if((mod & SDL_KMOD_LGUI) == SDL_KMOD_LGUI || (mod & SDL_KMOD_RGUI) == SDL_KMOD_RGUI) res = res | SuperMod;
    if((mod & SDL_KMOD_NUM) == SDL_KMOD_NUM) res = res | NumLockMod;
    if((mod & SDL_KMOD_CAPS) == SDL_KMOD_CAPS) res = res | CapsLockMod;
    return (Modifier)res;
}
