#include <stdio.h>
#include "ctim.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(CodeTableStruct *hztbl, int key)
{
	if (index(hztbl->UsedCodes, key))
		return(1);
	else
		return(0);
}

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

		case NUMBER_MODE:
			if (key >= '0' && 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(CodeTableStruct *hztbl, int key)
{
	int ret = get_select_num(hztbl, key);
	if (ret == -1)
		return(0);
	else
		return(1);
}

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

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

	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(CodeTableStruct *hztbl, int key)
{
	int i;
	unsigned char *keylist = hztbl->functionkey[CLEARALL_KEY_ID].keylist;

	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(CodeTableStruct *hztbl, int key)
{
	int i;
	unsigned char *keylist = hztbl->functionkey[PAGEDOWN_KEY_ID].keylist;

	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(CodeTableStruct *hztbl, int key)
{
	int i;
	unsigned char *keylist = hztbl->functionkey[PAGEUP_KEY_ID].keylist;

	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 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++) {
			DEBUG_printf("%d: %s %s\n", i, Candidates[i], Comments[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;
}

/* 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 ctim_filter(CodeTableStruct *hztbl, unsigned char key, ImeBufferRec *ime_buffer)
{
    	char    ch;
    	int     i, k, hznum;
	int     pos, select_num;

	int 	Max_Lookups_Num = LOOKUP_CHOICE_NUM;
	int 	nKeyByKeyMode = hztbl->nKeyByKeyMode;
	int 	nHelpInfoMode = hztbl->nHelpInfoMode;
	int 	nAutoSelectMode = hztbl->nAutoSelectMode;
	int 	nKeyPromptMode = hztbl->nKeyPromptMode;

	ime_buffer->encoding = hztbl->Encode;

	IME_Status = 0;

/*
	switch(hztbl->nSelectKeyMode) {
		case NUMBER0_MODE:
			ime_buffer->lookup_label_type = NUMERIC0_LABEL;
			break;
		case NUMBER_MODE:
			ime_buffer->lookup_label_type = NUMERIC_LABEL;
			break;
		case LOWER_MODE:
			ime_buffer->lookup_label_type = LOWER_LABEL;
			break;
		case UPPER_MODE:
			ime_buffer->lookup_label_type = UPPER_LABEL;
			break;
		default:
			ime_buffer->lookup_label_type = NUMERIC_LABEL;
	}
*/
    	if(Is_Select_Key(hztbl, key)) {
        	if (Lookups_Num > 0) {
			select_num = get_select_num(hztbl, key);
			if (select_num >= 0 && select_num < Lookups_Num) {
				commit_candidate(ime_buffer, select_num);
			} else {
				warning_bell(ime_buffer);
			}
			return(IME_OK);
		}
    	}

    	if((Is_UsedCodes_Key(hztbl, key)) || (Is_Wildchar_Key(hztbl, key))) { 
		/* if inputted keys length has over the limit */
		if (Input_Len >= hztbl->MaxCodes) {
			return(IME_OK);
		}

        	if (Lookups_Num > 0 && !nKeyByKeyMode) {
			strcpy((char *)Commit_Buf, (char *)Candidates[0]);
                        Commit_Len = strlen((char *)Commit_Buf);
                        Commit_And_Clean_All_Area(ime_buffer);
        	}

            	Input_Buf[Input_Len] = key;
            	Input_Len ++;
            	Input_Buf[Input_Len] = '\0';
		
		if (nKeyPromptMode) {
			strcpy(Preedit_Buf+Preedit_Len, hztbl->keyprompt[key].prompt);
			Preedit_Len += strlen(hztbl->keyprompt[key].prompt);
            		Preedit_Buf[Preedit_Len] = '\0';
		} else {
			Preedit_Buf[Preedit_Len] = key;
			Preedit_Len += 1;
            		Preedit_Buf[Preedit_Len] = '\0';
		}
		Preedit_CaretPos = Preedit_Len;
		IME_Status |= IME_PREEDIT_AREA;

		Lookups_Num = 0;
		if (nKeyByKeyMode /* || Input_Len == hztbl->MaxCodes */) {
			Lookup_Pos = 0;
		 	Lookups_Num = get_lookup_result(hztbl, ime_buffer, nHelpInfoMode, Lookup_Pos, Max_Lookups_Num); 
			/* if Input_Len is MaxCodes, no matter the KeyByKey mode, need do checking */
			if (Input_Len == hztbl->MaxCodes) {
				if (Lookups_Num == 1 && nAutoSelectMode) {
					commit_candidate(ime_buffer, 0);
					return(IME_OK);
				}
			}
		}
		IME_Status |= IME_LOOKUP_AREA;

		return(IME_OK);
	}

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

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

		Clean_All_Area(ime_buffer);

		return (IME_OK);
    	}

    	if (Is_BackSpace_Key(hztbl, 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 --;
		if (nKeyPromptMode) {
			ch = Input_Buf[Input_Len];
            		Preedit_Len -= strlen(hztbl->keyprompt[ch].prompt);
            		Preedit_Buf[Preedit_Len] = '\0';
		} else {
			Preedit_Len -= 1;
            		Preedit_Buf[Preedit_Len] = '\0';
		}

            	Input_Buf[Input_Len] = '\0';
		Preedit_CaretPos = Preedit_Len;
		IME_Status = IME_PREEDIT_AREA;

		Lookups_Num = 0;
		if ((Input_Len > 0) && nKeyByKeyMode) {
			Lookup_Pos = 0;
		 	Lookups_Num = get_lookup_result(hztbl, ime_buffer, nHelpInfoMode, Lookup_Pos, Max_Lookups_Num); 
		}
		IME_Status |= IME_LOOKUP_AREA;

		return(IME_OK);
    	}

    	if(Is_NextPage_Key(hztbl, 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(hztbl, 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_Space_Key(hztbl, 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);
    	}

	/* 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);
}
