#include "et9keyboardDatabase.h"
#include <malloc.h>


#include <stdlib.h>

#include "et9api.h"

#include "log.h"

int ET9KEY_OEM;

ET9STATUS ET9SetKeyboardDatabase(JNIEnv *env, jclass jcls,jobject jXT9KeyboardDatabase) {
	    jshort wStatus = ET9STATUS_ERROR;
	    CacheJavaFieldAndClassIDs(env, jXT9KeyboardDatabase);


	    int kdbId = (*env)->GetIntField(env, jXT9KeyboardDatabase, g_sXT9KeyboardDatabase.id);
	    int kdbPage = (*env)->GetIntField(env, jXT9KeyboardDatabase, g_sXT9KeyboardDatabase.page);
	    int layoutWidth = (*env)->GetIntField(env,  jXT9KeyboardDatabase, g_sXT9KeyboardDatabase.width);
	    int layoutHeight = (*env)->GetIntField(env,  jXT9KeyboardDatabase, g_sXT9KeyboardDatabase.height);

	    ET9KEY_OEM = 0x0B78;

	    // list of keys
	    jobject keyList = (*env)->GetObjectField(env, jXT9KeyboardDatabase, g_sXT9KeyboardDatabase.keys);
		
	    int keyCount = (*env)->CallIntMethod(env, keyList, g_sListClass.size);

	    setProperties(kdbId, kdbPage, layoutWidth, layoutHeight, keyCount);
	    
	    int i = 0;

	    // add keys to the current keyboard database
	    for (i ; i < keyCount; i++) {
	        // get the key object from the list
	       
	        jobject keyObject = (*env)->CallObjectMethod(env, keyList, g_sListClass.get, i);

	        // get the char[] codes define in the class object
	        jobject codesObject = (*env)->GetObjectField(env, keyObject, g_sXT9KeyboardDatabase_Key.codes);
		    jobject shfitCodesObject = (*env)->GetObjectField(env, keyObject, g_sXT9KeyboardDatabase_Key.shiftCodes);

	        // deference it
	        
	        jintArray* intArray = /*reinterpret_cast<jintArray*>*/(&codesObject);
	        jint* codes = (*env)->GetIntArrayElements(env, *intArray, NULL);
	        int len = (*env)->GetArrayLength(env, *intArray);

		    jintArray* shiftCodesArray = (&shfitCodesObject);
		    jint* shiftCodes = (*env)->GetIntArrayElements(env, *shiftCodesArray, NULL);
		    int shiftLen = (*env)->GetArrayLength(env, *shiftCodesArray);

	        int type = (*env)->GetIntField(env, keyObject, g_sXT9KeyboardDatabase_Key.type);
	        int x = (*env)->GetIntField(env, keyObject, g_sXT9KeyboardDatabase_Key.x);
	        int y = (*env)->GetIntField(env, keyObject, g_sXT9KeyboardDatabase_Key.y);
	        int w = (*env)->GetIntField(env, keyObject, g_sXT9KeyboardDatabase_Key.width);
	        int h = (*env)->GetIntField(env, keyObject, g_sXT9KeyboardDatabase_Key.height);

	        addKey(type, codes, len, shiftCodes, shiftLen, x, y, x + w - 1, y + h - 1, &ET9KEY_OEM);

	        if(ET9KEY_OEM == 0x0B80){
	        	ET9KEY_OEM = 0x0B50;
	       	}

	       	if(ET9KEY_OEM == 0x0B55){
	       	  	ET9KEY_OEM = 0xAA37;
	       	}

	        (*env)->ReleaseIntArrayElements(env, *intArray, codes, 0);
                (*env)->ReleaseIntArrayElements(env, *shiftCodesArray, shiftCodes, 0);
	        (*env)->DeleteLocalRef(env, keyObject);
	    }

	return wStatus;
}

ET9STATUS CacheJavaFieldAndClassIDs(JNIEnv *env,  jobject jXT9KeyboardDatabase)
{
	jshort wStatus = ET9STATUS_NONE;
	jclass cls;
	cls = (*env)->GetObjectClass(env, jXT9KeyboardDatabase);

	if (g_sXT9KeyboardDatabase.clazz == NULL) {
	        g_sXT9KeyboardDatabase.clazz = (*env)->FindClass(env, "com/diotek/ime/framework/engine/xt9/XT9KeyboardDatabase");
	        g_sXT9KeyboardDatabase.id = (*env)->GetFieldID(env, g_sXT9KeyboardDatabase.clazz, "id", "I");
	        g_sXT9KeyboardDatabase.page = (*env)->GetFieldID(env, g_sXT9KeyboardDatabase.clazz, "page", "I");
	        g_sXT9KeyboardDatabase.width = (*env)->GetFieldID(env, g_sXT9KeyboardDatabase.clazz, "width", "I");
	        g_sXT9KeyboardDatabase.height = (*env)->GetFieldID(env, g_sXT9KeyboardDatabase.clazz, "height", "I");
	        g_sXT9KeyboardDatabase.keys = (*env)->GetFieldID(env, g_sXT9KeyboardDatabase.clazz, "keys", "Ljava/util/List;");
		
	        g_sXT9KeyboardDatabase_Key.clazz = (*env)->FindClass(env, "com/diotek/ime/framework/engine/xt9/XT9KeyboardDatabase$XT9Key");
	        g_sXT9KeyboardDatabase_Key.codes = (*env)->GetFieldID(env, g_sXT9KeyboardDatabase_Key.clazz , "codes", "[I");		 
	        g_sXT9KeyboardDatabase_Key.type = (*env)->GetFieldID(env, g_sXT9KeyboardDatabase_Key.clazz ,"type", "I");			
	       g_sXT9KeyboardDatabase_Key.x = (*env)->GetFieldID(env, g_sXT9KeyboardDatabase_Key.clazz , "x", "I");		   
	        g_sXT9KeyboardDatabase_Key.y = (*env)->GetFieldID(env, g_sXT9KeyboardDatabase_Key.clazz , "y", "I");			
	        g_sXT9KeyboardDatabase_Key.width = (*env)->GetFieldID(env, g_sXT9KeyboardDatabase_Key.clazz , "width", "I");			
	        g_sXT9KeyboardDatabase_Key.height = (*env)->GetFieldID(env, g_sXT9KeyboardDatabase_Key.clazz , "height", "I");			
	    	g_sXT9KeyboardDatabase_Key.shiftCodes = (*env)->GetFieldID(env, g_sXT9KeyboardDatabase_Key.clazz , "shiftCodes", "[I");			
	}

	if (g_sListClass.clazz == NULL) {
		g_sListClass.clazz = (*env)->FindClass(env, "java/util/List");
		g_sListClass.size  = (*env)->GetMethodID(env, g_sListClass.clazz, "size", "()I");
		g_sListClass.get   = (*env)->GetMethodID(env, g_sListClass.clazz, "get", "(I)Ljava/lang/Object;");
		g_sListClass.add   = (*env)->GetMethodID(env, g_sListClass.clazz, "add", "(Ljava/lang/Object;)Z");			
	}
	return wStatus;
}

ET9STATUS dynamicKdbLoadCallback(ET9KDBInfo *pKDBInfo, const ET9U32 dwKdbNum, const ET9U16 swPageNum){
	ET9STATUS status = ET9STATUS_READ_DB_FAIL;

	if ( (ET9U32) g_mKeyboardDatabase.kdbId == dwKdbNum && g_mKeyboardDatabase.kdbPage == swPageNum) {
	    	status = ET9KDB_Load_Reset(pKDBInfo);
	    	if (status != ET9STATUS_NONE) {
 		} else {
	    		ET9U8 primaryId   = (ET9U8)( g_mKeyboardDatabase.kdbId & 0x00ff);
	    		ET9U8 secondaryId = (ET9U8)(( g_mKeyboardDatabase.kdbId) >> 8);
	    		ET9U16 width = (ET9U16) g_mKeyboardDatabase.width;
	    		ET9U16 height = (ET9U16) g_mKeyboardDatabase.height;
	    		ET9U16 totalPages = (ET9U16) g_mKeyboardDatabase.totalPages;

				status = ET9KDB_Load_SetProperties(pKDBInfo, 1, 0, primaryId, secondaryId, width, height, totalPages);
				
				if (status != ET9STATUS_NONE) {
		    		
			} else {
					int i = 0 ;
					for (i = 0; i <  g_mKeyboardDatabase.numbKeys; i++) {
						mPkey key = & g_mKeyboardDatabase.keys[i];
			    		
						status = ET9KDB_Load_AddKey(pKDBInfo, key->index, key->type, key->left, key->top, key->right, key->bottom,
								 key->charsCount, key->chars);

						if (status != ET9STATUS_NONE) {
							__android_log_print(ANDROID_LOG_DEBUG,"SamsungIME","ET9KDB_Load_AddKey - key->index : %d, key->type %d, error : %d", key->index, key->type, status);
							return SAMSUNG_STATUS_KDB_FAIL;
						}
						if (key->shiftedCharsCount > 0) {
							status = ET9KDB_Load_AttachShiftedChars(pKDBInfo, key->shiftedCharsCount, key->shiftedChars);
							if (status != ET9STATUS_NONE) {
								__android_log_print(ANDROID_LOG_DEBUG,"SamsungIME","ET9KDB_Load_AttachShiftedChars - key->index : %d, key->type %d, error : %d", key->index, key->type, status);
								return SAMSUNG_STATUS_KDB_FAIL;
							}
						}

						// if it is naragul keyboard...
						if(primaryId == 0x12 && secondaryId == 0x12
								&& (key->type == ET9LKT_REGIONAL || key->type == ET9LKT_NONREGIONAL)) {
							status = ET9KDB_Load_AttachMultitapInfo(pKDBInfo, key->charsCount, key->chars, 0, NULL);
							if (status != ET9STATUS_NONE) {
								break;
							}
						}

					}
				}
			if (status == ET9STATUS_NONE) {
				ET9KDB_Load_SetSmartTouch(pKDBInfo, TRUE, 1.0f);
			}
	    	}
	} else {
    }

    return (status);
}

ET9STATUS setProperties(int kdbId, int kdbPage, unsigned short width, unsigned short height, unsigned short maxKeys)
{
    g_mKeyboardDatabase.hashCode = width + height + maxKeys + 1;

    g_mKeyboardDatabase.numbKeys = 0;
    g_mKeyboardDatabase.kdbId = kdbId;
    g_mKeyboardDatabase.kdbPage= kdbPage;
    g_mKeyboardDatabase.width = width;
    g_mKeyboardDatabase.height = height;
    g_mKeyboardDatabase.totalPages = 0x3fff;

    free(g_mKeyboardDatabase.keys);

    if (maxKeys > 0) {
        g_mKeyboardDatabase.keys = (mkey*)calloc(maxKeys, sizeof(mkey));
    }

    g_mKeyboardDatabase.maxKeys = maxKeys;
    g_mKeyboardDatabase.numbKeys = 0;

    return ET9STATUS_NONE;
}

ET9STATUS addKey(int type, int* chars, unsigned short charsCount, int* shiftedChars, unsigned short shiftedCharsCount, unsigned short left, unsigned short top, unsigned short right, unsigned short bottom, int* oemKeyCode)
{
    if (g_mKeyboardDatabase.numbKeys > g_mKeyboardDatabase.maxKeys) {

        return ET9STATUS_ERROR;
    }

    if (g_mKeyboardDatabase.keys == 0) {

        return ET9STATUS_ERROR;
    }

    ET9LOADKEYTYPE keyType;
    int i = 1;

    if (type != -1) {
		
        keyType = (ET9LOADKEYTYPE)type;
      

    } else if (ET9IsFunctionKeySymbol(chars[0])) {
        keyType = ET9LKT_FUNCTION;


        // Core doesn't allow mixing function keys with other key codes
        for (i = 1; i < charsCount; i++) {
            if (!ET9IsFunctionKeySymbol(chars[i])) {
                
                charsCount = i;
                break;
            }
        }

    } else {
        ET9U8 charClass = ET9GetSymbolClass(chars[0]);
        switch (charClass) {
            case ET9SYMALPHA:
				
                keyType = ET9LKT_REGIONAL;
                break;

            default:
				
                keyType = ET9LKT_NONREGIONAL;
                break;
        }
        

        // Core doesn't allow mixing function keys with other key codes
        
        for ( i =1; i < charsCount; i++) {
            if (ET9IsFunctionKeySymbol(chars[i])) {

                charsCount = i;
                break;
            }
        }
    }

    g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].index = g_mKeyboardDatabase.numbKeys;
    g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].left = left;
    g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].top = top;
    g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].right = right;
    g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].bottom = bottom;
    g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].type = keyType;

    g_mKeyboardDatabase.hashCode = g_mKeyboardDatabase.hashCode + keyType + (bottom - top) + (right - left);

    for (i = 0; i < charsCount && i < 64; i++) {
        g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].chars[i] = (unsigned short)chars[i];
        g_mKeyboardDatabase.hashCode = g_mKeyboardDatabase.hashCode + g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].chars[i];
    }
	if(g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].type == ET9LKT_FUNCTION) {	
		for (i = 0; i < charsCount && i < 64; i++) {
			if (g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].chars[i] != 0x0020) {
       	 	g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].chars[i] = (*oemKeyCode)++ ;
		       }
        		g_mKeyboardDatabase.hashCode = g_mKeyboardDatabase.hashCode + g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].chars[i];
  		  }
   		 g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].charsCount = 1;
	} else {
		for (i = 0; i < charsCount && i < 64; i++) {
	        	g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].chars[i] = (unsigned short)chars[i];
	       	 g_mKeyboardDatabase.hashCode = g_mKeyboardDatabase.hashCode + g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].chars[i];
    		}
		 g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].charsCount = i;
	}

    int count = 0;
    for (i = 0; i < shiftedCharsCount && i < 64; i++) {
        if (!ET9IsFunctionKeySymbol((unsigned short)shiftedChars[i]) && shiftedChars[i] != 0) {
            g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].shiftedChars[count] = (unsigned short)shiftedChars[i];
            g_mKeyboardDatabase.hashCode = g_mKeyboardDatabase.hashCode + g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].shiftedChars[count];
            count++;
        }
    }
    g_mKeyboardDatabase.keys[g_mKeyboardDatabase.numbKeys].shiftedCharsCount = count;

    g_mKeyboardDatabase.numbKeys++;

    return ET9STATUS_NONE;
}