//-----------------------------------------------------------------------------
// Copyright (c) 2013 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#import "platform/platform.h"
#import "platform/platformInput.h"
#import "platformOSX/osxInputManager.h"
#import "platform/event.h"

#pragma mark ---- Static Variables ----
InputManager *Input::smManager = 0;
CursorManager *Input::smCursorManager = 0;
bool Input::smActive;

#pragma mark ---- Input Namespace Functions ----

//--------------------------------------------------------------------------
void Input::init()
{
    Con::printSeparator();
    Con::printf("Input initialization:");

    // Cleanup if initialized previously
    destroy();

    smManager = NULL;
    smActive = false;

    if (!smManager)
        smManager = new osxInputManager();

    Input::enable();

    if (!smCursorManager)
    {
        smCursorManager = new CursorManager();

        // Add the arrow cursor to the stack
        if (smCursorManager)
            smCursorManager->pushCursor(CursorManager::curArrow);
        else
            Con::printf("Cursor Manager not enabled");
    }
}

//--------------------------------------------------------------------------
void Input::destroy()
{
    if (smManager)
    {
        smManager->disable();
        delete smManager;
        smManager = NULL;
    }

    if (smCursorManager)
    {
        smCursorManager->popCursor();
        delete smCursorManager;
        smCursorManager = NULL;
    }

    smActive = false;
}

//------------------------------------------------------------------------------
// Disable all input for the application
bool Input::enable()
{
    bool enabledValue = false;

    // Check for any restrictions or errors

    // If the manager exists and is not enabled, dos o
    if (smManager && !smManager->isEnabled())
        enabledValue = smManager->enable();

    // Also enable mouse and keyboard automatically
    enableMouse();
    enableKeyboard();

    return enabledValue;
}

//------------------------------------------------------------------------------
// Disable all input in the application
void Input::disable()
{
    if (smManager && smManager->isEnabled())
        return smManager->disable();

    disableMouse();
    disableKeyboard();
}

//------------------------------------------------------------------------------
// Not used on OS X
void Input::activate()
{
}

//------------------------------------------------------------------------------
// Not used on OS X
void Input::deactivate()
{
}

//------------------------------------------------------------------------------
// Not used on OS X
void Input::reactivate()
{
}

//------------------------------------------------------------------------------
// Print the entire input state to the console
// Not yet implemented or unnecessary. Will resolve in the next platform update
void Input::echoInputState()
{
}

//------------------------------------------------------------------------------
// Accesses the global input manager to see if it is enabled
bool Input::isEnabled()
{
    if (smManager)
        return smManager->isEnabled();

    return false;
}

//------------------------------------------------------------------------------
// Accesses the global input manager to see if its mouse is enabled
bool Input::isMouseEnabled()
{
    osxInputManager* inputManager = (osxInputManager*)getManager();

    if (inputManager)
        return inputManager->isMouseEnabled();

    return false;
}

//------------------------------------------------------------------------------
// Accesses the global input manager to see if its keyboard is enabled
bool Input::isKeyboardEnabled()
{
    osxInputManager* inputManager = (osxInputManager*)getManager();

    if (inputManager)
        return inputManager->isKeyboardEnabled();

    return false;
}

//------------------------------------------------------------------------------
// Does nothing on OS X.
bool Input::isActive()
{
    // Input is always "active" in an OS X application
    // We manually enable or disable it, but the OS
    // always assumes it is running
    return true;
}

//------------------------------------------------------------------------------
// Access the global osxInputManager and enables its mouse
void Input::enableMouse()
{
    osxInputManager *inputManager = (osxInputManager *) getManager();

    if (inputManager)
        return inputManager->enableMouse();
}

//------------------------------------------------------------------------------
// Access the global osxInputManager and disables its mouse
void Input::disableMouse()
{
    osxInputManager *inputManager = (osxInputManager *) getManager();

    if (inputManager)
        return inputManager->disableMouse();
}

//------------------------------------------------------------------------------
// Access the global osxInputManager and enables its keyboard
void Input::enableKeyboard()
{
    osxInputManager *inputManager = (osxInputManager *) getManager();

    if (inputManager)
        inputManager->enableKeyboard();
}

//------------------------------------------------------------------------------
// Access the global osxInputManager and enables its keyboard
void Input::disableKeyboard()
{
    osxInputManager *inputManager = (osxInputManager *) getManager();

    if (inputManager)
        return inputManager->disableKeyboard();
}

//------------------------------------------------------------------------------
// This is essentially the same as enableKeyboard. The redunancy is due to
// keep parallel functionality with Windows, which has a different usage
// for activateKeyboard due to DirectInput
bool Input::activateKeyboard()
{
    osxInputManager *inputManager = (osxInputManager *) getManager();

    if (inputManager)
    {
        inputManager->enableKeyboard();
        return true;
    }

    return false;
}

//------------------------------------------------------------------------------
// This is essentially the same as disableKeyboard. The redunancy is due to
// keep parallel functionality with Windows, which has a different usage
// for deactivateKeyboard due to DirectInput
void Input::deactivateKeyboard()
{
    osxInputManager *inputManager = (osxInputManager *) getManager();

    if (inputManager)
        inputManager->disableKeyboard();
}

//------------------------------------------------------------------------------
// Enable joystick input
bool Input::enableJoystick()
{
    return false;
}

//------------------------------------------------------------------------------
// Disable joystick input
void Input::disableJoystick()
{
}

//------------------------------------------------------------------------------
// Handles platform and game input processing separately
void Input::process()
{
    // Perform any initial processing

    // Run the input manager's process
    smManager->process();
}

//------------------------------------------------------------------------------
// Returns the single instances of smManager, an osxInputManager in this case
InputManager *Input::getManager()
{
    return smManager;
}

//------------------------------------------------------------------------------
// Not yet implemented. Will resolve in the next platform update
U16 Input::getKeyCode(U16 asciiCode)
{
    return 0;
}

//------------------------------------------------------------------------------
// Not yet implemented. Will resolve in the next platform update
U16 Input::getAscii(U16 keyCode, KEY_STATE keyState)
{
    return 0;
}

//------------------------------------------------------------------------------
// Not yet implemented. Will resolve in the next platform update
void Input::pushCursor(S32 cursorID)
{
}

//------------------------------------------------------------------------------
// Not yet implemented. Will resolve in the next platform update
void Input::popCursor()
{
}

//-----------------------------------------------------------------------------
// Not yet implemented. Will resolve in the next platform update
void Input::refreshCursor()
{
}

//------------------------------------------------------------------------------
U32 Input::getDoubleClickTime()
{
    // Get system specified double click time
    NSTimeInterval doubleInterval = [NSEvent doubleClickInterval];
    
    return doubleInterval * 1000;
}

//------------------------------------------------------------------------------
S32 Input::getDoubleClickWidth()
{
    // this is an arbitrary value.
    return 10;
}

//------------------------------------------------------------------------------
S32 Input::getDoubleClickHeight()
{
    return getDoubleClickWidth();
}

//------------------------------------------------------------------------------
// Not yet implemented. Will resolve in the next platform update
void Input::setCursorPos(S32 x, S32 y)
{
}

//-----------------------------------------------------------------------------
// Not yet implemented. Will resolve in the next platform update
void Input::setCursorState(bool on)
{

}

//-----------------------------------------------------------------------------
// Not yet implemented. Will resolve in the next platform update
void Input::setCursorShape(U32 cursorID)
{

}

#pragma mark ---- Platform Namespace Functions ----

//------------------------------------------------------------------------------
// Not yet implemented. Will resolve in the next platform update
const char *Platform::getClipboard()
{
    return NULL;
}

//-----------------------------------------------------------------------------
// Not yet implemented. Will resolve in the next platform update
bool Platform::setClipboard(const char *text)
{
    return false;
}

//-----------------------------------------------------------------------------
// Not yet implemented. Will resolve in the next platform update
void Platform::enableKeyboardTranslation(void)
{

}

//-----------------------------------------------------------------------------
// Not yet implemented. Will resolve in the next platform update
void Platform::disableKeyboardTranslation(void)
{

}

//--------------------------------------------------------------------------
//#pragma message("input remap table might need tweaking - rumors of ibooks having diff virt keycodes, might need intermediate remap...")
static U8 VcodeRemap[256] =
{
        KEY_A,                     // 0x00
        KEY_S,                     // 0x01
        KEY_D,                     // 0x02
        KEY_F,                     // 0x03
        KEY_H,                     // 0x04
        KEY_G,                     // 0x05
        KEY_Z,                     // 0x06
        KEY_X,                     // 0x07
        KEY_C,                     // 0x08
        KEY_V,                     // 0x09
        KEY_Y,                     // 0x0A       // this is questionable - not normal Y code
        KEY_B,                     // 0x0B
        KEY_Q,                     // 0x0C
        KEY_W,                     // 0x0D
        KEY_E,                     // 0x0E
        KEY_R,                     // 0x0F
        KEY_Y,                     // 0x10
        KEY_T,                     // 0x11
        KEY_1,                     // 0x12
        KEY_2,                     // 0x13
        KEY_3,                     // 0x14
        KEY_4,                     // 0x15
        KEY_6,                     // 0x16
        KEY_5,                     // 0x17
        KEY_EQUALS,                // 0x18
        KEY_9,                     // 0x19
        KEY_7,                     // 0x1A
        KEY_MINUS,                 // 0x1B
        KEY_8,                     // 0x1C
        KEY_0,                     // 0x1D
        KEY_RBRACKET,              // 0x1E
        KEY_O,                     // 0x1F
        KEY_U,                     // 0x20
        KEY_LBRACKET,              // 0x21
        KEY_I,                     // 0x22
        KEY_P,                     // 0x23
        KEY_RETURN,                // 0x24
        KEY_L,                     // 0x25
        KEY_J,                     // 0x26
        KEY_APOSTROPHE,            // 0x27
        KEY_K,                     // 0x28
        KEY_SEMICOLON,             // 0x29
        KEY_BACKSLASH,             // 0x2A
        KEY_COMMA,                 // 0x2B
        KEY_SLASH,                 // 0x2C
        KEY_N,                     // 0x2D
        KEY_M,                     // 0x2E
        KEY_PERIOD,                // 0x2F
        KEY_TAB,                   // 0x30
        KEY_SPACE,                 // 0x31
        KEY_TILDE,                 // 0x32
        KEY_BACKSPACE,             // 0x33
        0,                         // 0x34 //?
        KEY_ESCAPE,                // 0x35
        0,                         // 0x36 //?
        KEY_ALT,                   // 0x37 // best mapping for mac Cmd key
        KEY_LSHIFT,                // 0x38
        KEY_CAPSLOCK,              // 0x39
        KEY_MAC_OPT,               // 0x3A // direct map mac Option key -- better than KEY_WIN_WINDOWS
        KEY_CONTROL,               // 0x3B
        KEY_RSHIFT,                // 0x3C
        0,                         // 0x3D
        0,                         // 0x3E
        0,                         // 0x3F
        0,                         // 0x40
        KEY_DECIMAL,               // 0x41
        0,                         // 0x42
        KEY_MULTIPLY,              // 0x43
        0,                         // 0x44
        KEY_ADD,                   // 0x45
        KEY_SUBTRACT,              // 0x46 // secondary code?
        KEY_NUMLOCK,               // 0x47 // also known as Clear on mac...
        KEY_SEPARATOR,             // 0x48 // secondary code? for KPEqual
        0,                         // 0x49
        0,                         // 0x4A
        KEY_DIVIDE,                // 0x4B
        KEY_NUMPADENTER,           // 0x4C
        KEY_DIVIDE,                // 0x4D // secondary code?
        KEY_SUBTRACT,              // 0x4E
        0,                         // 0x4F
        0,                         // 0x50
        KEY_SEPARATOR,             // 0x51 // WHAT IS SEP?  This is KPEqual on mac.
        KEY_NUMPAD0,               // 0x52
        KEY_NUMPAD1,               // 0x53
        KEY_NUMPAD2,               // 0x54
        KEY_NUMPAD3,               // 0x55
        KEY_NUMPAD4,               // 0x56
        KEY_NUMPAD5,               // 0x57
        KEY_NUMPAD6,               // 0x58
        KEY_NUMPAD7,               // 0x59
        0,                         // 0x5A
        KEY_NUMPAD8,               // 0x5B
        KEY_NUMPAD9,               // 0x5C
        0,                         // 0x5D
        0,                         // 0x5E
        0,                         // 0x5F
        KEY_F5,                    // 0x60
        KEY_F6,                    // 0x61
        KEY_F7,                    // 0x62
        KEY_F3,                    // 0x63
        KEY_F8,                    // 0x64
        KEY_F9,                    // 0x65
        0,                         // 0x66
        KEY_F11,                   // 0x67
        0,                         // 0x68
        KEY_PRINT,                 // 0x69
        0,                         // 0x6A
        KEY_SCROLLLOCK,            // 0x6B
        0,                         // 0x6C
        KEY_F10,                   // 0x6D
        0,                         // 0x6E
        KEY_F12,                   // 0x6F
        0,                         // 0x70
        KEY_PAUSE,                 // 0x71
        KEY_INSERT,                // 0x72 // also known as mac Help
        KEY_HOME,                  // 0x73
        KEY_PAGE_UP,               // 0x74
        KEY_DELETE,                // 0x75 // FwdDel
        KEY_F4,                    // 0x76
        KEY_END,                   // 0x77
        KEY_F2,                    // 0x78
        KEY_PAGE_DOWN,             // 0x79
        KEY_F1,                    // 0x7A
        KEY_LEFT,                  // 0x7B
        KEY_RIGHT,                 // 0x7C
        KEY_DOWN,                  // 0x7D
        KEY_UP,                    // 0x7E
        0,                         // 0x7F
        0,                         // 0x80
        0,                         // 0x81
        0,                         // 0x82
        0,                         // 0x83
        0,                         // 0x84
        0,                         // 0x85
        0,                         // 0x86
        0,                         // 0x87
        0,                         // 0x88
        0,                         // 0x89
        0,                         // 0x8A
        0,                         // 0x8B
        0,                         // 0x8C
        0,                         // 0x8D
        0,                         // 0x8E
        0,                         // 0x8F

        0,                         // 0x90
        0,                         // 0x91
        0,                         // 0x92
        0,                         // 0x93
        0,                         // 0x94
        0,                         // 0x95
        0,                         // 0x96
        0,                         // 0x97
        0,                         // 0x98
        0,                         // 0x99
        0,                         // 0x9A
        0,                         // 0x9B
        0,                         // 0x9C
        0,                         // 0x9D
        0,                         // 0x9E
        0,                         // 0x9F

        0,                         // 0xA0
        0,                         // 0xA1
        0,                         // 0xA2
        0,                         // 0xA3
        0,                         // 0xA4
        0,                         // 0xA5
        0,                         // 0xA6
        0,                         // 0xA7
        0,                         // 0xA8
        0,                         // 0xA9
        0,                         // 0xAA
        0,                         // 0xAB
        0,                         // 0xAC
        0,                         // 0xAD
        0,                         // 0xAE
        0,                         // 0xAF
        0,                         // 0xB0
        0,                         // 0xB1
        0,                         // 0xB2
        0,                         // 0xB3
        0,                         // 0xB4
        0,                         // 0xB5
        0,                         // 0xB6
        0,                         // 0xB7
        0,                         // 0xB8
        0,                         // 0xB9
        0,                         // 0xBA
        0,                         // 0xBB
        0,                         // 0xBC
        0,                         // 0xBD
        0,                         // 0xBE
        0,                         // 0xBF
        0,                         // 0xC0
        0,                         // 0xC1
        0,                         // 0xC2
        0,                         // 0xC3
        0,                         // 0xC4
        0,                         // 0xC5
        0,                         // 0xC6
        0,                         // 0xC7
        0,                         // 0xC8
        0,                         // 0xC9
        0,                         // 0xCA
        0,                         // 0xCB
        0,                         // 0xCC
        0,                         // 0xCD
        0,                         // 0xCE
        0,                         // 0xCF
        0,                         // 0xD0
        0,                         // 0xD1
        0,                         // 0xD2
        0,                         // 0xD3
        0,                         // 0xD4
        0,                         // 0xD5
        0,                         // 0xD6
        0,                         // 0xD7
        0,                         // 0xD8
        0,                         // 0xD9
        0,                         // 0xDA
        0,                         // 0xDB
        0,                         // 0xDC
        0,                         // 0xDD
        0,                         // 0xDE
        0,                         // 0xDF
        0,                         // 0xE0
        0,                         // 0xE1
        0,                         // 0xE2
        0,                         // 0xE3
        0,                         // 0xE4

        0,                         // 0xE5

        0,                         // 0xE6
        0,                         // 0xE7
        0,                         // 0xE8
        0,                         // 0xE9
        0,                         // 0xEA
        0,                         // 0xEB
        0,                         // 0xEC
        0,                         // 0xED
        0,                         // 0xEE
        0,                         // 0xEF

        0,                         // 0xF0
        0,                         // 0xF1
        0,                         // 0xF2
        0,                         // 0xF3
        0,                         // 0xF4
        0,                         // 0xF5

        0,                         // 0xF6
        0,                         // 0xF7
        0,                         // 0xF8
        0,                         // 0xF9
        0,                         // 0xFA
        0,                         // 0xFB
        0,                         // 0xFC
        0,                         // 0xFD
        0,                         // 0xFE
        0                          // 0xFF
};


U8 TranslateOSKeyCode(U8 vcode)
{
    return VcodeRemap[vcode];
}