
#include <WFX/SDL/SDLInputHandler.h>
#include <WFX/util/Init.h>

using namespace WFX;
using namespace std;
using namespace WFX::SDL;
using namespace WFX::input;

Int SDLInputHandler::Instances = 0;

//init KeyMap
std::map<SDLKey, WFX::input::WFXKey> SDLInputHandler::KeyMap;
WFX::util::Init<SDLInputHandler> SDLInputHandlerInit;

SDLInputHandler::SDLInputHandler() {
    if (Instances < 1) {
        if (-1 == SDL_InitSubSystem(SDL_INIT_JOYSTICK)) {
            THROW("unable to init joystick subsystem " << SDL_GetError());
        }
        NumSticks = SDL_NumJoysticks();
        if (NumSticks) SDL_JoystickEventState(SDL_ENABLE);
        Joysticks = new SDL_Joystick*[NumSticks];
        LOG("found " << NumSticks << " joysticks!");
        for (int i=0;i<NumSticks;i++) {
            Joysticks[i] = SDL_JoystickOpen(i);
        }
        SDL_WM_GrabInput(SDL_GRAB_ON);
    }
    Instances++;
}

SDLInputHandler::~SDLInputHandler() {
    Instances--;
    if (Instances<1) {
        SDL_QuitSubSystem(SDL_INIT_JOYSTICK); 
    }
    //TODO: delete Joysticks
}

bool SDLInputHandler::start() {
    return true;
}

void SDLInputHandler::flushEvents() {
    while (SDL_PollEvent(&Event)) {
    }
}

void SDLInputHandler::getMousePos(Int* x, Int* y) {
    SDL_GetMouseState(x,y);
}

void SDLInputHandler::update() {
    //crude hack to determine which mouse button
    MouseButtonEvent::MouseButton btn = MouseButtonEvent::MB_OTHER;
    while (SDL_PollEvent(&Event)) {
        switch (Event.type) {
            case SDL_KEYDOWN:
                keyPressed(KeyEvent(getKey(),getChar()));
                break;
            case SDL_KEYUP:
                keyReleased(KeyEvent(getKey(),getChar()));
                break;
            case SDL_JOYAXISMOTION:
                axisEvent(JoystickAxisEvent((UChar)Event.jaxis.which,
                                            (UChar)Event.jaxis.axis,
                                            (Int)Event.jaxis.value
                                           ) 
                         );
                break;
            case SDL_JOYBUTTONDOWN:
                buttonPressed(JoystickButtonEvent((UChar)Event.jbutton.which,
                                                  (UChar)Event.jbutton.button,
                                                  (Event.jbutton.state==SDL_PRESSED)?JoystickButtonEvent::BS_PRESSED:JoystickButtonEvent::BS_RELEASED
                                                 )
                             );
                break;
            case SDL_JOYBUTTONUP:
                buttonReleased(JoystickButtonEvent((UChar)Event.jbutton.which,
                                                   (UChar)Event.jbutton.button,
                                                   (Event.jbutton.state==SDL_PRESSED)?JoystickButtonEvent::BS_PRESSED:JoystickButtonEvent::BS_RELEASED
                                                  )
                              );
                break;
            case SDL_JOYBALLMOTION:
                LOG(" SDLInputHandler::update  SDL_JOYBALLMOTION");
                break;
            case SDL_JOYHATMOTION:
                LOG("  SDLInputHandler::update SDL_JOYHATMOTION");
                break;
            case SDL_MOUSEMOTION:
                mouseMoved(MouseMotionEvent((UInt)Event.motion.x,
                                            (UInt)Event.motion.y,
                                            (Int)Event.motion.xrel,
                                            (Int)Event.motion.yrel
                                           )
                           );
                break;
            case SDL_MOUSEBUTTONDOWN:
                if (Event.button.button == (SDL_BUTTON_LEFT)) 
                    btn = MouseButtonEvent::MB_LEFT;
                if (Event.button.button == (SDL_BUTTON_MIDDLE)) 
                    btn = MouseButtonEvent::MB_MIDDLE;
                if (Event.button.button == (SDL_BUTTON_RIGHT)) 
                    btn = MouseButtonEvent::MB_RIGHT;
                mouseButtonPressed(MouseButtonEvent((UInt)Event.button.x,
                                                    (UInt)Event.button.y,
                                                    btn,
                                                    (Event.button.state==SDL_PRESSED)?MouseButtonEvent::BS_PRESSED:MouseButtonEvent::BS_RELEASED
                                                   )
                                  );
                break;
            case SDL_MOUSEBUTTONUP:
                break;
        }
    }
}

void SDLInputHandler::stop() {
}


WFX::input::WFXKey SDLInputHandler::getKey() {
    WFXKey k = KeyMap[Event.key.keysym.sym];
    if (k) return k;
    return WFXK_UNKNOWN;
}

Char SDLInputHandler::getChar() {
    return Event.key.keysym.sym;
}

void SDLInputHandler::WFXInit() {
    //init KeyMap
    KeyMap.insert(std::make_pair(SDLK_ESCAPE,WFXK_ESC));
    KeyMap.insert(std::make_pair(SDLK_F1,WFXK_F1));
    KeyMap.insert(std::make_pair(SDLK_F2,WFXK_F2));
    KeyMap.insert(std::make_pair(SDLK_F3,WFXK_F3));
    KeyMap.insert(std::make_pair(SDLK_F4,WFXK_F4));
    KeyMap.insert(std::make_pair(SDLK_F5,WFXK_F5));
    KeyMap.insert(std::make_pair(SDLK_F6,WFXK_F6));
    KeyMap.insert(std::make_pair(SDLK_F7,WFXK_F7));
    KeyMap.insert(std::make_pair(SDLK_F8,WFXK_F8));
    KeyMap.insert(std::make_pair(SDLK_F9,WFXK_F9));
    KeyMap.insert(std::make_pair(SDLK_F10,WFXK_F10));
    KeyMap.insert(std::make_pair(SDLK_F11,WFXK_F11));
    KeyMap.insert(std::make_pair(SDLK_F12,WFXK_F12));
    KeyMap.insert(std::make_pair(SDLK_0,WFXK_0));
    KeyMap.insert(std::make_pair(SDLK_1,WFXK_1));
    KeyMap.insert(std::make_pair(SDLK_2,WFXK_2));
    KeyMap.insert(std::make_pair(SDLK_3,WFXK_3));
    KeyMap.insert(std::make_pair(SDLK_4,WFXK_4));
    KeyMap.insert(std::make_pair(SDLK_5,WFXK_5));
    KeyMap.insert(std::make_pair(SDLK_6,WFXK_6));
    KeyMap.insert(std::make_pair(SDLK_7,WFXK_7));
    KeyMap.insert(std::make_pair(SDLK_8,WFXK_8));
    KeyMap.insert(std::make_pair(SDLK_9,WFXK_9));
    KeyMap.insert(std::make_pair(SDLK_BACKSPACE,WFXK_BACKSPACE));
    KeyMap.insert(std::make_pair(SDLK_LSHIFT,WFXK_LSHIFT));
    KeyMap.insert(std::make_pair(SDLK_RSHIFT,WFXK_RSHIFT));
    KeyMap.insert(std::make_pair(SDLK_LCTRL,WFXK_LCTRL));
    KeyMap.insert(std::make_pair(SDLK_RCTRL,WFXK_RCTRL));
    KeyMap.insert(std::make_pair(SDLK_LALT,WFXK_RALT));
    KeyMap.insert(std::make_pair(SDLK_RETURN,WFXK_RETURN));
    KeyMap.insert(std::make_pair(SDLK_SPACE,WFXK_SPACE));
    KeyMap.insert(std::make_pair(SDLK_a,WFXK_a));
    KeyMap.insert(std::make_pair(SDLK_b,WFXK_b));
    KeyMap.insert(std::make_pair(SDLK_c,WFXK_c));
    KeyMap.insert(std::make_pair(SDLK_d,WFXK_d));
    KeyMap.insert(std::make_pair(SDLK_e,WFXK_e));
    KeyMap.insert(std::make_pair(SDLK_f,WFXK_f));
    KeyMap.insert(std::make_pair(SDLK_g,WFXK_g));
    KeyMap.insert(std::make_pair(SDLK_h,WFXK_h));
    KeyMap.insert(std::make_pair(SDLK_i,WFXK_i));
    KeyMap.insert(std::make_pair(SDLK_j,WFXK_j));
    KeyMap.insert(std::make_pair(SDLK_k,WFXK_k));
    KeyMap.insert(std::make_pair(SDLK_l,WFXK_l));
    KeyMap.insert(std::make_pair(SDLK_m,WFXK_m));
    KeyMap.insert(std::make_pair(SDLK_n,WFXK_n));
    KeyMap.insert(std::make_pair(SDLK_o,WFXK_o));
    KeyMap.insert(std::make_pair(SDLK_p,WFXK_p));
    KeyMap.insert(std::make_pair(SDLK_q,WFXK_q));
    KeyMap.insert(std::make_pair(SDLK_r,WFXK_r));
    KeyMap.insert(std::make_pair(SDLK_s,WFXK_s));
    KeyMap.insert(std::make_pair(SDLK_t,WFXK_t));
    KeyMap.insert(std::make_pair(SDLK_u,WFXK_u));
    KeyMap.insert(std::make_pair(SDLK_v,WFXK_v));
    KeyMap.insert(std::make_pair(SDLK_w,WFXK_w));
    KeyMap.insert(std::make_pair(SDLK_x,WFXK_x));
    KeyMap.insert(std::make_pair(SDLK_y,WFXK_y));
    KeyMap.insert(std::make_pair(SDLK_z,WFXK_z));
    KeyMap.insert(std::make_pair(SDLK_UP,WFXK_UP));
    KeyMap.insert(std::make_pair(SDLK_DOWN,WFXK_DOWN));
    KeyMap.insert(std::make_pair(SDLK_LEFT,WFXK_LEFT));
    KeyMap.insert(std::make_pair(SDLK_RIGHT,WFXK_RIGHT));
}

