#include <stdio.h>
#include "newpinyin_im.h"

#define NEWPINYIN_VERSION	202
#define NEWPINYIN_NAME_UTF8	"NewPinYin"
#define NEWPINYIN_UUID		"newpinyin-9d3878a2-ca6a-4dbb-9e81-62b3774716c3"
#define NEWPINYIN_AUTHOR	"Ervin Yan <Ervin.Yan@sun.com>"
#define NEWPINYIN_COPYRIGHT	"Copyright (c) 2004 Sun Microsystems"
#define NEWPINYIN_HINTING	"NewPinYin Input Method"
#define NEWPINYIN_ICONPATH	"newpinyin.xpm"

#define NEWSHUANGPIN_UUID	"newshuangpin-6ab65f44-a765-4303-87d5-5d1a0d22f96d"
#define NEWSHUANGPIN_ICONPATH	"newshuangpin.xpm"

ImeResult newpinyin_Initialize(ImeInfo ime_info);
ImeResult newpinyin_Destroy(ImeInfo ime_info);
ImeResult newpinyin_Process_Key_Event(ImeInputContext ic, ImeKey key_event);
ImeResult newpinyin_Create_Session(ImeInputContext ic);
ImeResult newpinyin_Destroy_Session(ImeInputContext ic);
ImeResult newpinyin_FocusIn(ImeInputContext ic);
ImeResult newpinyin_FocusOut(ImeInputContext ic);

ImmServices imm_services;

#define MAX_SESSIONS 1024

typedef struct _newpinyin_im_data_t {
	int   encoding;
	char  opened_session[MAX_SESSIONS];
} newpinyin_im_data_t;

ImeMethodsRec newpinyin_methods = {
	1,                                /* version */
	newpinyin_Initialize,             /* ImeInitialize */
	newpinyin_Destroy,                /* ImeDestroy  */
	newpinyin_Process_Key_Event,      /* ImeProcessKeyEvent */
	NULL,                             /* ImeProcessAuxEvent  */
	newpinyin_Create_Session,         /* ImeAttachSession */
	newpinyin_Destroy_Session,        /* ImeDetachSession */
	newpinyin_FocusIn,                             /* ImeFocusIn  */
	newpinyin_FocusOut,                             /* ImeFocusOut */
	NULL,                             /* ImeAttachUser */
	NULL,                             /* ImeDetachUser */
	NULL,                             /* ImeAttachDesktop */
	NULL,                             /* ImeDetachDesktop */
	NULL,                             /* ImeGetErrorMessage */
#if 0
	NULL,                             /* ImeDoConfig */
#endif
};

#ifdef	WIN32
#define EXPORT extern __declspec(dllexport)
EXPORT
#endif
ImeResult RegisterIME(ImmServices srvs, ImeInfo* ppinfo, ImeMethods* pmthds, int argc, char **argv)
{
	ImeInfoRec *newpinyin_info = NULL;
	int  encoding = ENCODE_GB2312;
	char *encoding_str = NULL;
	char *base_dir = NULL;
	newpinyin_im_data_t *newpinyin_data = NULL;

	int i, ret;

	DEBUG_printf("Register NewPinYin IM: argc: %d\n", argc);
	for (i=0; i<argc; i++) {
		if (!strcasecmp(argv[i], "-basedir")) {
			if (argv[i+1]) {
				base_dir = argv[i+1];
				DEBUG_printf("       setting base dir to: %s\n", argv[i+1]);
			}
			i++;
		} else if (!strcasecmp(argv[i], "-encoding")) {
			if (argv[i+1]) {
				encoding_str = argv[i+1];
				DEBUG_printf("       setting newpinyin file to: %s\n", argv[i+1]);
			}
			i++;
		}
	}

	if (encoding_str && *encoding_str) {
		if (!strcasecmp(encoding_str, "gb2312"))
			encoding = ENCODE_GB2312;
		else if (!strcasecmp(encoding_str, "gbk"))
			encoding = ENCODE_GBK;
	}

	newpinyin_info = (ImeInfoRec *)calloc(1, sizeof(ImeInfoRec));
	DEBUG_printf("newpinyin_info: 0x%x\n", newpinyin_info);
	if (newpinyin_info == NULL)  {
		return (IME_FAIL);
	}
	
	DEBUG_printf("get newpinyin_im_data_t\n");
	newpinyin_data = (newpinyin_im_data_t *)calloc(1, sizeof(newpinyin_im_data_t));
	DEBUG_printf("newpinyin_data: 0x%x\n", newpinyin_data);
	if (newpinyin_data == NULL) {
		free ((char *)newpinyin_info);
		return (IME_FAIL);
	}

	newpinyin_info->version           = NEWPINYIN_VERSION;
#ifdef CompByNewPinyin
	newpinyin_info->name              = "ÐÂÈ«Æ´";
	newpinyin_info->uuid      	  = NEWPINYIN_UUID;
	newpinyin_info->icon_file         = NEWPINYIN_ICONPATH;
#else
	newpinyin_info->name              = "ÐÂË«Æ´";
	newpinyin_info->uuid      	  = NEWSHUANGPIN_UUID;
	newpinyin_info->icon_file         = NEWSHUANGPIN_ICONPATH;
#endif
	newpinyin_info->encoding          = encoding;
	newpinyin_info->author            = NEWPINYIN_AUTHOR;
	newpinyin_info->hinting           = NEWPINYIN_HINTING;
	newpinyin_info->copyright         = NEWPINYIN_COPYRIGHT;
	newpinyin_info->support_locales = "zh_CN.UTF-8,zh_CN.GB18030";

	newpinyin_data->encoding = encoding;
	for (i=0; i<MAX_SESSIONS; i++) {
		newpinyin_data->opened_session[i] = 0;
	}
	newpinyin_data->opened_session[0] = 1;
	newpy_open(0);

	newpinyin_info->specific_data     = (void *)newpinyin_data;

	*ppinfo = newpinyin_info;
	*pmthds = &newpinyin_methods;

	imm_services = srvs;

	DEBUG_printf("begin leave Register IME\n");
	return (IME_OK);
}

ImeResult newpinyin_Initialize(ImeInfo newpinyin_info)
{
	int ret;

	DEBUG_printf("newpinyin_Initialize\n");

/*
	ret = newpy_open(0);
	if (ret == -1)
		return(IME_FAIL);
*/

	return (IME_OK);
}

ImeResult newpinyin_Destroy(ImeInfo newpinyin_info)
{
	int i;
	newpinyin_im_data_t *newpinyin_data;

	DEBUG_printf("newpinyin_Destroy\n");

	if (newpinyin_info != NULL) {
		newpinyin_data = (newpinyin_im_data_t *)newpinyin_info->specific_data;
		if (newpinyin_data) {
			for (i=0; i<MAX_SESSIONS; i++) {
				if (newpinyin_data->opened_session[i] == 1)
					newpy_close(i);
			}

			free ((char *)newpinyin_data);
		}

		free ((char *)newpinyin_info);
	}

	return (IME_OK);
}

ImeResult newpinyin_Create_Session(ImeInputContext ic)
{
	int i, ret;
	ImmResult imm_result;
	ImeBufferRec *ime_buffer = NULL;
	ImeInfoRec *newpinyin_info = NULL;
	newpinyin_im_data_t *newpinyin_data;

	DEBUG_printf("newpinyin_Create_Session \n");
	newpinyin_info = (ImeInfo)imm_services->ImmGetImeInfo(ic);
	DEBUG_printf("newpinyin_info: 0x%x\n", newpinyin_info);
	if (newpinyin_info == NULL || newpinyin_info->specific_data == NULL)
		return (IME_FAIL);

	newpinyin_data = (newpinyin_im_data_t *)newpinyin_info->specific_data;
	DEBUG_printf("newpinyin_data: 0x%x\n", newpinyin_data);
	if (newpinyin_data == NULL)
		return (IME_FAIL);

	ime_buffer = (ImeBufferRec *)imm_services->ImmGetData(ic, IME_SCOPE_SESSION);
	DEBUG_printf("newpinyin_Create_Session ======= begin get ime_session_data: 0x%x\n", ime_buffer);
	if (ime_buffer == NULL) {
		ime_buffer = (ImeBufferRec *)calloc(1, sizeof(ImeBufferRec));
		if (ime_buffer == NULL)
			return (IME_FAIL);

		for (i = 0; i < MAX_CANDIDATES_NUM; i++) {
			ime_buffer->candidates[i] = ime_buffer->candidates_buf[i];
			ime_buffer->comments[i] = ime_buffer->comments_buf[i];
			ime_buffer->lookups[i] = ime_buffer->lookups_buf[i];
		}

		imm_result = imm_services->ImmSetData(ic, IME_SCOPE_SESSION, ime_buffer);
		if (imm_result == IMM_FAIL) {
			free ((char *)ime_buffer);
			return (IME_FAIL);
		}
	}
	
	ime_buffer->session_id = 0;
	for (i = 0; i < MAX_SESSIONS; i++) {
		if (newpinyin_data->opened_session[i] == 0) {
			DEBUG_printf("newpinyin_Create_Session ======= begin newpy_open: %d\n", i);
			ret = newpy_open(i);
			if (ret == -1)
				return (IME_FAIL);
			ime_buffer->session_id = i;
			newpinyin_data->opened_session[i] = 1;
			break;
		}
	}
	return (IME_OK);
}

ImeResult newpinyin_Destroy_Session(ImeInputContext ic)
{
	ImeBufferRec *ime_buffer = NULL;
	ImeInfoRec *newpinyin_info = NULL;
	newpinyin_im_data_t *newpinyin_data;

	newpinyin_info = (ImeInfo)imm_services->ImmGetImeInfo(ic);
	if (newpinyin_info == NULL || newpinyin_info->specific_data == NULL)
		return (IME_FAIL);

	newpinyin_data = (newpinyin_im_data_t *)newpinyin_info->specific_data;
	if (newpinyin_data == NULL)
		return (IME_FAIL);

	ime_buffer = (ImeBufferRec *)imm_services->ImmGetData(ic, IME_SCOPE_SESSION);
	DEBUG_printf("newpinyin_Destroy_Session ======= begin get ime_session_data: 0x%x\n", ime_buffer);

	if (ime_buffer != NULL) {
		DEBUG_printf("newpinyin_Destroy_Session ======= session_id: 0x%x\n", ime_buffer->session_id);
		newpy_close(ime_buffer->session_id);
		newpinyin_data->opened_session[ime_buffer->session_id] = 0;
		free ((char *)ime_buffer);
	}

	imm_services->ImmSetData(ic, IME_SCOPE_SESSION, NULL);

	return (IME_OK);
}

ImeResult newpinyin_FocusIn(ImeInputContext ic)
{
        DEBUG_printf("newpinyin: call newpinyin_FocusIn()\n");
        return(IME_OK);
}

ImeResult newpinyin_FocusOut(ImeInputContext ic)
{
        DEBUG_printf("newpinyin: call newpinyin_FocusOut()\n");
        return(IME_OK);
}

ImmResult newpinyin_beep(ImeInputContext ic)
{
	return (imm_services->ImmBeep(ic, ImeBeepWarning));
}

ImmResult newpinyin_commit(ImeInputContext ic, int encoding, char *commit_buf, int commit_len)
{
	if (commit_len <= 0)
		return (IMM_FAIL);

	if (commit_buf == NULL)
		return (IMM_FAIL);

	return (imm_services->ImmCommit(ic, commit_buf));
}

ImmResult newpinyin_update_preedit(ImeInputContext ic, int encoding,
				   char *preedit_buf, int preedit_len, int caret_pos)
{
	ImePreeditRec ime_preedit;

	memset(&ime_preedit, 0, sizeof(ImePreeditRec));
	if (preedit_len == 0) {
		return (imm_services->ImmHidePreedit(ic));
	}

	imm_services->ImmShowPreedit(ic);

	ime_preedit.caret = caret_pos;
	ime_preedit.preedit.text     = preedit_buf;

	return (imm_services->ImmUpdatePreedit(ic, &ime_preedit));
}

ImmResult newpinyin_update_candidates(ImeInputContext ic, int encoding, char **candidates, int num_candidates)
{
	int i;
	ImmResult imm_result;
	ImeCandidatesRec       ime_candidates;

	memset(&ime_candidates, 0, sizeof(ImeCandidatesRec));

        ime_candidates.horizental = 0;
	
	if (num_candidates == 0 || candidates == NULL) {
		return (imm_services->ImmHideCandidates(ic));
	}

	imm_services->ImmShowCandidates(ic);

	ime_candidates.title = NULL;
        ime_candidates.numbers = NULL;
	ime_candidates.focus = 0;
	ime_candidates.count = num_candidates;
	ime_candidates.candidates = (ImeTextRec *)calloc(num_candidates, sizeof(ImeTextRec));
	if (ime_candidates.candidates == NULL)
		return (IMM_FAIL);

	for (i=0; i<num_candidates; i++) {
		ime_candidates.candidates[i].text = candidates[i];
	}

	imm_result = imm_services->ImmUpdateCandidates(ic, &ime_candidates);

	free ((char *) ime_candidates.candidates);
	return(imm_result);

}

/* process key input event */
/* return value:  IME_UNUSED_KEY:  if IME not use this key, return this key to systerm directly */
/*                IME_KEY_USED:      if IME has used this key */
ImeResult newpinyin_Process_Key_Event(ImeInputContext ic, ImeKey key_event)
{
	ImeInfoRec *newpinyin_info = NULL;
	newpinyin_im_data_t *newpinyin_data;
	ImeBufferRec *ime_buffer = NULL;
	long    kcode, kstate;
	unsigned short kchar;
	int ret;

	DEBUG_printf("newpinyin_Process_Key_Event: ic: 0x%x\n", ic);
	ime_buffer = (ImeBufferRec *)imm_services->ImmGetData(ic, IME_SCOPE_SESSION);
	if (ime_buffer == NULL)
		return (IME_UNUSED_KEY);

	DEBUG_printf("newpinyin_Process_Key_Event ======= begin get ime_session_data: 0x%x\n", ime_buffer);
	newpinyin_info = (ImeInfo)imm_services->ImmGetImeInfo(ic);
	if (newpinyin_info == NULL || newpinyin_info->specific_data == NULL)
		return (IME_UNUSED_KEY);

	newpinyin_data = (newpinyin_im_data_t *)newpinyin_info->specific_data;
	if (newpinyin_data == NULL)
		return (IME_UNUSED_KEY);

	ime_buffer->encoding = newpinyin_data->encoding;

	kcode = key_event->keycode;
	kchar = key_event->keychar;
	kstate = key_event->modifier;

	DEBUG_printf("Before Modify:keycode:0x%x, keychar:0x%x, keystatus:0x%x\n", kcode, kchar, kstate);
	modifyEvent(&kcode, &kchar, &kstate);
	DEBUG_printf("After Modify: keycode:0x%x, keychar:0x%x, keystatus:0x%x\n", kcode, kchar, kstate);
	ret = newpy_filter(kcode, kchar, kstate, ime_buffer);
	DEBUG_printf("After newpy_filter: ret=%d, return_status: 0x%x\n", ret, ime_buffer->return_status);

	if (ime_buffer->return_status & IME_PREEDIT_AREA) {
		newpinyin_update_preedit(ic, ime_buffer->encoding, ime_buffer->preedit_buf,
					 ime_buffer->preedit_len, ime_buffer->preedit_caretpos);
	}

	if (ime_buffer->return_status & IME_LOOKUP_AREA) {
		newpinyin_update_candidates(ic, ime_buffer->encoding, ime_buffer->lookups, ime_buffer->num_candidates);
	}
	
	if (ime_buffer->return_status & IME_COMMIT) {
		newpinyin_commit(ic, ime_buffer->encoding, ime_buffer->commit_buf, ime_buffer->commit_len);
	}

	if (ret == IME_UNUSED_KEY)
		return (IME_UNUSED_KEY);
	
	return (IME_OK);
}
