#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SunIM.h"
#include "phonetic_im.h"
#include "phonetic_filter.h"
#include "unit_input.h"
#include "logf.h"

int Is_UsedCodes_Key(indic_table, key)
TableStruct *indic_table;
int key;
{
 if ( index(indic_table->UsedCodes, key) )
  return(1);
 else
  return(0);
}

int Is_Commit_Key(indic_table, key)
TableStruct *indic_table;
int key;
{
  if (key == RETURN_KEY || key == SPACE_KEY || key == TAB_KEY)
    return(1);
  else
   return(0);
}

int Is_BackSpace_Key(indic_table, key)
TableStruct *indic_table;
int key;
{
 if (key == BACKSPACE_KEY || key == DELETE_KEY)
  return(1);
 else
  return(0);
}

int Is_ClearAll_Key(indic_table, key)
TableStruct *indic_table;
int key;
{
 if (key == ESC_KEY)
   return(1);
 else
   return(0);
}

int commit_candidate(ime_buffer)
IMEBufferRec *ime_buffer;
{
  (void)strcpy((char *)Commit_Buf, (char *)Preedit_Buf);
  Commit_Len = strlen((char *)Commit_Buf);
  log_f("Inside commit_candidate, Commit_Buf <%s>\n",Commit_Buf);
  IME_Status = IME_COMMIT;
  return(0);
}

void warning_bell()
{
}

int process_output_buffer(indic_table, ime_buffer, key, Output_Buf, commit_flag)
TableStruct *indic_table;
IMEBufferRec *ime_buffer;
int key;
unsigned char *Output_Buf;
int commit_flag;
{
    log_f("process_output_buffer:Output_Buf:%s, commit_flag:%d\n",Output_Buf, commit_flag);
    log_f("process_output_buffer:key:%d\n",key);
    if (!commit_flag){
      (void)strcpy(prev_Preedit_Buf, Output_Buf);
      log_f("commit_flag:%d, prev_Preedit_Buf:%s\n",commit_flag,prev_Preedit_Buf);
      (void)strcpy(Preedit_Buf, prev_Preedit_Buf);
      Preedit_Len = strlen(Preedit_Buf);
      log_f("Preedit_Len:%d\n",Preedit_Len);
      Preedit_CaretPos = Preedit_Len;
      log_f("*** Preedit_CaretPos:%d\n",Preedit_CaretPos);
      IME_Status = IME_PREEDIT_AREA;
      free(Output_Buf);
    }else{
      word_start_flag = 0;
      log_f("commit_flag:%d, prev_Preedit_Buf:%s\n",commit_flag,prev_Preedit_Buf);
      (void)strcpy(Preedit_Buf, prev_Preedit_Buf);
      Preedit_Len = strlen(Preedit_Buf);
      Preedit_CaretPos = Preedit_Len;
      log_f("Preedit_Buf:%s, Preedit_Len:%d, Preedit_CaretPos:%d\n",Preedit_Buf, Preedit_Len, Preedit_CaretPos);
      commit_candidate(ime_buffer);

      /* After committing, copy the Output_Buf into Preedit_Buf */
      (void)strcpy(Preedit_Buf, Output_Buf);
      (void)strcpy(prev_Preedit_Buf, Output_Buf);
      Preedit_Len = strlen(Preedit_Buf);
      Preedit_CaretPos = Preedit_Len;
      log_f("After commit: Preedit_Buf:%s, Preedit_Len:%d\n",Preedit_Buf, Preedit_Len);
      /* After committing, copy the latest key into Input_Buf */
      Input_Len = 0;
      Input_Buf[Input_Len] = key;
      Input_Len ++;
      Input_Buf[Input_Len] = '\0';
      log_f("Input_Buf:%s, Input_Len:%d\n",Input_Buf, Input_Len);
      IME_Status |= IME_PREEDIT_AREA;
      free(Output_Buf);
    }
    return (1);
}

/* return value:  IME_NOT_USED_KEY:  if IME not use this key, return */ 
/*                                   this key to systerm directly    */
/*                IME_USED_KEY:      if IME has used this key        */

int phonetic_filter(indic_table, key_event, ime_buffer)
TableStruct *indic_table;
IMEKey key_event;
IMEBufferRec *ime_buffer;
{
  int     key;
  int commit_flag;
  char    ch;
  unsigned char *Output_Buf;
 
  ime_buffer->encode = indic_table->Encode;

  IME_Status = 0;
  commit_flag = 0;

  key = map_keyevent_to_imekey(indic_table, key_event);
  log_f("phonetic_filter: map_keyevent_to_imekey: return key:0x%x\n", key);
 
  if (key == IME_NOT_USED_KEY){
    log_f("IME_NOT_USED_KEY \n");
    return(IME_NOT_USED_KEY);
  }

  if ((key == SPACE_KEY) && (Preedit_Len == 0)){
    log_f("Starting of the Word \n");
    word_start_flag = 1;
    word_end_flag = 1;
    key = key_event->keyChar;

    log_f("prev_Preedit_Buf:%s\n",prev_Preedit_Buf);
    (void)strcpy(Preedit_Buf, prev_Preedit_Buf);
    Preedit_Len = strlen(Preedit_Buf);
    Preedit_Buf[Preedit_Len] = key;
    Preedit_Len++;
    Preedit_Buf[Preedit_Len] = '\0';
    log_f("Preedit_Buf:%s\n",Preedit_Buf);
    Preedit_Len = strlen(Preedit_Buf);
    Preedit_CaretPos = Preedit_Len;
    commit_candidate(ime_buffer);
   
    Preedit_Len = 0;
    Preedit_Buf[Preedit_Len] = '\0';
    (void)memset((char *)prev_Preedit_Buf, '\0', sizeof(prev_Preedit_Buf));
    IME_Status |= IME_PREEDIT_AREA;

    /* After committing, copy the latest key into Input_Buf */
    Input_Len = 0;
    Input_Buf[Input_Len] = '\0';
    log_f("Input_Buf:%s, Input_Len:%d\n",Input_Buf, Input_Len);
    return(IME_USED_KEY);
  }
 
  if (Is_UsedCodes_Key(indic_table, key)){
    /* if not key by key, and is selectkey, and Lookup Mode */
    /* directly select */
  
    Input_Buf[Input_Len] = key;
    Input_Len ++;
    Input_Buf[Input_Len] = '\0';
  
    log_f("Input_Buf:%s, Input_Len:%d, word_start_flag:%d\n",Input_Buf, Input_Len, word_start_flag);

    log_f("phonetic_Filter: fNum:%d\n",fNum);
    log_f("phonetic_Filter: word_end_flag:%d\n",word_end_flag);
    /* Array of Function Pointers */
    fArray[fNum](Input_Buf, &Output_Buf, &commit_flag, word_start_flag, word_end_flag);

    log_f("Output_Buf:%s, commit_flag:%d\n",Output_Buf, commit_flag);

    process_output_buffer(indic_table, ime_buffer, key, Output_Buf, commit_flag);
  }

  if (Is_ClearAll_Key(indic_table, key)) { 
    /* Esc , clear preedit and so on */
    log_f("ESC_KEY\n");
    /*  if no inputted key, directly return this key */
    if (Input_Len==0) return(IME_NOT_USED_KEY);
  
    Input_Len = 0;
    Preedit_Len = 0;
    Preedit_CaretPos = 0;
    IME_Status = IME_PREEDIT_AREA ;
    free(Output_Buf);
    return (IME_USED_KEY);
  }

  if (Is_BackSpace_Key(indic_table, key)) { /* Back Space & Delete */
    log_f("BACKSPACE_KEY, Input_Len:%d, Preedit_Len:%d\n", Input_Len, Preedit_Len);
    /*  if no inputted key, directly return this key */
    if (Input_Len==0) return(IME_NOT_USED_KEY);

    Input_Len --;
    ch = Input_Buf[Input_Len];
    log_f("ch:%c, Preedit_Buf:%s\n", ch, Preedit_Buf);
    Input_Buf[Input_Len] = '\0';

    log_f("phonetic_Filter: word_end_flag:%d\n",word_end_flag);
    fArray[fNum](Input_Buf, &Output_Buf, &commit_flag, word_start_flag, word_end_flag);
    process_output_buffer(indic_table, ime_buffer, key, Output_Buf, commit_flag);
    return(IME_USED_KEY);
  }

  if (Is_Commit_Key(indic_table, key)) { /* space or return key */
    log_f("SPACE/RETURN/TAB KEY: Input_Buf:[%s]\n",Input_Buf);
    if (Input_Len==0){
      word_start_flag = 1;
      return(IME_NOT_USED_KEY);
    }

    /* if any keys and key is Space key and mode is not keybykey */
    /* then search and display the candidates */

    if((key == RETURN_KEY || key == SPACE_KEY || key == TAB_KEY) && (Preedit_Len > 0)){
      log_f("RETURN/SPACE key: Input_Buf:%s\n",Input_Buf);
      log_f("RETURN/SPACE key: Preedit_Buf:%s\n",Preedit_Buf);
      word_end_flag = 1;
      log_f("SPACE_KEY: word_start_flag:%d\n",word_start_flag);
      log_f("SPACE_KEY: word_end_flag:%d\n",word_end_flag);
      fArray[fNum](Input_Buf, &Output_Buf, &commit_flag, word_start_flag, word_end_flag);
      log_f("SPACE_KEY: commit_flag:%d\n",commit_flag);
      process_output_buffer(indic_table, ime_buffer, key, Output_Buf, commit_flag);
      word_start_flag = 1;
    }
    if((key == RETURN_KEY) && (Preedit_Len > 0)){
      strcat((char *)Preedit_Buf,(char *)"\n");
      log_f("Preedit_Buf:%s\n",Preedit_Buf);
      Preedit_Len = strlen(Preedit_Buf);
    }else if((key == SPACE_KEY) && (Preedit_Len > 0)){
      strcat((char *)Preedit_Buf,(char *)" ");
      log_f("Preedit_Buf:%s\n",Preedit_Buf);
      Preedit_Len = strlen(Preedit_Buf);
    }else if((key == TAB_KEY) && (Preedit_Len > 0)){
      strcat((char *)Preedit_Buf,(char *)"\t");
      log_f("Preedit_Buf:%s\n",Preedit_Buf);
      Preedit_Len = strlen(Preedit_Buf);
    }
    word_end_flag = 0;
    commit_candidate(ime_buffer);

    /* clear Preedit_Buf , prev_Preedit_Buf and Input_Buf */ 
    Preedit_Len = 0;
    Preedit_CaretPos = 0;
    (void)memset((char *)prev_Preedit_Buf, '\0', sizeof(prev_Preedit_Buf));
    Input_Len = 0;
    Input_Buf[Input_Len]='\0';
    IME_Status |= IME_PREEDIT_AREA; 
    return(IME_USED_KEY);
  }

  /* for unnormal keys */
  if (Input_Len==0) return(IME_NOT_USED_KEY);
  else return(IME_USED_KEY);
}

/*********************** Key Mapping ***********************/

/*  get the keys that IME will use */
int map_keyevent_to_imekey(TableStruct *indic_table, IMEKey key_event)
{
	int keycode, keystatus, keychar;

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

	log_f("phonetic_filter: keycode: 0x%x, keychar:0x%x, keystatus: 0x%x\n", keycode, keychar, keystatus);
	/* normal status */
	if (keystatus  == 0) {
		/* Function Keys */
		if (keychar == 0) {
			log_f(" Function Key :%d\n", keycode);
			switch (keycode) {
				case IM_VK_ESCAPE:
					return(ESC_KEY);

				case IM_VK_BACK_SPACE:
					return(BACKSPACE_KEY);

				case IM_VK_ENTER:
					return(RETURN_KEY);

				case IM_VK_TAB:
					return(TAB_KEY);

				case IM_VK_INSERT:
					return(INSERT_KEY);

				case IM_VK_DELETE:
					return(DELETE_KEY);

				case IM_VK_HOME:
					return(HOME_KEY);

				case IM_VK_END:
					return(END_KEY);

				case IM_VK_PAGE_UP:
					return(PAGEUP_KEY);

				case IM_VK_PAGE_DOWN:
					return(PAGEDOWN_KEY);

			}
			return(IME_NOT_USED_KEY);
		} else {
			/*  normal key  */
			log_f("phonetic_filter:  Normal Key :0x%x, %c\n", keychar, keychar);
			return(keychar);
		}
	}

	/*  Shift status */
	if (keystatus == IM_SHIFT_MASK) {
		if (keychar != 0) {
			/*  normal key  */
			log_f("phonetic_filter:  Ascii Key :0x%x, %c\n", keychar, keychar);
			return(keychar);
		}
	}
	return (IME_NOT_USED_KEY);
}
