/*
 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
 */

#import "common.h"

#import "GlassKey.h"
#import "GlassMacros.h"

#import "com_sun_glass_events_KeyEvent.h"

//#define VERBOSE
#ifndef VERBOSE
    #define LOG(MSG, ...)
#else
    #define LOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__);
#endif

struct KeyMapEntry
{
    unsigned short	keyCode;
    jint			jKeyCode;
    BOOL			sendJavaChars;
};

static const struct KeyMapEntry gKeyMap[] =
{
    {0x00, com_sun_glass_events_KeyEvent_VK_A, YES},
    {0x01, com_sun_glass_events_KeyEvent_VK_S, YES},
    {0x02, com_sun_glass_events_KeyEvent_VK_D, YES},
    {0x03, com_sun_glass_events_KeyEvent_VK_F, YES},
    {0x04, com_sun_glass_events_KeyEvent_VK_H, YES},
    {0x05, com_sun_glass_events_KeyEvent_VK_G, YES},
    {0x06, com_sun_glass_events_KeyEvent_VK_Z, YES},
    {0x07, com_sun_glass_events_KeyEvent_VK_X, YES},
    {0x08, com_sun_glass_events_KeyEvent_VK_C, YES},
    {0x09, com_sun_glass_events_KeyEvent_VK_V, YES},
    {0x0A, com_sun_glass_events_KeyEvent_VK_BACK_QUOTE, YES},
    {0x0B, com_sun_glass_events_KeyEvent_VK_B, YES},
    {0x0C, com_sun_glass_events_KeyEvent_VK_Q, YES},
    {0x0D, com_sun_glass_events_KeyEvent_VK_W, YES},
    {0x0E, com_sun_glass_events_KeyEvent_VK_E, YES},
    {0x0F, com_sun_glass_events_KeyEvent_VK_R, YES},
    {0x10, com_sun_glass_events_KeyEvent_VK_Y, YES},
    {0x11, com_sun_glass_events_KeyEvent_VK_T, YES},
    {0x12, com_sun_glass_events_KeyEvent_VK_1, YES},
    {0x13, com_sun_glass_events_KeyEvent_VK_2, YES},
    {0x14, com_sun_glass_events_KeyEvent_VK_3, YES},
    {0x15, com_sun_glass_events_KeyEvent_VK_4, YES},
    {0x16, com_sun_glass_events_KeyEvent_VK_6, YES},
    {0x17, com_sun_glass_events_KeyEvent_VK_5, YES},
    {0x18, com_sun_glass_events_KeyEvent_VK_EQUALS, YES},
    {0x19, com_sun_glass_events_KeyEvent_VK_9, YES},
    {0x1A, com_sun_glass_events_KeyEvent_VK_7, YES},
    {0x1B, com_sun_glass_events_KeyEvent_VK_MINUS, YES},
    {0x1C, com_sun_glass_events_KeyEvent_VK_8, YES},
    {0x1D, com_sun_glass_events_KeyEvent_VK_0, YES},
    {0x1E, com_sun_glass_events_KeyEvent_VK_CLOSE_BRACKET, YES},
    {0x1F, com_sun_glass_events_KeyEvent_VK_O, YES},
    {0x20, com_sun_glass_events_KeyEvent_VK_U, YES},
    {0x21, com_sun_glass_events_KeyEvent_VK_OPEN_BRACKET, YES},
    {0x22, com_sun_glass_events_KeyEvent_VK_I, YES},
    {0x23, com_sun_glass_events_KeyEvent_VK_P, YES},
    {0x24, com_sun_glass_events_KeyEvent_VK_ENTER, YES},
    {0x25, com_sun_glass_events_KeyEvent_VK_L, YES},
    {0x26, com_sun_glass_events_KeyEvent_VK_J, YES},
    {0x27, com_sun_glass_events_KeyEvent_VK_QUOTE, YES},
    {0x28, com_sun_glass_events_KeyEvent_VK_K, YES},
    {0x29, com_sun_glass_events_KeyEvent_VK_SEMICOLON, YES},
    {0x2A, com_sun_glass_events_KeyEvent_VK_BACK_SLASH, YES},
    {0x2B, com_sun_glass_events_KeyEvent_VK_COMMA, YES},
    {0x2C, com_sun_glass_events_KeyEvent_VK_SLASH, YES},
    {0x2D, com_sun_glass_events_KeyEvent_VK_N, YES},
    {0x2E, com_sun_glass_events_KeyEvent_VK_M, YES},
    {0x2F, com_sun_glass_events_KeyEvent_VK_PERIOD, YES},
    {0x30, com_sun_glass_events_KeyEvent_VK_TAB, YES},
    {0x31, com_sun_glass_events_KeyEvent_VK_SPACE, YES},
    {0x32, com_sun_glass_events_KeyEvent_VK_BACK_QUOTE, YES},
    {0x33, com_sun_glass_events_KeyEvent_VK_BACKSPACE, NO},
    {0x34, com_sun_glass_events_KeyEvent_VK_ENTER, YES},
    {0x35, com_sun_glass_events_KeyEvent_VK_ESCAPE, NO},
    {0x36, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
//	{0x37, com_sun_glass_events_KeyEvent_VK_META, NO},
//	{0x38, com_sun_glass_events_KeyEvent_VK_SHIFT, NO},
    {0x39, com_sun_glass_events_KeyEvent_VK_CAPS_LOCK, NO},
//	{0x3A, com_sun_glass_events_KeyEvent_VK_ALT, NO},
//	{0x3B, com_sun_glass_events_KeyEvent_VK_CONTROL, NO},
    {0x3C, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
    {0x3D, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
    {0x3E, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
    {0x3F, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
    {0x40, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
    {0x41, com_sun_glass_events_KeyEvent_VK_DECIMAL, YES},
    {0x42, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
    {0x43, com_sun_glass_events_KeyEvent_VK_MULTIPLY, YES},
    {0x44, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
    {0x45, com_sun_glass_events_KeyEvent_VK_ADD, YES},
    {0x46, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
    {0x47, com_sun_glass_events_KeyEvent_VK_CLEAR, NO},
    {0x48, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
    {0x49, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
    {0x4A, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
    {0x4B, com_sun_glass_events_KeyEvent_VK_DIVIDE, YES},
    {0x4C, com_sun_glass_events_KeyEvent_VK_ENTER, YES},
    {0x4D, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
    {0x4E, com_sun_glass_events_KeyEvent_VK_SUBTRACT, YES},
    {0x4F, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
    {0x50, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
    {0x51, com_sun_glass_events_KeyEvent_VK_EQUALS, YES},
    {0x52, com_sun_glass_events_KeyEvent_VK_NUMPAD0, YES},
    {0x53, com_sun_glass_events_KeyEvent_VK_NUMPAD1, YES},
    {0x54, com_sun_glass_events_KeyEvent_VK_NUMPAD2, YES},
    {0x55, com_sun_glass_events_KeyEvent_VK_NUMPAD3, YES},
    {0x56, com_sun_glass_events_KeyEvent_VK_NUMPAD4, YES},
    {0x57, com_sun_glass_events_KeyEvent_VK_NUMPAD5, YES},
    {0x58, com_sun_glass_events_KeyEvent_VK_NUMPAD6, YES},
    {0x59, com_sun_glass_events_KeyEvent_VK_NUMPAD7, YES},
    {0x5A, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
    {0x5B, com_sun_glass_events_KeyEvent_VK_NUMPAD8, YES},
    {0x5C, com_sun_glass_events_KeyEvent_VK_NUMPAD9, YES},
    {0x5D, com_sun_glass_events_KeyEvent_VK_BACK_SLASH, YES},
    {0x5E, com_sun_glass_events_KeyEvent_VK_UNDERSCORE, YES},
    {0x5F, com_sun_glass_events_KeyEvent_VK_COMMA, YES},
    {0x60, com_sun_glass_events_KeyEvent_VK_F5, NO},
    {0x61, com_sun_glass_events_KeyEvent_VK_F6, NO},
    {0x62, com_sun_glass_events_KeyEvent_VK_F7, NO},
    {0x63, com_sun_glass_events_KeyEvent_VK_F3, NO},
    {0x64, com_sun_glass_events_KeyEvent_VK_F8, NO},
    {0x65, com_sun_glass_events_KeyEvent_VK_F9, NO},
//	{0x66, com_sun_glass_events_KeyEvent_VK_ALPHANUMERIC, NO},
    {0x67, com_sun_glass_events_KeyEvent_VK_F11, NO},
//	{0x68, com_sun_glass_events_KeyEvent_VK_KATAKANA, NO},
//	{0x69, com_sun_glass_events_KeyEvent_VK_F13, NO},
//	{0x6A, com_sun_glass_events_KeyEvent_VK_F16, NO},
//	{0x6B, com_sun_glass_events_KeyEvent_VK_F14, NO},
    {0x6C, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
    {0x6D, com_sun_glass_events_KeyEvent_VK_F10, NO},
    {0x6E, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
    {0x6F, com_sun_glass_events_KeyEvent_VK_F12, NO},
    {0x70, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
//	{0x71, com_sun_glass_events_KeyEvent_VK_F15, NO},
    {0x72, com_sun_glass_events_KeyEvent_VK_HELP, NO},
    {0x73, com_sun_glass_events_KeyEvent_VK_HOME, NO},
    {0x74, com_sun_glass_events_KeyEvent_VK_PAGE_UP, NO},
    {0x75, com_sun_glass_events_KeyEvent_VK_DELETE, NO},
    {0x76, com_sun_glass_events_KeyEvent_VK_F4, NO},
    {0x77, com_sun_glass_events_KeyEvent_VK_END, NO},
    {0x78, com_sun_glass_events_KeyEvent_VK_F2, NO},
    {0x79, com_sun_glass_events_KeyEvent_VK_PAGE_DOWN, NO},
    {0x7A, com_sun_glass_events_KeyEvent_VK_F1, NO},
    {0x7B, com_sun_glass_events_KeyEvent_VK_LEFT, NO},
    {0x7C, com_sun_glass_events_KeyEvent_VK_RIGHT, NO},
    {0x7D, com_sun_glass_events_KeyEvent_VK_DOWN, NO},
    {0x7E, com_sun_glass_events_KeyEvent_VK_UP, NO},
    {0x7F, com_sun_glass_events_KeyEvent_VK_UNDEFINED, NO},
};
static const int gKeyMapSize = sizeof(gKeyMap) / sizeof(struct KeyMapEntry);

jint GetJavaModifiers(NSEvent *event)
{
    jint jModifiers = 0;
    
    NSUInteger modifierFlags = ([event modifierFlags] & NSDeviceIndependentModifierFlagsMask);
    if (((modifierFlags & NSShiftKeyMask) != 0) == YES)
    {
        jModifiers |= com_sun_glass_events_KeyEvent_MODIFIER_SHIFT;
    }
    if (((modifierFlags & NSFunctionKeyMask) != 0) == YES)
    {
        jModifiers |= com_sun_glass_events_KeyEvent_MODIFIER_FUNCTION;
    }
    if (((modifierFlags & NSControlKeyMask) != 0) == YES)
    {
        jModifiers |= com_sun_glass_events_KeyEvent_MODIFIER_CONTROL;
    }
    if (((modifierFlags & NSAlternateKeyMask) != 0) == YES)
    {
        jModifiers |= com_sun_glass_events_KeyEvent_MODIFIER_OPTION;
    }
    if (((modifierFlags & NSCommandKeyMask) != 0) == YES)
    {
        jModifiers |= com_sun_glass_events_KeyEvent_MODIFIER_COMMAND;
    }

    NSUInteger buttons = [NSEvent pressedMouseButtons];
    if (buttons & (1 << 0)) {
        jModifiers |= com_sun_glass_events_KeyEvent_MODIFIER_BUTTON_PRIMARY;
    }
    if (buttons & (1 << 1)) {
        jModifiers |= com_sun_glass_events_KeyEvent_MODIFIER_BUTTON_SECONDARY;
    }
    if (buttons & (1 << 2)) {
        jModifiers |= com_sun_glass_events_KeyEvent_MODIFIER_BUTTON_MIDDLE;
    }
    
    return jModifiers;
}

jint GetJavaKeyCode(NSEvent *event)
{
    unsigned short keyCode = [event keyCode];
    // Not the fastest implementation...
    for (int i=0; i<gKeyMapSize; i++)
    {
        if (gKeyMap[i].keyCode == keyCode)
        {
            return gKeyMap[i].jKeyCode;
        }
    }
    return com_sun_glass_events_KeyEvent_VK_UNDEFINED;
}

jcharArray GetJavaKeyChars(JNIEnv *env, NSEvent *event)
{
    NSString *chars = [event characters];
    
    unsigned short keyCode = [event keyCode];
    BOOL needChars = NO;
    // Not the fastest implementation...
    for (int i=0; i<gKeyMapSize; i++)
    {
        if (gKeyMap[i].keyCode == keyCode)
        {
            needChars = gKeyMap[i].sendJavaChars;
            break;
        }
    }
    if (needChars == NO)
    {
        // Return an empty array instead of NULL
        return (*env)->NewCharArray(env, 0);
    }
    
    jchar jc[16];
    [chars getCharacters:jc range:NSMakeRange(0, [chars length])];
    jcharArray jChars = (*env)->NewCharArray(env, [chars length]);
    (*env)->SetCharArrayRegion(env, jChars, 0, [chars length], jc);
    return jChars;
}

BOOL GetMacKey(jint javaKeyCode, unsigned short *outMacKeyCode)
{
    for (int index=0; index<gKeyMapSize; index++)
    {
        if (gKeyMap[index].jKeyCode == javaKeyCode)
        {
            *outMacKeyCode = gKeyMap[index].keyCode;
            return YES;
        }
    }
    
    // ??? unknown VK
    return NO;
}

/*
 * Class:     com_sun_glass_events_KeyEvent
 * Method:    _getKeyCodeForChar
 * Signature: (C)I
 */
JNIEXPORT jint JNICALL Java_com_sun_glass_events_KeyEvent__1getKeyCodeForChar
(JNIEnv * env, jclass cls, jchar c)
{
    LOG("Java_com_sun_glass_events_KeyEvent__1getKeyCodeForChar");
    
    //TODO
    return com_sun_glass_events_KeyEvent_VK_UNDEFINED;
}

