#include <stdio.h>
#include "le_info.h"
#include "le_session.h"

#include "wtt_isc.h"
#include "thai_key.h"
#include "thai_common.h"
#include "encode.h"

void encode_commit(iml_session_t * s, int encode,
		   unsigned char *commit_buf);
void encode_draw_status(iml_session_t * s, int encode,
			unsigned char *status_buf);
void le_commit_key(iml_session_t * s, unsigned char key);
void le_status_draw(iml_session_t * s, int on);
int le_session_map_keyevent_to_immkey(IMKeyEventStruct * key_event);
int le_session_map_keyevent_to_imekey(IMKeyEventStruct * key_event);
void le_session_process_key_output(iml_session_t * s, unsigned char key);

extern char *wtt_isc_mode_names[];
extern LeInfoRec *le_info;

/* process the keyboard event */
void le_session_process_key_event(iml_session_t * s,
				  IMKeyListEvent * keylistevent)
{
    int key_ret, input_mode_id;
    IMKeyEventStruct *key_event =
	(IMKeyEventStruct *) keylistevent->keylist;

    key_ret = le_session_map_keyevent_to_immkey(key_event);

    switch (key_ret) {
	/* English status <----> Thai status */
    case ENGLISH_THAI_SWITCH_KEY:
	le_session_set_conversion_status(s, CONVERSION_OFF);
	return;

	/* Roundly Switch Input methods */
    case MODE_SWITCH_KEY:
	input_mode_id = le_session_get_isc_mode(s);
	input_mode_id = (input_mode_id + 1) % WTT_ISC_MODES_NUM;
	le_session_save_isc_mode(s, input_mode_id);
	le_status_draw(s, CONVERSION_ON);
	return;
    }

    key_ret = le_session_map_keyevent_to_imekey(key_event);
    if (key_ret == IME_NOT_USED_KEY) {
	le_session_save_previous_char(s, 0);
	le_iml_sendback_key(s, key_event);
	return;
    }

    le_session_process_key_output(s, key_ret);
}

/* filter keys that used by Input Methods Manager */
int le_session_map_keyevent_to_immkey(IMKeyEventStruct * key_event)
{
    int keycode, keystatus, keychar;

    keycode = key_event->keyCode;
    keychar = key_event->keyChar;
    keystatus = key_event->modifier;

    DEBUG_printf("keycode: 0x%x, keychar:0x%x, keystatus: 0x%x\n", keycode,
		 keychar, keystatus);

    /* Function Keys */
    if (keycode == IM_VK_F2)
	return (MODE_SWITCH_KEY);

    /* Ctrl + Space */
    if ((keycode == IM_VK_SPACE) && (keystatus & IM_CTRL_MASK))
	return (ENGLISH_THAI_SWITCH_KEY);

    return (IMM_NOT_USED_KEY);
}

/*  get the keys that IME will use */
int le_session_map_keyevent_to_imekey(IMKeyEventStruct * key_event)
{
    int keycode, keystatus, keychar;

    keycode = key_event->keyCode;
    keychar = key_event->keyChar;
    keystatus = key_event->modifier;

    /* fix bug 4700325: when switch to Thai IM, Numpad doesn't work as expected */
    if (keycode >= IM_VK_NUMPAD0 && keycode <= IM_VK_DIVIDE)
	return (IME_NOT_USED_KEY);

    /* fix bug 4708815: Thai IM gives English character */
    if (keycode >= IM_VK_COMMA && keycode <= IM_VK_CLOSE_BRACKET) {
	if (!(keystatus & IM_CTRL_MASK) &&
	    !(keystatus & IM_META_MASK) &&
	    !(keystatus & IM_ALT_MASK) && !(keystatus & IM_ALT_GRAPH_MASK))
	    return (keychar);
    }

    return (IME_NOT_USED_KEY);
}

void le_status_draw(iml_session_t * s, int on)
{
    char status_string[128];
    char *mode_string;
    int input_mode_id;

    sprintf(status_string, "[ %s ]", (char *) ENGLISH_LANG_NAME);
    if (on == CONVERSION_ON) {
        input_mode_id = le_session_get_isc_mode(s);
        mode_string = (char *) wtt_isc_mode_names[input_mode_id];
	sprintf(status_string, "[ %s ] [ %s ]", (char *) THAI_LANG_NAME,
	        mode_string);
    }

    encode_draw_status(s, ENCODE_EUCTH, status_string);
}

void le_commit_key(iml_session_t * s, unsigned char key)
{
    unsigned char key_string[2];
    key_string[0] = key;
    key_string[1] = 0;

    encode_commit(s, ENCODE_EUCTH, key_string);
}

void le_session_process_key_output(iml_session_t * s, unsigned char key)
{
    int input_mode_id;
    int keyboard_id;
    int ret;

    unsigned char previous_char, following_char;

    input_mode_id = le_session_get_isc_mode(s);
    keyboard_id = le_session_get_keyboard_mode(s);

    DEBUG_printf
	("le_session_process_key_output: Mode_ID:%d, nKeyboardID:%d\n",
	 input_mode_id, keyboard_id);

    previous_char = le_session_get_previous_char(s);
    following_char =
	ThaiKeymapList_Item_Get_Symbol(le_info->keymap_list, keyboard_id,
				       key);

    ret = THAI_isaccepted(following_char, previous_char, input_mode_id);
    if (ret == True) {
	le_session_save_previous_char(s, following_char);
	le_commit_key(s, following_char);
    }
#if 0
    if (previous_char) {
	printf("previous_char: %c\t", previous_char);
    } else {
	printf("previous_char: 0\t");
    }

    if (following_char) {
	printf("following_char: %c\t", following_char);
    } else {
	printf("following_char: 0\t");
    }

    printf("accepted: %s\n", ret ? "True" : "False");
#endif
}

int encode_to_unicode(int encode, unsigned char *from, int from_len,
		      UTFCHAR * to, int to_len)
{
    int to_left, ret;
    char *to_ptr;

    DEBUG_printf("encode_to_unicode: from:%s, encode:%d\n", from, encode);
    to_left = to_len;
    ret =
	Convert_Native_To_UTF16(encode, from, from_len, (char **) &to,
				(size_t *) & to_left);
    DEBUG_printf("encode_to_unicode: return:%d, to_left:%d\n", ret,
		 to_left);
    if (ret == -1) {
	to[0] = (UTFCHAR) 0;
    } else {
	if (to_left > 2) {
	    to_ptr = (char *) to;
	    to_ptr[to_len - to_left] = 0;
	    to_ptr[to_len - to_left + 1] = 0;
	}
    }
    return (ret);
}

void encode_draw_status(iml_session_t * s, int encode,
			unsigned char *status_buf)
{
#define MAX_STATUS_CHAR_NUM   32
    static UTFCHAR Status_Buffer[MAX_STATUS_CHAR_NUM * 2];
    int status_len;
    int ret;

    status_len = strlen((char *) status_buf);
    if (status_len <= 0)
	return;

    ret =
	encode_to_unicode(encode, status_buf, status_len, Status_Buffer,
			  MAX_STATUS_CHAR_NUM * 2);
    if (ret != -1) {
	le_iml_status_draw(s, Status_Buffer);
    }
}

void encode_commit(iml_session_t * s, int encode,
		   unsigned char *commit_buf)
{
#define MAX_COMMIT_CHAR_NUM   32
    static UTFCHAR Commit_Buffer[MAX_COMMIT_CHAR_NUM * 2];
    int commit_len;
    int ret;

    commit_len = strlen((char *) commit_buf);
    if (commit_len <= 0)
	return;

    ret =
	encode_to_unicode(encode, commit_buf, commit_len, Commit_Buffer,
			  MAX_COMMIT_CHAR_NUM * 2);
    if (ret != -1) {
	le_iml_commit(s, Commit_Buffer);
    }
}
