#include <stdio.h>

#include "le_info.h"
#include "le_session.h"
#include "le_aux_protocol.h"

#include "ime.h"

void le_show_selectaux_notify(iml_session_t * s);
void le_update_aux_imeinfo_notify(iml_session_t * s, char *classname);
void le_show_propertiesaux_notify(iml_session_t * s);

LeResult le_proc_paletteaux_update_property_event(iml_session_t * s,
                                                  IMAuxDrawCallbackStruct * aux_data);

LeResult le_proc_paletteaux_connect_event(iml_session_t * s,
                                          IMAuxDrawCallbackStruct *
                                          aux_data);
LeResult le_proc_paletteaux_switch_engine_event(iml_session_t * s,
                                                IMAuxDrawCallbackStruct *
                                                aux_data);
LeResult le_proc_paletteaux_switch_qjbj_event(iml_session_t * s,
                                              IMAuxDrawCallbackStruct *
                                              aux_data);
LeResult le_proc_paletteaux_switch_punct_event(iml_session_t * s,
                                               IMAuxDrawCallbackStruct *
                                               aux_data);
LeResult le_proc_commonaux_commit_string_event(iml_session_t * s,
                                               IMAuxDrawCallbackStruct *
                                               aux_data);
LeResult le_proc_commonaux_commit_key_event(iml_session_t * s,
                                            IMAuxDrawCallbackStruct *
                                            aux_data);

LeResult le_proc_pc_style_change                   (iml_session_t            *s,
                                                    IMAuxDrawCallbackStruct  *aux_data);

LeResult le_proc_pc_candidate_selection            (iml_session_t            *s,
                                                    IMAuxDrawCallbackStruct  *aux_data);

LeResult le_proc_pc_candidate_page                 (iml_session_t            *s,
                                                    IMAuxDrawCallbackStruct  *aux_data);

LeResult le_proc_pc_move                           (iml_session_t            *s,
                                                    IMAuxDrawCallbackStruct  *aux_data);


LeResult le_update_pc_position                     (iml_session_t *s,
                                                    char          *classname,
                                                    int            cursor_x,
                                                    int            cursor_y,
                                                    int            cursor_w,
                                                    int            cursor_h);

//UTF-16 -->encodingid
static IMAuxDrawCallbackStruct* convertAuxEventEncoding(IMAuxDrawCallbackStruct * auxdata, int encoding_id)
{
    int i, sz, srclen, dstlen;
    char * dstbuf;
    IMAuxDrawCallbackStruct *ad = (IMAuxDrawCallbackStruct*)calloc(1, sizeof(IMAuxDrawCallbackStruct));

    *ad = *auxdata;
    ad->string_values = NULL;
    if (ad->count_string_values) {
        ad->string_values = (IMText *)calloc(ad->count_string_values, sizeof(IMText));
        memset(ad->string_values, 0, sizeof(IMText)*ad->count_string_values);
        for (i=0; i < ad->count_string_values; ++i) {
            ad->string_values[i] = auxdata->string_values[i];
            ad->string_values[i].encoding = encoding_id;
            srclen = sizeof(UTFCHAR)*ad->string_values[i].char_length;
            dstlen = sz = ad->string_values[i].char_length*6;
            dstbuf = ad->string_values[i].text.native_chars = (char*)calloc(sz, sizeof(char));

            Convert_UTF16_To_Native(encoding_id,
                                    auxdata->string_values[i].text.utf_chars, srclen,
                                    &dstbuf, &dstlen);
        }
    }
    return ad;
}

static void freeConvertedEvent(IMAuxDrawCallbackStruct* auxdata)
{
    int i;
    if (auxdata) {
        if (auxdata->string_values) {
            for (i=0; i < auxdata->count_string_values; ++i) {
                if (auxdata->string_values[i].text.native_chars)
                    free(auxdata->string_values[i].text.native_chars);
            }
            free(auxdata->string_values);
        }
        free(auxdata);
    }
    return;
}

/* ============================================================== */
/*            Process information from Auxiliary Window           */
/* ============================================================== */
LeResult le_session_proc_aux_event(iml_session_t * s,
                                   IMAuxEvent * auxevent)
{

    LeDesktopContextRec *le_desktop_context = NULL;

    IMAuxDrawCallbackStruct *aux_data = auxevent->aux;
    int nIntegerCount, *pIntegerList;
    int reqType;
    int ret = LE_OK;

    le_desktop_context = (LeDesktopContextRec *) le_session_get_desktop_context(s);
#if 0
    /* NEED CHECK WHETHER HAVE OTHER PROBLEM */
    s = (iml_session_t *) le_desktop_context_get_current_session(le_desktop_context);

    DEBUG_printf("le_session_proc_aux_event: desktop: %p, current_session:%p\n",
                  le_desktop_context, s);

    if (s == NULL || aux_data == NULL)
        return (LE_FAIL);
#endif

    nIntegerCount = aux_data->count_integer_values;
    pIntegerList = aux_data->integer_values;

    if (nIntegerCount <= 0)
        return (LE_FAIL);

    reqType = pIntegerList[0];

    DEBUG_printf("reqType: %d\n", reqType);

    aux_data = convertAuxEventEncoding(aux_data, ENCODE_UTF8); //convert string UTF-16 --> UTF-8
    switch (reqType) {
    case PALETTEAUX_CONNECT:
        ret = le_proc_paletteaux_connect_event(s, aux_data);
        break;

    case PALETTEAUX_SWITCH_IME:
        ret = le_proc_paletteaux_switch_engine_event(s, aux_data);
        break;

    case PALETTEAUX_SWITCH_QJBJ:
        ret = le_proc_paletteaux_switch_qjbj_event(s, aux_data);
        break;

    case PALETTEAUX_SWITCH_PUNCT:
        ret = le_proc_paletteaux_switch_punct_event(s, aux_data);
        break;

    case COMMONAUX_COMMIT_STRING:
        ret = le_proc_commonaux_commit_string_event(s, aux_data);
        break;

    case COMMONAUX_COMMIT_KEY:
        ret = le_proc_commonaux_commit_key_event(s, aux_data);
        break;

    case PALETTEAUX_UPDATE_PROPERTY:
        ret = le_proc_paletteaux_update_property_event(s, aux_data);
        break;

    case COMPOSITE_PC_OPTION:
        ret = le_proc_pc_style_change(s, aux_data);
        break;

    case COMPOSITE_PC_CANDIDATE_SELECTION:
        ret = le_proc_pc_candidate_selection(s, aux_data);
        break;

    case COMPOSITE_PC_CANDIDATE_PAGE:
        ret = le_proc_pc_candidate_page(s, aux_data);
        break;

    case COMPOSITE_PC_MOVE:
        ret = le_proc_pc_move(s, aux_data);
        break;
    }
    freeConvertedEvent(aux_data);

    return (ret);
}

LeResult le_proc_paletteaux_connect_event(iml_session_t * s,
                                          IMAuxDrawCallbackStruct * aux_data)
{
    int locale_id;
    int ime_info_len;
    char *ime_info_str;

    int nIntegerCount, *pIntegerList;
    int nStringCount;

    LeDesktopContextRec *le_desktop_context = NULL;

    le_desktop_context =
        (LeDesktopContextRec *) le_session_get_desktop_context(s);

    le_desktop_context->palette_aux_started = 1;

    nIntegerCount = aux_data->count_integer_values;
    pIntegerList = aux_data->integer_values;
    nStringCount = aux_data->count_string_values;

    if (nIntegerCount != 3)
        return (LE_FAIL);

    locale_id = pIntegerList[1];
    ime_info_len = pIntegerList[2];

    if (ime_info_len > 0 && nStringCount == 1) {
        ime_info_str = (char *) aux_data->string_values[0].text.utf_chars;
#if 0
        ime_info_str[ime_info_len] = 0;
#endif

#if DEBUG
        printf("ime_info_len: %d\n", ime_info_len);
        printf("le_proc_paletteaux_connect_event:  locale_id: %d, ime_info_str:%s\n",
                        locale_id, ime_info_str);
#endif

        if (ime_info_str && *ime_info_str) {
            LeDesktopContextRec *le_desktop_context;
            le_desktop_context =
                (LeDesktopContextRec *) le_session_get_desktop_context(s);
            le_desktop_profile_new_from_memory(le_desktop_context, ime_info_str,
                                            strlen(ime_info_str));
        }
    }

    le_update_aux_imeinfo_notify(s, PALETTE_AUX_CLASS_NAME);
    return (LE_OK);
}

LeResult le_proc_paletteaux_update_property_event(iml_session_t * s,
                                                  IMAuxDrawCallbackStruct * aux_data)
{
    int locale_id;
    int ime_info_len;
    char *ime_info_str;

    int nIntegerCount, *pIntegerList;
    int nStringCount;

    nIntegerCount = aux_data->count_integer_values;
    pIntegerList = aux_data->integer_values;
    nStringCount = aux_data->count_string_values;

    if (nIntegerCount != 2 || nStringCount != 1)
        return (LE_FAIL);

    ime_info_len = pIntegerList[1];
    ime_info_str = (char *) aux_data->string_values[0].text.utf_chars;
    ime_info_str[ime_info_len-1] = 0;

#if DEBUG
    printf("ime_info_len: %d\n", ime_info_len);
    printf("le_proc_paletteaux_update_property_event:  locale_id: %d, ime_info_str:%s\n",
                    locale_id, ime_info_str);
#endif

    if (ime_info_str && *ime_info_str) {
        LeDesktopContextRec *le_desktop_context;
        le_desktop_context =
            (LeDesktopContextRec *) le_session_get_desktop_context(s);
        le_desktop_profile_new_from_memory(le_desktop_context, ime_info_str,
                                        strlen(ime_info_str));
    }

    return (LE_OK);
}

LeResult le_proc_paletteaux_switch_engine_event(iml_session_t * s,
                                                IMAuxDrawCallbackStruct *
                                                aux_data)
{
    char *ime_uuid;
    ImeModuleRec *ime_module = NULL;

    int nStringCount;

    nStringCount = aux_data->count_string_values;
    if (nStringCount != 1) return (LE_FAIL);

    ime_uuid = (char *) aux_data->string_values[0].text.utf_chars;
    DEBUG_printf("PALETTEAUX_SWITCH_IME:  uuid:%s\n", ime_uuid);

    if (!ime_uuid || !*ime_uuid) return (LE_FAIL);

    ime_module = (ImeModuleRec *) le_session_get_ime_module_by_uuid(s, ime_uuid);
    if (ime_module == NULL) return (LE_FAIL);

    le_session_switch_to_new_ime_module(s, ime_module);
    return (LE_OK);
}

LeResult le_proc_paletteaux_switch_qjbj_event(iml_session_t * s,
                                              IMAuxDrawCallbackStruct *
                                              aux_data)
{
    int qjbj;
    int nIntegerCount, *pIntegerList;

    nIntegerCount = aux_data->count_integer_values;
    pIntegerList = aux_data->integer_values;

    if (nIntegerCount != 2)
        return (LE_FAIL);

    qjbj = pIntegerList[1];
    DEBUG_printf("PALETTEAUX_SWITCH_QJBJ:  qjbj:%d\n", qjbj);

    /* FIXME, add functions to process qjbj switching */
    le_session_toggle_qjbj_status(s);
    return (LE_OK);
}

LeResult le_proc_paletteaux_switch_punct_event(iml_session_t * s,
                                               IMAuxDrawCallbackStruct *
                                               aux_data)
{
    int punct;
    int nIntegerCount, *pIntegerList;

    nIntegerCount = aux_data->count_integer_values;
    pIntegerList = aux_data->integer_values;

    if (nIntegerCount != 2)
        return (LE_FAIL);

    punct = pIntegerList[1];
    DEBUG_printf("PALETTEAUX_SWITCH_PUNCT:  punct: %d\n", punct);

    /* FIXME, add functions to process punct switching */
    le_session_toggle_punct_status(s);

    return (LE_OK);
}

LeResult le_proc_commonaux_commit_string_event(iml_session_t * s,
                                               IMAuxDrawCallbackStruct * aux_data)
{
    int encoding;
    int commit_str_len;
    char *commit_str;
    UTFCHAR tmp_buf[1024];
    UTFCHAR *tmp_ptr = tmp_buf;
    int from_len, to_left, ret;

    int nIntegerCount, *pIntegerList;
    int nStringCount, nStringLen;

    nIntegerCount = aux_data->count_integer_values;
    pIntegerList = aux_data->integer_values;
    nStringCount = aux_data->count_string_values;

    if (nIntegerCount != 3 || nStringCount != 1)
        return (LE_FAIL);

    encoding = pIntegerList[1];
    if (encoding < 0 || encoding > ENCODES_NUM)
        return (LE_FAIL);

    commit_str_len = pIntegerList[2];

    commit_str = (char *) aux_data->string_values[0].text.utf_chars;
    commit_str[commit_str_len] = 0;

    if (commit_str == NULL)
        return (LE_FAIL);

    DEBUG_printf("COMMONAUX_COMMIT_STRING Request Received: \n");
    DEBUG_printf("encoding:%d, command_str:%s, len:%d\n",
                 encoding, commit_str, strlen(commit_str));

    from_len = strlen(commit_str);
    to_left = 1024;
    memset(tmp_buf, 0, sizeof(UTFCHAR) * 1024);
    ret = Convert_Native_To_UTF16(encoding,
                                  commit_str,
                                  from_len,
                                  (char **) &tmp_ptr,
                                  (size_t *) & to_left);
    if (ret == -1)
        return (LE_FAIL);

    DEBUG_printf("begin do le_iml_commit for session: %p\n", s);
    le_iml_commit(s, tmp_buf);

    return (LE_OK);
}

LeResult le_proc_commonaux_commit_key_event(iml_session_t * s,
                                            IMAuxDrawCallbackStruct *
                                            aux_data)
{
    int keycode, keychar, keystatus;
    static IMKeyEventStruct akey;
    static IMKeyListEvent keyev;

    int nIntegerCount, *pIntegerList;

    nIntegerCount = aux_data->count_integer_values;
    pIntegerList = aux_data->integer_values;

    if (nIntegerCount != 4)
        return (LE_FAIL);

    keycode = pIntegerList[1];
    keychar = pIntegerList[2];
    keystatus = pIntegerList[3];

    DEBUG_printf("COMMONAUX_COMMIT_KEY Request Received: \n");
    DEBUG_printf("keycode:0x%x, keychar:0x%x, keystatus:0x%x\n",
                 keycode, keychar, keystatus);

    akey.keyCode = keycode;
    akey.keyChar = keychar;
    akey.modifier = keystatus;
    keyev.type = IM_EventKeyList;
    keyev.keylist = (IMKeyList) & akey;
    le_session_process_key_event(s, (IMKeyListEvent *) & keyev);

    return (LE_OK);
}

/* ============================================================== */
/*              Send information to Auxiliary Window              */
/* ============================================================== */
void le_update_aux_imeinfo_notify(iml_session_t * s, char *classname)
{
    int nIntegerCount, pIntegerList[1];
    int nStringsCount, pLenStrings[1];
    char *pStrings[1];

    char *ime_info_str;
    LeDesktopContextRec *le_desktop_context;

    DEBUG_printf("le_imeinfo_notify: ======\n");

    nIntegerCount = 1;
    pIntegerList[0] = COMMONAUX_IME_INFO_NOTIFY;

    le_desktop_context = (LeDesktopContextRec *) le_session_get_desktop_context(s);
    ime_info_str = (char *) le_desktop_profile_write_to_memory(le_desktop_context);
    if (ime_info_str == NULL)
        return;

    nStringsCount = 1;
    pLenStrings[0] = strlen(ime_info_str) + 1;
    pStrings[0] = (char *) ime_info_str;

#if DEBUG
    printf("ime_info: %s, len: %d\n", ime_info_str, strlen(ime_info_str));
#endif
    le_iml_aux_draw_native(s, classname,
                           nIntegerCount, pIntegerList,
                           ENCODE_UTF8, nStringsCount, pStrings);

    free((char *) ime_info_str);
    return;
}

/**********************************************************/
/*                      Palette Aux                       */
/**********************************************************/
void le_start_aux_objects(iml_session_t * s)
{
    LeDesktopContextRec *le_desktop_context = NULL;

    le_desktop_context =
        (LeDesktopContextRec *) le_session_get_desktop_context(s);

    if (le_desktop_context->palette_aux_started == 1)
        return;

    le_iml_aux_start(s, AUX_OBJECT_CLASS_NAME);
    le_iml_aux_start(s, PALETTE_AUX_CLASS_NAME);
}

void le_change_paletteaux_focus_notify(iml_session_t * s)
{
    char *classname = PALETTE_AUX_CLASS_NAME;
    int nIntegerCount, pIntegerList[4];
    int nStringsCount, pLenStrings[1];
    char *pStrings[1];
    char *ime_uuid;

    ImeModuleRec *current_ime_module;
    int show_status = True;
    int qjbj;
    int punct;

    current_ime_module =
        (ImeModuleRec *) le_session_get_current_ime_module(s);
    show_status = le_session_get_conversion_status(s);
    qjbj = le_session_get_qjbj_status(s);
    punct = le_session_get_punct_status(s);

    if (current_ime_module == NULL)
        show_status = False;

    DEBUG_printf("le_change_paletteaux_focus_notify: ======\n");

    nIntegerCount = 4;
    pIntegerList[0] = COMMONAUX_CHANGE_FOCUS_NOTIFY;
    pIntegerList[1] = show_status;
    pIntegerList[2] = qjbj;
    pIntegerList[3] = punct;

    ime_uuid = "NoIME";
    if (current_ime_module != NULL &&
        current_ime_module->info != NULL &&
        current_ime_module->info->uuid) {
        ime_uuid = (char *) current_ime_module->info->uuid;
    }

    DEBUG_printf("ime_uuid: %s\n", ime_uuid);
    nStringsCount = 1;
    pLenStrings[0] = strlen(ime_uuid) + 1;
    pStrings[0] = (char *) ime_uuid;

    le_iml_aux_draw_native(s, classname,
                           nIntegerCount, pIntegerList,
                           ENCODE_UTF8, nStringsCount, pStrings);
}

void le_beep_paletteaux_notify(iml_session_t * s, ImeBeepType beep_type)
{
    char *classname = PALETTE_AUX_CLASS_NAME;
    int nIntegerCount, pIntegerList[2];

    DEBUG_printf("le_beep_paletteaux_notify: ====== beep_type: %d\n", beep_type);

    nIntegerCount = 2;
    pIntegerList[0] = PALETTEAUX_BEEP_NOTIFY;
    pIntegerList[1] = beep_type;

    le_iml_aux_draw(s, classname, nIntegerCount, pIntegerList, 0, NULL, NULL);
}

void le_show_paletteaux_notify(iml_session_t * s)
{
    char *classname = PALETTE_AUX_CLASS_NAME;
    int nIntegerCount, pIntegerList[2];

    DEBUG_printf("le_show_paletteaux_notify: ======\n");

    nIntegerCount = 1;
    pIntegerList[0] = COMMONAUX_SHOW_NOTIFY;

    le_iml_aux_draw(s, classname, nIntegerCount, pIntegerList, 0, NULL, NULL);
}

void le_hide_paletteaux_notify(iml_session_t * s)
{
    char *classname = PALETTE_AUX_CLASS_NAME;
    int nIntegerCount, pIntegerList[2];

    DEBUG_printf("le_hide_paletteaux_notify: ======\n");

    nIntegerCount = 1;
    pIntegerList[0] = COMMONAUX_HIDE_NOTIFY;

    le_iml_aux_draw(s, classname, nIntegerCount, pIntegerList, 0, NULL, NULL);
}

void le_update_paletteaux_ime_notify(iml_session_t * s)
{
    char *classname = PALETTE_AUX_CLASS_NAME;
    int nIntegerCount, pIntegerList[2];
    int nStringsCount, pLenStrings[1];
    char *pStrings[1];
    char *ime_uuid;

    int show_status = True;

    ImeModuleRec *current_ime_module;

    current_ime_module =
        (ImeModuleRec *) le_session_get_current_ime_module(s);
    if (current_ime_module == NULL)
        show_status = False;

    DEBUG_printf("le_switch_paletteaux_ime_notify: ======\n");

    nIntegerCount = 2;
    pIntegerList[0] = PALETTEAUX_SWITCH_IME_NOTIFY;
    pIntegerList[1] = show_status;

    ime_uuid = "NoIME";
    if (current_ime_module != NULL &&
        current_ime_module->info != NULL &&
        current_ime_module->info->uuid) {
        ime_uuid = (char *) current_ime_module->info->uuid;
    }

    nStringsCount = 1;
    pLenStrings[0] = strlen(ime_uuid) + 1;
    pStrings[0] = (char *) ime_uuid;

    le_iml_aux_draw_native(s, classname,
                           nIntegerCount, pIntegerList,
                           ENCODE_UTF8, nStringsCount, pStrings);
}

void le_update_paletteaux_qjbj_notify(iml_session_t * s)
{
    char *classname = PALETTE_AUX_CLASS_NAME;
    int nIntegerCount, pIntegerList[2];

    int qjbj = le_session_get_qjbj_status(s);

    DEBUG_printf("le_update_paletteaux_qjbj_notify: ====== qjbj: %d\n",
                 qjbj);

    nIntegerCount = 2;
    pIntegerList[0] = PALETTEAUX_SWITCH_QJBJ_NOTIFY;
    pIntegerList[1] = qjbj;

    le_iml_aux_draw(s, classname, nIntegerCount, pIntegerList, 0, NULL, NULL);
}

void le_update_paletteaux_punct_notify(iml_session_t * s)
{
    char *classname = PALETTE_AUX_CLASS_NAME;
    int nIntegerCount, pIntegerList[2];

    int punct = le_session_get_punct_status(s);

    DEBUG_printf("le_update_paletteaux_punct_notify: ======\n");

    nIntegerCount = 2;
    pIntegerList[0] = PALETTEAUX_SWITCH_PUNCT_NOTIFY;
    pIntegerList[1] = punct;

    le_iml_aux_draw(s, classname, nIntegerCount, pIntegerList, 0, NULL, NULL);
}

/**********************************************************/
/*                      Select Aux                        */
/**********************************************************/
void le_show_selectaux_notify(iml_session_t * s)
{
    char *classname = SELECT_AUX_CLASS_NAME;
    int nIntegerCount, pIntegerList[2];

    DEBUG_printf("le_show_selectaux_notify: ======\n");

    nIntegerCount = 1;
    pIntegerList[0] = COMMONAUX_SHOW_NOTIFY;

    le_iml_aux_draw(s, classname, nIntegerCount, pIntegerList, 0, NULL, NULL);
}

void le_show_propertiesaux_notify(iml_session_t * s)
{
    char *classname = PROPERTIES_AUX_CLASS_NAME;
    int nIntegerCount, pIntegerList[2];

    DEBUG_printf("le_show_propertyaux_notify: ======\n");

    nIntegerCount = 1;
    pIntegerList[0] = COMMONAUX_SHOW_NOTIFY;

    le_iml_aux_draw(s, classname, nIntegerCount, pIntegerList, 0, NULL, NULL);

}

/**********************************************************/
/*                      CompositeAux                      */
/**********************************************************/
void le_change_compositeaux_option_notify(LeSessionContextRec* le_session_context)
{
    int  pIntList[1+sizeof(TImePCAuxOption)/sizeof(int) + 4];

    pIntList[0] = COMPOSITE_PC_OPTION;
    *(TImePCAuxOption*)(pIntList+1) = *(TImePCAuxOption*)session_get_pc_style(le_session_context);

    session_get_pc_position(le_session_context,
                            pIntList+sizeof(TImePCAuxOption)/sizeof(int)+1,
                            pIntList+sizeof(TImePCAuxOption)/sizeof(int)+2,
                            pIntList+sizeof(TImePCAuxOption)/sizeof(int)+3,
                            pIntList+sizeof(TImePCAuxOption)/sizeof(int)+4);

    le_iml_aux_draw(le_session_context->s,
                    session_get_pc_aux_name(le_session_context),
                    sizeof(pIntList)/sizeof(int), pIntList,
                    0, NULL, NULL);

}

void le_show_compositeaux_preedit_notify(iml_session_t * s, char* classname)
{
    int nIntegerCount, pIntegerList[2];

    DEBUG_printf("le_show_compositeaux_preedit_notify: ======\n");

    nIntegerCount = 1;
    pIntegerList[0] = COMMONAUX_SHOW_PREEDIT_NOTIFY;

    le_iml_aux_draw(s, classname, nIntegerCount, pIntegerList, 0, NULL, NULL);
}

void le_hide_compositeaux_preedit_notify(iml_session_t * s, char* classname)
{
    int nIntegerCount, pIntegerList[2];

    DEBUG_printf("le_hide_compositeaux_preedit_notify: ======\n");

    nIntegerCount = 1;
    pIntegerList[0] = COMMONAUX_HIDE_PREEDIT_NOTIFY;

    le_iml_aux_draw(s, classname, nIntegerCount, pIntegerList, 0, NULL, NULL);
}

LeResult le_update_pc_position                     (iml_session_t *s,
                                                    char          *classname,
                                                    int            cursor_x,
                                                    int            cursor_y,
                                                    int            cursor_w,
                                                    int            cursor_h)
{
    int nIntegerCount, pIntegerList[5];

    nIntegerCount = 5;
    pIntegerList[0] = COMPOSITE_PC_MOVE;
    pIntegerList[1] = cursor_x;
    pIntegerList[2] = cursor_y;
    pIntegerList[3] = cursor_w;
    pIntegerList[4] = cursor_h;

    le_iml_aux_draw(s, classname, nIntegerCount, pIntegerList, 0, NULL, NULL);
}

int  le_update_compositeaux_preedit_notify(LeSessionContextRec  *le_session_context,
                                           char                 *classname,
                                           ImePreeditRec        *ime_preedit)
{
    ImeEncoding encoding;
    int i, from_len, to_left, ret;
    char tmp_buf[1024];
    char *tmp_ptr = tmp_buf;

    memset(tmp_buf, 0, sizeof(tmp_buf));
    if (ime_preedit && ime_preedit->preedit.text) {
        //FIX ME, assume only multibyte string encoding used, including UTF-8
        ImeEncoding encoding = le_session_get_current_ime_encoding(le_session_context->s);
        from_len = strlen(ime_preedit->preedit.text);
        to_left = 1024;
        ret = Convert_Native_To_UTF8(encoding,
                                 ime_preedit->preedit.text,
                                 from_len,
                                 (char **) &tmp_ptr,
                                 (size_t *) & to_left);
        if (ret == -1)
            tmp_buf[0] = 0;
    }

    DEBUG_printf("le_update_compositeaux_preedit_notify: ====== [%s]\n", tmp_buf);

    int nIntegerCount = 3 + ime_preedit->preedit.count_feedbacks * 4;
    int pIntegerList[nIntegerCount];

    pIntegerList[0] = COMMONAUX_UPDATE_PREEDIT_NOTIFY;
    pIntegerList[1] = ime_preedit->caret;
    pIntegerList[2] = ime_preedit->cl_start;

    for (i=0; i < ime_preedit->preedit.count_feedbacks; ++i) {
        pIntegerList[i*4+3+0] = ime_preedit->preedit.feedbacks[i].type;
        pIntegerList[i*4+3+1] = ime_preedit->preedit.feedbacks[i].value;
        pIntegerList[i*4+3+2] = ime_preedit->preedit.feedbacks[i].start;
        pIntegerList[i*4+3+3] = ime_preedit->preedit.feedbacks[i].length;
    }

    tmp_ptr = tmp_buf;
    le_iml_aux_draw_native(le_session_context->s, classname,
                           nIntegerCount, pIntegerList,
                           ENCODE_UTF8, 1, &tmp_ptr);
    return IME_OK;
}

void le_show_compositeaux_candidates_notify(iml_session_t * s, char* classname)
{
    int nIntegerCount, pIntegerList[2];


    nIntegerCount = 1;
    pIntegerList[0] = COMMONAUX_SHOW_CANDIDATES_NOTIFY;

    le_iml_aux_draw(s, classname, nIntegerCount, pIntegerList, 0, NULL, NULL);
}

void le_hide_compositeaux_candidates_notify(iml_session_t * s, char* classname)
{
    int nIntegerCount, pIntegerList[2];

    DEBUG_printf("le_show_compositeaux_candidates_notify: ======\n");

    nIntegerCount = 1;
    pIntegerList[0] = COMMONAUX_HIDE_CANDIDATES_NOTIFY;

    le_iml_aux_draw(s, classname, nIntegerCount, pIntegerList, 0, NULL,  NULL);
}

int le_update_compositeaux_candidates_notify(LeSessionContextRec  *le_session_context,
                                              char                 *classname,
                                              ImeCandidatesRec     *ime_candidates)
{
    char **candidates = NULL;
    char tmp_buf[1024];
    char *tmp_cand_ptr;

    if (le_session_context == NULL || le_session_context->s == NULL || ime_candidates == NULL)
        return IMM_FAIL;

    ImeEncoding encoding = le_session_get_current_ime_encoding(le_session_context->s);
    int from_len, to_left, ret, i, j, num_candidates = ime_candidates->count;

    candidates = (char **) calloc(num_candidates+1, sizeof(char *)); //one for title
    if (candidates == NULL)  return (IMM_FAIL);

    int nIntegerCount = num_candidates + 4; // + 4*sum(fb_count)
    for (i = 0; i <num_candidates; i++) {
        ret = -1;
        if (ime_candidates != NULL && ime_candidates->candidates[i].text != NULL) {
            from_len = strlen(ime_candidates->candidates[i].text);
            to_left = 1024;
            memset(tmp_buf, 0, sizeof(tmp_buf));
            tmp_cand_ptr = tmp_buf;
            ret = Convert_Native_To_UTF8(encoding,
                                     ime_candidates->candidates[i].text,
                                     from_len,
                                     (char **) &tmp_cand_ptr,
                                     (size_t *) & to_left);
        }
        if (ret == -1) {
             ((char*)tmp_buf)[0] = 0x0;
             to_left = 1024;
        }

        candidates[i] = (char *)calloc(1024 - to_left + 4, sizeof(char));

        if (candidates[i] != NULL) {
            candidates[i][0] = (ime_candidates->numbers)?(ime_candidates->numbers[i]) : ('1' + i);
            candidates[i][1] = '.';
            candidates[i][2] = ' ';
            candidates[i][3] = 0;

            strcat(candidates[i], tmp_buf);
        }
        nIntegerCount += 4 * ime_candidates->candidates[i].count_feedbacks;
    }

    //last one for title
    ret = -1;
    if (ime_candidates->title) {
        from_len = strlen(ime_candidates->title);
        to_left = 1024;
        memset(tmp_buf, 0, sizeof(tmp_buf));
        tmp_cand_ptr = tmp_buf;
        ret = Convert_Native_To_UTF8(encoding,
                                     ime_candidates->title,
                                     from_len,
                                     (char **) &tmp_cand_ptr,
                                     (size_t *) & to_left);
    }
    if (ret == -1) {
         ((char*)tmp_buf)[0] = 0x0;
         to_left = 1024;
    }
    candidates[i] = (char *)calloc(1024 - to_left + 1, sizeof(char));
    if (candidates[i] != NULL) {
        strcpy(candidates[i], tmp_buf);
    }

    int pIntegerList[nIntegerCount];

    DEBUG_printf("le_update_compositeaux_candidates_notify: ======\n");

    pIntegerList[0] = COMMONAUX_UPDATE_CANDIDATES_NOTIFY;
    pIntegerList[1] = num_candidates;
    pIntegerList[2] = ime_candidates->page_state;
    pIntegerList[3] = ime_candidates->focus;

    int * p_fb_counts = pIntegerList + 4;
    ImeFeedbackRec* pfbs = (ImeFeedbackRec*)(p_fb_counts + num_candidates);
    for (i=0; i < num_candidates; ++i) {
        p_fb_counts[i] = ime_candidates->candidates[i].count_feedbacks;
        memcpy(pfbs, ime_candidates->candidates[i].feedbacks, p_fb_counts[i]*sizeof(ImeFeedbackRec));
        for (j=0; j < p_fb_counts[i]; ++j) {
            pfbs[j].start += 3; // for number string
        }
        pfbs += p_fb_counts[i];
    }

    le_iml_aux_draw_native(le_session_context->s, classname,
                           nIntegerCount, pIntegerList,
                           ENCODE_UTF8, num_candidates + 1, candidates);


    for (i = 0; i < num_candidates+1; i++) {
        if (candidates[i]) free(candidates[i]);
    }
    if (candidates) free(candidates);
}

LeResult le_proc_pc_style_change                   (iml_session_t            *s,
                                                    IMAuxDrawCallbackStruct  *aux_data)
{
    int  nIntegerCount = aux_data->count_integer_values;
    int *pIntegerList = aux_data->integer_values;

    if (nIntegerCount != 1 + sizeof(TImePCAuxOption)/sizeof(int))
        return (LE_FAIL);

    DEBUG_printf("Session change PCAux style\n");
    return session_proc_style_change(s, pIntegerList+1);
}

LeResult le_proc_pc_candidate_selection            (iml_session_t            *s,
                                                    IMAuxDrawCallbackStruct  *aux_data)
{
    int  nIntegerCount = aux_data->count_integer_values;
    int *pIntegerList = aux_data->integer_values;

    if (nIntegerCount != 2) return LE_FAIL;

    DEBUG_printf("candidate selection from client\n");
    return session_proc_candidate_selection(s, pIntegerList[1]);
}

LeResult le_proc_pc_candidate_page                 (iml_session_t            *s,
                                                    IMAuxDrawCallbackStruct  *aux_data)
{
    int  nIntegerCount = aux_data->count_integer_values;
    int *pIntegerList = aux_data->integer_values;

    if (nIntegerCount != 2) return LE_FAIL;

    DEBUG_printf("candidate page request from client\n");
    return session_proc_candidate_page(s, pIntegerList[1]);
}

LeResult le_proc_pc_move                           (iml_session_t            *s,
                                                    IMAuxDrawCallbackStruct  *aux_data)
{
    int  nIntegerCount = aux_data->count_integer_values;
    int *pIntegerList = aux_data->integer_values;

    if (nIntegerCount != 5) return LE_FAIL;

    DEBUG_printf("PC Aux move position\n");
    return session_proc_pc_move(s, pIntegerList[1], pIntegerList[2], pIntegerList[3], pIntegerList[4]);
}


