/*
 * Copyright 2003 Sun Microsystems Inc.
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * Authors: Karl Park <karl.park@sun.com>
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <assert.h>
#include "koinput.h"
#include "key_event.h"
#include "le.h"
#include "le_proc.h"
#include "iml.h"
#include "method.h"
#include "encode.h"
#include "xaux_locale.h"
#include "fullwidth.h"
#include "util.h"
#include "kolelog.h"

#if 0
void proc_symbole_input_event(iml_session_t *s, IMKeyEventStruct *key_event);
#endif

static void keyevent_toggle_junjabanja_handler(iml_session_t *s, int junjabanja);
static void keyevent_input_handler(iml_session_t *s, IMKeyEventStruct *key_event);
#if 0
static void proc_key_switch_keyboard_layout_event(iml_session_t *s, int nKeyboardID);
#endif

extern int          g_number_of_engines;
extern int			  default_engine_id;
extern IMEEngineRec *g_engines[MAX_ENGINE_NUM];
static Bool imekeycmp (IMEKeyEventStruct *key_a, IMEKeyEventStruct *key_b);
static Bool is_hotkey (iml_session_t *s, IMEKeyEventStruct *key_event);

void
keyevent_handler (iml_session_t *s, IMKeyListEvent *keylistevent)
{
  MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
  MyDataPerDesktop *desktop_data =
    (MyDataPerDesktop *)(s->desktop->specific_data);
  IMKeyEventStruct *key_event =
    (IMKeyEventStruct *) keylistevent->keylist;
  IMEBufferMethods mthds = session_data->session_core.ime_methods_table;
  IMEBuffer a_buffer = session_data->session_core.ime_buffer;
  
  int key_ret, ime_id, junjabanja, punct;
  int kid;
  
  INPUT_MODE_T imode_return;
  Bool mthd_return;

  KOLE_LOG (LOGDEST_STDOUT, " proc_keyevent:   session:%x\n", s);

  keyevent_input_handler (s, key_event);
  
  mthd_return = (*mthds->ime_buffer_get_input_mode) (a_buffer,  &imode_return);
  if (!mthd_return){
    KOLE_LOG (LOGDEST_STDERR,
	      "keyevent_handler: error in getting current input mode\n");
    return;
  }
  return;
}

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

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

  KOLE_LOG (LOGDEST_STDOUT,
	    "keycode: %d, keychar: %d, status: %d", keycode, keychar, keystatus);

  /*  Shift status */
  if (keystatus == IM_SHIFT_MASK) {
    switch(keycode){
    case IM_VK_SPACE:	return(FULL_HALF_WIDTH_SWITCH_KEY);
    case IM_VK_F2:
      return(KEYBOARD_LAYOUT_TOGGLE_KEY);
    }
  }
  /*  Control status */
  if (keystatus & IM_CTRL_MASK) {
    switch(keycode) {
    case IM_VK_SPACE:	return(ENGLISH_KOREAN_SWITCH_KEY);
    case IM_VK_X:
      if(keystatus & IM_SHIFT_MASK){
	return(HEX_INPUT_IN_UTF8_MODE_KEY);
      } else {
	return(HEX_INPUT_IN_EUC_MODE_KEY);
      }
    case IM_VK_J:		return(SYMBOL_INPUT_MODE_KEY);
    case IM_VK_Q:		return(HANJA_CONVERSION_HANJA_KEY);
      /*
	case IM_VK_W:		return(HANJA_CONVERSION_DEFAULT_KEY);
      */
    case IM_VK_H:		return(HANJA_CONVERSION_DEFAULT_KEY);
    case IM_VK_E:		return(HANJA_CONVERSION_HANGUL_HANJA_KEY);
    case IM_VK_R:		return(HANJA_CONVERSION_HANJA_HANGUL_KEY);
    }
  }

  return (IMM_NOT_USED_KEY);
}
#endif

void
keyevent_switch_conversion_handler (iml_session_t *s, int on)
{
  MyDataPerSession *sd = (MyDataPerSession *) s->specific_data;
  MyDataPerDesktop *dd = (MyDataPerDesktop *)(s->desktop->specific_data);
  int engine_id, i;
  char locale_id, system_locale_id;
  IMEBufferMethods ime_methods =  sd->session_core.ime_methods_table;
  INPUT_MODE_T imt;
  Bool mthd_return;
  
  KOLE_LOG (LOGDEST_STDOUT,
	    "ENGLISH_KOREAN SWITCH IME KEY, on:%d", on);

  sd->paletteaux_status.on = on;
  engine_id = sd->paletteaux_status.engine_id;
  ime_methods = g_engines[engine_id]->so_methods;

  if (on == CONVERSION_OFF) {
    
    (*ime_methods->ime_buffer_conversion_end)(sd->session_core.ime_buffer);

    iml_conversion_off (s);
    iml_status_draw (s);
    
    mthd_return =
      (*ime_methods->ime_buffer_get_input_mode)(sd->session_core.ime_buffer, &imt);
    if (mthd_return)
      le_update_paletteaux_input_mode_info (s, imt);

  } else {

    (*ime_methods->ime_buffer_conversion_start)(sd->session_core.ime_buffer);
    
    iml_conversion_on(s);
    iml_status_draw (s);

    mthd_return =
      (*ime_methods->ime_buffer_get_input_mode)(sd->session_core.ime_buffer, &imt);
    if (mthd_return)
      le_update_paletteaux_input_mode_info (s, imt);
    /*
      iml_status_draw (s);
      if (engine_id != 0xff)
      le_switch_engine(s, engine_id);
    */
  }
#if 0
  /* test code */
  iml_inst *lp;
  iml_inst *rrv = NULL;
  lp = s->If->m->iml_make_lookup_done_inst(s);
  s->If->m->iml_link_inst_tail (&rrv, lp);
  s->If->m->iml_execute (s, &rrv);

  le_change_focus_notify(s);

  /* If PaletteAux can be started */
  if (dd->paletteaux_ready == True) {
    return;
  }

  /* PaletteAux can not be started */
  if (on == CONVERSION_ON && engine_id == 0xff) {
    system_locale_id = dd->aux_locale_id;
    engine_id = 0;
    for (i = 0; i< g_number_of_engines; i++) {
      locale_id = g_engines[i]->core.baseinfo.locale_id;
      if (locale_id == system_locale_id || locale_id == ENCODES_NUM) {
	engine_id = i;
	break;
      }
    }
    KOLE_LOG (LOGDEST_STDOUT, "engine_id:%d", engine_id);
    le_switch_engine(s, engine_id);
  }
#endif
}


void
proc_key_switch_keyboard_layout_event (iml_session_t *s, int nKeyboardID)
{
  MyDataPerSession *session_data = (MyDataPerSession *)s->specific_data;
  if(nKeyboardID == -1){ /* no change, this would be for hiding the keyboad aux */
    iml_status_draw (s);
    return;
  }

  if(nKeyboardID < -1 || nKeyboardID > 3)
    nKeyboardID = 0;

  iml_status_draw (s);
}

void
proc_symbol_input_event (iml_session_t *s, IMKeyEventStruct *key_event)
{
	iml_status_draw (s);
	keyevent_input_handler (s, key_event);
	iml_status_draw (s);
}

void
keyevent_toggle_junjabanja_handler (iml_session_t *s, int junjabanja)
{
  MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
  IMEBufferMethods methods_table = session_data->session_core.ime_methods_table;
  IMEBuffer session_ime_buffer = session_data->session_core.ime_buffer;

  KOLG_LOG (LOGDEST_STDOUT, "FULL_HALF_WIDTH_SWITCH_KEY: %d\n", junjabanja);

  session_data->paletteaux_status.junjabanja = junjabanja;
  (*methods_table->ime_buffer_initialize)(session_ime_buffer);
  le_switch_junjabanja_notify (s, junjabanja);
}

int
proc_junja (iml_session_t *s, IMKeyEventStruct *key_event)
{
  MyDataPerDesktop *desktop_data =
    (MyDataPerDesktop *)(s->desktop->specific_data);
  int lang_id, locale_id;
  char *commit_buf;
  int keycode, keystatus, keychar;

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

  /* normal ASCII key */
  if ((keychar != 0) && (keystatus == IM_SHIFT_MASK || keystatus == 0)) {
    locale_id = desktop_data->aux_locale_id;
    lang_id = get_langid_from_localeid(locale_id);
    commit_buf = (char *)get_junja_str(keychar);
    if (commit_buf != NULL) {
#if 0
      encode_commit(s, ENCODE_EUC_KO, (unsigned char *)commit_buf);
#endif
      return (IMM_USED_KEY);
    }
  }

  return (IMM_NOT_USED_KEY);
}

void
keyevent_input_handler (iml_session_t *s, IMKeyEventStruct *key_event)
{

  MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
  MyDataPerDesktop *desktop_data = (MyDataPerDesktop *)(s->desktop->specific_data);
  IMEBufferMethods ime_methods =  session_data->session_core.ime_methods_table;
  IMEBuffer pbuffer = session_data->session_core.ime_buffer;
  IMEKeyEventStruct  ime_keyevent;
  IMEArgList ime_args;
  int engine_id, i;
  int ret, cur_engine_id, junjabanja, punct;
  Bool method_return;
  

  punct = session_data->paletteaux_status.punct;
  KOLE_LOG (LOGDEST_STDOUT, "punct:%d", punct);
	
  junjabanja = session_data->paletteaux_status.junjabanja;

  KOLE_LOG (LOGDEST_STDOUT, "junjabanja:%d", junjabanja);

  if (junjabanja == True) {
    ret = proc_junja(s, key_event);
    if (ret == IMM_USED_KEY) 
      return;
  }
	
  cur_engine_id = session_data->paletteaux_status.engine_id;
  KOLE_LOG (LOGDEST_STDOUT, "cur_engine_id:%d", cur_engine_id);
  if (cur_engine_id == 0xff) {
    iml_sendback_key(s, key_event);
    return;
  }

  ime_keyevent.key_code = key_event->keyCode;
  ime_keyevent.key_char = key_event->keyChar;
  ime_keyevent.key_modifier = key_event->modifier;

  method_return =
    (*ime_methods->ime_buffer_process_key_input) (pbuffer, &ime_keyevent);

  if (!method_return)
    iml_sendback_key (s, key_event);
  else
    {
      if (is_hotkey (s, &ime_keyevent)){
	auxhandler_send_session_property (s, XAUX_PALETTE_CLASS_NAME);
      }
      le_output_ime_buffer(s, session_data->session_core.ime_buffer, &ime_keyevent);
    }
}

static Bool
is_hotkey (iml_session_t *s, IMEKeyEventStruct *key_event)
{
  int n;
  IMEHotKey photkey;
  IMEHotKey tmp;
  IMEEngine p_engine;
  IMECore p_core;
  MyDataPerSession *sd = (MyDataPerSession *) s->specific_data;
  p_engine = sd->p_engine;
  p_core = &p_engine->core;
  photkey = &p_core->hotkeys;

  assert (photkey != NULL);
  
  if (photkey->n_count){
    for (n = 0 ;n < photkey->n_count; n++){
      if (!imekeycmp (key_event, photkey->keylist[n]))
	return True;
    }
    return False;
  }
  return False;
}

static Bool
imekeycmp (IMEKeyEventStruct *key_a, IMEKeyEventStruct *key_b)
{
  assert (key_a != NULL);
  assert (key_b != NULL);

  if ( (key_a->key_code == key_b->key_code) &&
       (key_a->key_char == key_b->key_char) &&
       (key_a->key_modifier == key_b->key_modifier))
    return 0;
  else
    return -1;
}
