#include <stdio.h>
#include "ctim.h"
#include "zhuyin_data.h"

#define LOOKUP_CHOICE_NUM  	6

#define IME_Status		ime_buffer->return_status
#define Input_Buf		ime_buffer->input_buf
#define Input_Len		ime_buffer->input_len
#define Preedit_Buf		ime_buffer->preedit_buf
#define Preedit_Len		ime_buffer->preedit_len
#define Preedit_CaretPos	ime_buffer->preedit_caretpos
#define Commit_Buf		ime_buffer->commit_buf
#define Commit_Len		ime_buffer->commit_len
#define Status_Buf		ime_buffer->status_buf
#define Status_Len		ime_buffer->status_len
#define Lookups_Num		ime_buffer->num_candidates
#define Lookup_Pos		ime_buffer->cur_lookup_pos
#define Candidates		ime_buffer->candidates
#define Comments		ime_buffer->comments
#define Lookups			ime_buffer->lookups
#define Page_State		ime_buffer->page_state

int Is_UsedCodes_Key(TZhuyinData *pZhuyinData, int key)
{
	int nKeymap_ID = pZhuyinData->nCurrentKeymapID;
	return(ZhuyinKeymapList_Item_CheckIfValidKey(pZhuyinData->pZhuyinKeymapList, nKeymap_ID, key));
}

int Is_Zhuyin_Tone_Key(TZhuyinData *pZhuyinData, int key)
{
	int nKeymap_ID = pZhuyinData->nCurrentKeymapID;
	int nKeyType = ZhuyinKeymapList_Item_KeyToType(pZhuyinData->pZhuyinKeymapList, nKeymap_ID, key);
	return(nKeyType == ZHUYIN_TYPE_TONE ? 1 : 0);
}

int get_select_num(TZhuyinData *pZhuyinData, int key)
{
	CodeTableStruct *hztbl = pZhuyinData->pCodetableHeader;
	int ret = -1;
	switch(hztbl->nSelectKeyMode) {
		case NUMBER0_MODE:
			if (key >= '0' && key <= '9')
				ret = (key - '0') % 10;
			break;

		case NUMBER_MODE:
			if (key >= '1' && key <= '9')
				ret = (key - '0' + 9) % 10;
			break;

		case LOWER_MODE:
			if (key >= 'a' && key <= 'a' + 10)
				ret = key - 'a';
			break;

		case UPPER_MODE:
			if (key >= 'A' && key <= 'A' + 10)
				ret = key - 'A';
			break;
	}
	return(ret);
}

int Is_Select_Key(TZhuyinData *pZhuyinData, int key)
{
	CodeTableStruct *hztbl = pZhuyinData->pCodetableHeader;
	int ret = get_select_num(pZhuyinData, key);
	if (ret == -1)
		return(0);
	else
		return(1);
}

int Is_Space_Key(TZhuyinData *pZhuyinData, int key)
{
	if (key == IME_FILTERED_KEY_SPACEBAR)
		return(1);
	else
		return(0);
}

int Is_Return_Key(TZhuyinData *pZhuyinData, int key)
{
	if (key == IME_FILTERED_KEY_ENTER)
		return(1);
	else
		return(0);
}

int Is_BackSpace_Key(TZhuyinData *pZhuyinData, int key)
{
	CodeTableStruct *hztbl = pZhuyinData->pCodetableHeader;
	unsigned char *keylist = hztbl->functionkey[BACKSPACE_KEY_ID].keylist;
	int i;

	if (key == IME_FILTERED_KEY_BACKSPACE || key == IME_FILTERED_KEY_DELETE)
		return(1);

	if (keylist[0]) {
		for (i=0; i<MAX_FUNCTIONKEY_LEN; i++)
			if (keylist[i] == key)
				return(1);
	}

	return(0);
}

int Is_ClearAll_Key(TZhuyinData *pZhuyinData, int key)
{
	CodeTableStruct *hztbl = pZhuyinData->pCodetableHeader;
	unsigned char *keylist = hztbl->functionkey[CLEARALL_KEY_ID].keylist;
	int i;

	if (key == IME_FILTERED_KEY_ESCAPE)
		return(1);

	if (keylist[0]) {
		for (i=0; i<MAX_FUNCTIONKEY_LEN; i++)
			if (keylist[i] == key)
				return(1);
	}
	return(0);
}

int Is_NextPage_Key(TZhuyinData *pZhuyinData, int key)
{
	CodeTableStruct *hztbl = pZhuyinData->pCodetableHeader;
	unsigned char *keylist = hztbl->functionkey[PAGEDOWN_KEY_ID].keylist;
	int i;

	if (key == IME_FILTERED_KEY_PAGEDOWN)
		return(1);

	if (keylist[0]) {
		for (i=0; i<MAX_FUNCTIONKEY_LEN; i++)
			if (keylist[i] == key)
				return(1);
	}
	return(0);
}

int Is_PrevPage_Key(TZhuyinData *pZhuyinData, int key)
{
	CodeTableStruct *hztbl = pZhuyinData->pCodetableHeader;
	unsigned char *keylist = hztbl->functionkey[PAGEUP_KEY_ID].keylist;
	int i;

	if (key == IME_FILTERED_KEY_PAGEUP)
		return(1);
	
	if (keylist[0]) {
		for (i=0; i<MAX_FUNCTIONKEY_LEN; i++)
			if (keylist[i] == key)
				return(1);
	}
	return(0);
}

int If_Has_WildChar(char *input_str)
{
	char *p = input_str;

	while(*p) {
		if (*p == '?' || *p == '*')
			return(1);
		p++;
	}
	return(0);
}

int get_lookup_result(CodeTableStruct *hztbl, ImeBufferRec *ime_buffer, 
int nHelpInfoMode, int pos, int max_lookup_num)
{
	int i, lookup_num;

	lookup_num = codetable_search(hztbl, Input_Buf, Candidates, Comments, pos, max_lookup_num + 1); 
	if (lookup_num > 0) {
		Page_State = 0;
		if (pos == 0)
			Page_State |= ImeCandidatesFirstPage;
		if (lookup_num < max_lookup_num + 1)
			Page_State |= ImeCandidatesLastPage;
		if (lookup_num == max_lookup_num + 1)
			lookup_num = max_lookup_num;

		for (i=0; i<lookup_num; i++) {
			if (nHelpInfoMode)
				snprintf((char *)Lookups[i], MAX_CANDIDATE_CHAR_NUM, "%s %s",
					 Candidates[i], Comments[i]);
			else
				strcpy(Lookups[i], Candidates[i]);
		}
	}

	return(lookup_num);
}

int Commit_And_Clean_All_Area(ImeBufferRec *ime_buffer)
{
	Input_Len = 0;
	Preedit_Len = 0;
	Lookups_Num = 0;
	Preedit_CaretPos = 0;
	IME_Status = IME_COMMIT | IME_PREEDIT_AREA | IME_LOOKUP_AREA;
}

int Clean_All_Area(ImeBufferRec *ime_buffer)
{
	Input_Len = 0;
	Preedit_Len = 0;
	Lookups_Num = 0;
	Preedit_CaretPos = 0;
	IME_Status = IME_PREEDIT_AREA | IME_LOOKUP_AREA;
}

int commit_candidate(ImeBufferRec *ime_buffer, int id)
{
	if (id >= Lookups_Num)
		return(-1);

	strcpy((char *)Commit_Buf, (char *)Candidates[id]);
	Commit_Len = strlen((char *)Commit_Buf);
	Commit_And_Clean_All_Area(ime_buffer);

	return(0);
}

void warning_bell(ImeBufferRec *ime_buffer)
{
	IME_Status |= IME_BEEP;
}

int zhuyin_inputbuf_to_preeditbuf(TZhuyinData *pZhuyinData, ImeBufferRec *ime_buffer)
{
	int i, nKeyType;
	char tmp_buf[4];
	char *space_str = "  ";
	unsigned char *pSymbol, buffer[128];
	CodeTableStruct *hztbl = pZhuyinData->pCodetableHeader;

	memset(tmp_buf, 0, 4);
	for (i=0; i<Input_Len; i++) {
		if (i>=4) break;
		nKeyType = ZhuyinKeyToZhuyinType(Input_Buf[i]);
		if (nKeyType == ZHUYIN_TYPE_ERROR) continue;

		tmp_buf[nKeyType - 1] = Input_Buf[i];
	}

	Preedit_Len = 0;
	for (i=0; i<4; i++) {
		pSymbol = NULL;
		if (tmp_buf[i]) {
			pSymbol = (unsigned char *)ZhuyinKeyToZhuyinSymbol(tmp_buf[i]);
			if (pSymbol && hztbl->Encode != ENCODE_UTF8) {
				char *ip, *op;
				int ileft, oleft;
				ip = (char *)pSymbol;
				ileft = strlen(pSymbol);
				op = (char *)buffer;
				oleft = 128;
				memset(buffer, 0, 128);
				Convert_UTF8_To_Native(hztbl->Encode, ip, ileft, &op, &oleft);
				pSymbol = buffer;
			}
		}
		if(!pSymbol || !*pSymbol) pSymbol = (unsigned char *)space_str;

		strcpy(Preedit_Buf+Preedit_Len, pSymbol);
		Preedit_Len += strlen(pSymbol);
	}
	Preedit_Buf[Preedit_Len] = '\0';
	Preedit_CaretPos = Preedit_Len;
	return(0);
}

int zhuyin_add_key(TZhuyinData *pZhuyinData, ImeBufferRec *ime_buffer, int key)
{
	char StandardKey;
	int nKeyType, nSKeyType, i, j;
	int nKeymap_ID = pZhuyinData->nCurrentKeymapID;

	StandardKey = ZhuyinKeymapList_Item_KeyToStandardKey(pZhuyinData->pZhuyinKeymapList, nKeymap_ID, key);
	if (StandardKey == 0) 
		return(-1);

	nSKeyType = ZhuyinKeyToZhuyinType(StandardKey);
	if (nSKeyType == ZHUYIN_TYPE_ERROR)
		return(-1);

	/* if is Tone 0 */
	if (StandardKey == ' ') StandardKey = '\0';

	for (i=0; i<Input_Len; i++) {
		if (i >= 4) break;
		nKeyType = ZhuyinKeyToZhuyinType(Input_Buf[i]);
		if (nKeyType == ZHUYIN_TYPE_ERROR)
			return(-1);

		if (nSKeyType == nKeyType) {
			/* replace the key */
			Input_Buf[i] = StandardKey;
			return(0);
		} else if (nSKeyType < nKeyType) {
			/* insert the new key */
			for (j=Input_Len; j>i; j--) {
				Input_Buf[j] = Input_Buf[j-1];
			}
			Input_Buf[i] = StandardKey;
			Input_Len++;
			Input_Buf[Input_Len] = 0;
			return(0);
		}
	}

	Input_Buf[Input_Len++] = StandardKey;
	Input_Buf[Input_Len] = 0;
	return(0);
}

/* return value:  IME_UNUSED_KEY:  if IME not use this key, return this key to systerm directly */
/*                IME_OK:      if IME has used this key */
int zhuyin_filter(TZhuyinData *pZhuyinData, unsigned char key, ImeBufferRec *ime_buffer)
{
    	char    ch;
    	int     ret, i, k, hznum;
	int     pos, select_num;
	int	bHasWildChar, symbol_area_id;
	int 	Max_Lookups_Num = LOOKUP_CHOICE_NUM;
	int     Max_Symbols_Lookups_Num = 10;

	CodeTableStruct *hztbl = pZhuyinData->pCodetableHeader;

	int 	nHelpInfoMode = hztbl->nHelpInfoMode;
	int 	nAutoSelectMode = hztbl->nAutoSelectMode;

	ime_buffer->encoding = hztbl->Encode;

	IME_Status = 0;

/*
	ime_buffer->lookup_label_type = NUMERIC_LABEL;
*/

	bHasWildChar = If_Has_WildChar(Input_Buf);

    	if(Is_Select_Key(pZhuyinData, key) && (Lookups_Num > 0)) {
		select_num = get_select_num(pZhuyinData, key);
		if (select_num >= 0 && select_num < Lookups_Num) {
			commit_candidate(ime_buffer, select_num);
			return(IME_OK);
		}
    	}

    	if(Is_Space_Key(pZhuyinData, key)) {
		/* if no input keys */
		if (Input_Len==0) 
			return(IME_UNUSED_KEY);

		if (Lookups_Num==0) {
			/* Search from beginning */
			Lookup_Pos = 0;
			Lookups_Num = get_lookup_result(hztbl, ime_buffer, nHelpInfoMode, Lookup_Pos, Max_Lookups_Num);
			if (Lookups_Num == 1 && nAutoSelectMode) {
				commit_candidate(ime_buffer, 0);
			} else if (Lookups_Num == 0) {
				warning_bell(ime_buffer);
			}
			IME_Status |= IME_LOOKUP_AREA;
			return(IME_OK);
		}

		/* Space key as scroll key */
		/* if Have several candidates, need search the next page */
		pos = Lookup_Pos + Max_Lookups_Num;
		hznum = get_lookup_result(hztbl, ime_buffer, nHelpInfoMode, pos, Max_Lookups_Num); 
		if (hznum == 0) {
			/* if no candidates for the next page */
			if (Lookup_Pos = 0) {
				/* if is the first page, need not do anything */
				return(IME_OK);
			} else {
				/* if not the first page, need scroll to the first page */
				pos = 0;
				hznum = get_lookup_result(hztbl, ime_buffer, nHelpInfoMode, pos, Max_Lookups_Num); 
			}
		}

		Lookup_Pos = pos;
		Lookups_Num = hznum;
		IME_Status = IME_LOOKUP_AREA;

		return(IME_OK);
    	}

    	if(Is_UsedCodes_Key(pZhuyinData, key)) { 
		/* if inputted keys length has over the limit */
        	if (Lookups_Num > 0) {
			strcpy((char *)Commit_Buf, (char *)Candidates[0]);
			Commit_Len = strlen((char *)Commit_Buf);
			Commit_And_Clean_All_Area(ime_buffer);
        	}

		if (Input_Len == 0 && Is_Zhuyin_Tone_Key(pZhuyinData, key))
			return(IME_OK);

		ret = zhuyin_add_key(pZhuyinData, ime_buffer, key);
		if (ret == -1) return(IME_OK);

		zhuyin_inputbuf_to_preeditbuf(pZhuyinData, ime_buffer);
		IME_Status |= IME_PREEDIT_AREA;

		if (Is_Zhuyin_Tone_Key(pZhuyinData, key)) {
			/* Search from beginning */
			Lookup_Pos = 0;
			Lookups_Num = get_lookup_result(hztbl, ime_buffer, nHelpInfoMode, Lookup_Pos, Max_Lookups_Num);
			if (Lookups_Num == 1 && nAutoSelectMode) {
				commit_candidate(ime_buffer, 0);
			} else if (Lookups_Num == 0) {
				warning_bell(ime_buffer);
			}
			IME_Status |= IME_LOOKUP_AREA;
		}

		return(IME_OK);
	}

    	if(Is_ClearAll_Key(pZhuyinData, key)) { 
		/* Esc , clear preedit area, lookup choice area */

		/*  if no inputted key, directly return this key */
		if (Lookups_Num == 0 && Input_Len==0) return(IME_UNUSED_KEY);

		Clean_All_Area(ime_buffer);
		return (IME_OK);
    	}

    	if (Is_BackSpace_Key(pZhuyinData, key)) { /* Back Space & Delete */
		/*  if no inputted key, directly return this key */
		if (Input_Len==0) return(IME_UNUSED_KEY);

        	/* Delete characters in pre-edit region */
            	Input_Len --;
		Input_Buf[Input_Len] = 0;
		if (Input_Len > 0) {
			zhuyin_inputbuf_to_preeditbuf(pZhuyinData, ime_buffer);
		} else {
			Preedit_Len = 0;
		}
		IME_Status = IME_PREEDIT_AREA;

		Lookups_Num = 0;
		IME_Status |= IME_LOOKUP_AREA;
		return(IME_OK);

    	}

    	if(Is_NextPage_Key(pZhuyinData, key)) {
		/*  if no inputted key, directly return this key */
		if (Input_Len==0) return(IME_UNUSED_KEY);

		/* if any preedit key and not in Lookup status */
		if (Lookups_Num==0) return(IME_OK);

		pos = Lookup_Pos + Max_Lookups_Num;
		hznum = get_lookup_result(hztbl, ime_buffer, nHelpInfoMode, pos, Max_Lookups_Num); 
		if (hznum > 0) {
			Lookups_Num = hznum;
			Lookup_Pos = pos;
			IME_Status = IME_LOOKUP_AREA;
		} else {
               		warning_bell(ime_buffer);
		}

		return(IME_OK);
    	}

    	if(Is_PrevPage_Key(pZhuyinData, key)) {
		/*  if no inputted key, directly return this key */
		if (Input_Len==0) return(IME_UNUSED_KEY);

		/* if any preedit key and not in Lookup status */
		if (Lookups_Num==0) return(IME_OK);

		/* if in beginning pos */
		if (Lookup_Pos<=0) {
               		warning_bell(ime_buffer);
			return(IME_OK);
		}

		pos = Lookup_Pos - Max_Lookups_Num;
		hznum = get_lookup_result(hztbl, ime_buffer, nHelpInfoMode, pos, Max_Lookups_Num); 
		if (hznum > 0) {
			Lookups_Num = hznum;
			Lookup_Pos = pos;
			IME_Status = IME_LOOKUP_AREA;
		} else {
               		warning_bell(ime_buffer);
		}

		return(IME_OK);
    	}

    	if(Is_Return_Key(pZhuyinData, key)) { 
		/* Esc , clear preedit area, lookup choice area */

		/*  if no inputted key, directly return this key */
		if (Lookups_Num == 0 && Input_Len==0) return(IME_UNUSED_KEY);

		Clean_All_Area(ime_buffer);
		return (IME_OK);
    	}


	/* for unnormal keys */
	if (Lookups_Num > 0) {
		/* need commit the first candidate */
		strcpy((char *)Commit_Buf, (char *)Candidates[0]);
		Commit_Len = strlen((char *)Commit_Buf);
		Commit_And_Clean_All_Area(ime_buffer);
	}

        return(IME_UNUSED_KEY);
}
