#include <stdio.h>

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

LeDesktopContextRec *le_session_get_desktop_context(iml_session_t * s);
LeSessionContextRec *le_session_get_session_context(iml_session_t * s);
ImeModuleRec *le_session_get_current_ime_module(iml_session_t * s);
LeResult le_session_update_status_string(iml_session_t * s,
                                         ConversionStatus
                                         conversion_status);


static LeResult le_session_focus_out(iml_session_t * s);
static LeResult le_session_focus_in(iml_session_t * s);

/* UTF-8 string of [ Ӣ�� ] */
unsigned char English_Status_UTF[] = {
    0xe8, 0x8b, 0xb1, 0x0
};

unsigned char Chinese_Status_UTF[] = {
    0xe4, 0xb8, 0xad, 0x0
};

/*****************************************
      LeSessionContextRec
*****************************************/
LeSessionContextRec *le_session_context_new()
{
    LeSessionContextRec *le_session_context = NULL;

    le_session_context = (LeSessionContextRec *) calloc(1, sizeof(LeSessionContextRec));
    if (le_session_context == NULL) return (NULL);

    le_session_context->client_encoding = ENCODE_UTF8;
    le_session_context->current_ime_module = NULL;
    le_session_context->current_qjbj_status = QJBJ_HALFWIDTH;
    le_session_context->current_punct_status = PUNCT_ENGLISH;
    le_session_context->current_conversion_status = CONVERSION_OFF;

    return (le_session_context);
}

LeResult le_session_context_destroy(LeSessionContextRec * le_session_context)
{
    if (le_session_context == NULL)
        return (LE_FAIL);

    free((char *)le_session_context);

    return (LE_OK);
}

LeResult le_session_context_print(LeSessionContextRec * le_session_context)
{
    if (le_session_context == NULL)
        return (LE_FAIL);

    return (LE_OK);
}


//FIXME, this should be put into server configuration files
static TImePCAuxOption dummyPCOpt[] = {
{
    0,    //type, custom;
    1,    //showSystemBar;
    1,    //followCursor;
    1,    //composite;
    1,    //showPageControl;
    1,    //ignorCandidateTitle;
    0,    //candidateVertical;
    2,    //candidatePosition -- stick right
    0     //candidateTitlePosition -- Left or Above
},

{ //for sunpinyin
    0,    //type, custom;
    1,    //showSystemBar;
    1,    //followCursor;
    1,    //composite;
    1,    //showPageControl;
    1,    //ignorCandidateTitle;
    0,    //candidateVertical;
    1,    //candidatePosition -- ime specify
    1     //candidateTitlePosition -- Left or Above
},

{
    0,    //type, custom;
    1,    //showSystemBar;
    1,    //followCursor;
    0,    //composite;
    1,    //showPageControl;
    1,    //ignorCandidateTitle;
    1,    //candidateVertical;
    2,    //candidatePosition -- stick right;
    0     //candidateTitlePosition -- Left or Above
}

};

void
session_set_pc_position(LeSessionContextRec* le_session_context, 
                        int cursor_x, int cursor_y, int cursor_w, int cursor_h)
{
    ImeModuleRec *current_ime_module = le_session_context->current_ime_module;
    if (current_ime_module != NULL && current_ime_module->info != NULL && current_ime_module->info->uuid != NULL) {
        current_ime_module->pc_cursor_x = cursor_x;
        current_ime_module->pc_cursor_y = cursor_y;
        current_ime_module->pc_cursor_w = cursor_w;
        current_ime_module->pc_cursor_h = cursor_h;
    }
}

void
session_get_pc_position(LeSessionContextRec* le_session_context, 
                        int *cursor_x, int *cursor_y, int *cursor_w, int *cursor_h)
{
    ImeModuleRec *current_ime_module = le_session_context->current_ime_module;
    if (current_ime_module != NULL && current_ime_module->info != NULL && current_ime_module->info->uuid != NULL) {
        *cursor_x = current_ime_module->pc_cursor_x;
        *cursor_y = current_ime_module->pc_cursor_y;
        *cursor_w = current_ime_module->pc_cursor_w;
        *cursor_h = current_ime_module->pc_cursor_h;
    } else {
        *cursor_x = 300;
        *cursor_y = 500;
        *cursor_w = 1;
        *cursor_h = 2;
    }
}

char*
session_get_pc_aux_name(LeSessionContextRec* le_session_context)
{
    ImeModuleRec *current_ime_module = le_session_context->current_ime_module;
    if (current_ime_module != NULL && current_ime_module->info != NULL && current_ime_module->info->uuid != NULL) {
        if (current_ime_module->pc_aux_name[0])
            return current_ime_module->pc_aux_name;
    }
    return NULL;
}

void
session_set_pc_aux_name(LeSessionContextRec* le_session_context, const char* aux_name)
{
    ImeModuleRec *current_ime_module = le_session_context->current_ime_module;
    if (current_ime_module != NULL && current_ime_module->info != NULL && current_ime_module->info->uuid != NULL) {
        strncpy(current_ime_module->pc_aux_name, aux_name, sizeof(current_ime_module->pc_aux_name));
    }
}

TImePCAuxOption*
session_get_pc_style(LeSessionContextRec* le_session_context)
{
    ImeModuleRec *current_ime_module = le_session_context->current_ime_module;
    if (current_ime_module != NULL && current_ime_module->info != NULL && current_ime_module->info->uuid != NULL) {
        return &current_ime_module->pc_aux_options;
    }
    return NULL;
}

static void 
session_init_ime_pc_aux_options(LeSessionContextRec   *le_session_context)
{
    ImeModuleRec *current_ime_module = le_session_context->current_ime_module;
    
    if (current_ime_module != NULL && current_ime_module->info != NULL && current_ime_module->info->uuid != NULL) {
        if (session_get_pc_aux_name(le_session_context) == NULL) {
            session_set_pc_aux_name(le_session_context, COMPOSITE_AUX_CLASS_NAME);
            TImePCAuxOption* p_pc_style = session_get_pc_style(le_session_context);
            if (strcmp(current_ime_module->info->uuid, "SunPinyin-ef1a0a92-9f0e-410b-b8a8-e6f296c1801c") == 0) {
                *p_pc_style = dummyPCOpt[1];
            } else {
                *p_pc_style = dummyPCOpt[2];
            }
        }
    }
}

static LeResult
session_detach_ime(LeSessionContextRec * le_session_context)
{
    ImeModuleRec* current_ime_module = le_session_context->current_ime_module;
    if (current_ime_module != NULL) {
        if (current_ime_module->methods->ImeDestroySession != NULL) {
            current_ime_module->methods->ImeDestroySession((ImeInputContext) le_session_context);
            le_session_context->ime_session_data = NULL;
        }
        le_session_context->preedit_show = 0;
        le_session_context->candidates_show = 0;
        freeImPreeditInternal(&le_session_context->preedit_backup);
        freeImCandidatesInternal(&le_session_context->candidates_backup);
/*
        le_session_context->current_ime_module = NULL;
*/
    }

    /*
    if (le_session_context->pc_aux_name) free(le_session_context->pc_aux_name);
    if (le_session_context->pc_aux_options) free(le_session_context->pc_aux_options);
    le_session_context->pc_aux_name = NULL;
    le_session_context->pc_aux_options = NULL;
    */

    le_session_context->current_conversion_status = CONVERSION_OFF;
}

static LeResult
session_attach_ime(LeSessionContextRec * le_session_context, ImeModuleRec* new_ime_module)
{
    le_session_context->current_ime_module = new_ime_module;
    if (new_ime_module != NULL) {
        session_init_ime_pc_aux_options(le_session_context);
    
        if (new_ime_module->methods->ImeCreateSession != NULL)
            new_ime_module->methods->ImeCreateSession((ImeInputContext) le_session_context);

        if (new_ime_module->methods->ImeProcessUIEvent != NULL) {
            ImeEventRec trigger;

            trigger.notify_event.type = IME_EVENT_IMM_NOTIFY;
            trigger.notify_event.peer = 0;      // should not be used, it is from IMM
            trigger.notify_event.ic = (ImeInputContext) le_session_context;
            trigger.notify_event.trigger = IMM_TRIGGER_FULL_HALF_SIMBOL;
            trigger.notify_event.value = (le_session_context->current_qjbj_status == QJBJ_FULLWIDTH) ? 1 : 0;
            new_ime_module->methods-> ImeProcessUIEvent((ImeInputContext) le_session_context, &trigger);

            trigger.notify_event.type = IME_EVENT_IMM_NOTIFY;
            trigger.notify_event.peer = 0;      // should not be used, it is from IMM
            trigger.notify_event.ic = (ImeInputContext) le_session_context;
            trigger.notify_event.trigger = IMM_TRIGGER_FULL_HALF_PUNC;
            trigger.notify_event.value = (le_session_context->current_punct_status == PUNCT_CHINESE) ? 1 : 0;
            new_ime_module->methods-> ImeProcessUIEvent((ImeInputContext) le_session_context, &trigger);
        }
        le_session_context->current_conversion_status = CONVERSION_ON;
    }
    //focus_in should be called later
}

/*****************************************
      LE Session for iml_session_t
*****************************************/
LeSessionContextRec *le_session_create(iml_session_t * s)
{
    LeDesktopContextRec *le_desktop_context = NULL;
    LeSessionContextRec *le_session_context = NULL;
    int default_qjbj_status;
    int default_punct_status;
    int default_conversion_status;

    le_session_context = (LeSessionContextRec *) s->specific_data;
    if (le_session_context != NULL) return (le_session_context);

    le_session_context = (LeSessionContextRec *) le_session_context_new();
    if (le_session_context == NULL) return (NULL);

    le_desktop_context = (LeDesktopContextRec *) le_session_get_desktop_context(s);
    default_qjbj_status = le_desktop_context_get_default_qjbj_status(le_desktop_context);
    default_punct_status = le_desktop_context_get_default_punct_status(le_desktop_context);
    default_conversion_status = le_desktop_context_get_default_conversion_status(le_desktop_context);

    le_session_context->current_qjbj_status = default_qjbj_status;
    le_session_context->current_punct_status = default_punct_status;
    le_session_context->current_conversion_status = default_conversion_status;

    le_session_context->s = s;

    s->specific_data = (void *)le_session_context;

    return (le_session_context);
}

LeResult le_session_destroy(iml_session_t * s)
{
    DEBUG_printf("le_session_destroy: s: 0x%x\n", s);

    LeSessionContextRec* le_session_context = le_session_get_session_context(s);

    if (le_session_context != NULL) {
        LeDesktopContextRec* le_desktop_context = (LeDesktopContextRec *)le_session_get_desktop_context(s);
        iml_session_t* cfs = (iml_session_t *)le_desktop_context_get_current_session(le_desktop_context); 

        le_session_focus_out(s);
        session_detach_ime(le_session_context);
        le_session_context_destroy(le_session_context);

        if (cfs == s)
            le_desktop_context_set_current_session(le_desktop_context, NULL);
    }

    s->specific_data = NULL;

    return (LE_OK);
}

static
LeResult le_session_focus_out(iml_session_t * s)
{
    LeDesktopContextRec* le_desktop_context = (LeDesktopContextRec *)le_session_get_desktop_context(s);
    LeSessionContextRec *le_session_context = (LeSessionContextRec *)le_session_get_session_context(s);

    int wrong_seq = 0;
    if(le_desktop_context)
        wrong_seq = le_desktop_context->focus_seq_wrong;

    if (le_session_context != NULL && !wrong_seq) {
            le_session_update_status_string(s, CONVERSION_OFF/*le_session_context->current_conversion_status*/);
            le_hide_paletteaux_notify(s);

        ImeModuleRec *current_ime_module = le_session_context->current_ime_module;
        if (current_ime_module && current_ime_module->methods && current_ime_module->methods->ImeFocusOut)
            current_ime_module->methods->ImeFocusOut((ImeInputContext)le_session_context);

        if (session_get_pc_aux_name(le_session_context)) {
            le_hide_candidates_atomic(le_session_context, 0);
            le_hide_preedit_atomic(le_session_context, 0);
        }
    }

    if(le_desktop_context)
        le_desktop_context->focus_seq_wrong = 0;

    return (LE_OK);
}

LeResult le_session_set_focus_out(iml_session_t * s)
{
    LeDesktopContextRec* le_desktop_context = (LeDesktopContextRec *)le_session_get_desktop_context(s);
    iml_session_t* cfs = (iml_session_t *)le_desktop_context_get_current_session(le_desktop_context); 

    DEBUG_printf("le_session_focus_out: 0x%x, and current focus 0x%x\n", s, cfs);

    le_session_focus_out(s);

    if (cfs == s)
        le_desktop_context_set_current_session(le_desktop_context, NULL);
}

static
LeResult le_session_focus_in(iml_session_t * s)
{
    LeSessionContextRec* le_session_context = le_session_get_session_context(s);
    if (le_session_context != NULL) {
        le_change_paletteaux_focus_notify(s);

        le_update_paletteaux_qjbj_notify(s);
        le_update_paletteaux_punct_notify(s);

        le_session_update_status_string(s, le_session_context->current_conversion_status);

        if (session_get_pc_aux_name(le_session_context)) {
            int cursor_x, cursor_y, cursor_w, cursor_h;

            session_get_pc_position(le_session_context, &cursor_x, &cursor_y, &cursor_w, &cursor_h);

            le_hide_candidates_atomic(le_session_context, 0);
            le_hide_preedit_atomic(le_session_context, 0);
            le_change_compositeaux_option_notify(le_session_context);
            le_update_pc_position(s, 
                                  session_get_pc_aux_name(le_session_context),
                                  cursor_x,
                                  cursor_y,
                                  cursor_w,
                                  cursor_h);

            le_update_preedit_atomic(le_session_context, &le_session_context->preedit_backup, 0);
            if (le_session_context->preedit_show)
                le_show_preedit_atomic(le_session_context, 0);

            le_update_candidates_atomic(le_session_context, &le_session_context->candidates_backup, 0);
            if (le_session_context->candidates_show)
                le_show_candidates_atomic(le_session_context, 0);
        }

        ImeModuleRec* current_ime_module = le_session_context->current_ime_module;
        if (current_ime_module && current_ime_module->methods  && current_ime_module->methods->ImeFocusIn)
            current_ime_module->methods->ImeFocusIn((ImeInputContext)le_session_context);
    }

    return (LE_OK);
}

LeResult le_session_set_focus_in(iml_session_t * s)
{
    LeDesktopContextRec* le_desktop_context = (LeDesktopContextRec *)le_session_get_desktop_context(s);
    iml_session_t* cfs = (iml_session_t *)le_desktop_context_get_current_session(le_desktop_context); 

    DEBUG_printf("le_session_focus_in: switch session from 0x%x to 0x%x\n", cfs, s);

    if (cfs != NULL) {
        le_session_focus_out(cfs);
        le_desktop_context_set_current_session(le_desktop_context, NULL);
        le_desktop_context->focus_seq_wrong = 1;
    }
    le_session_focus_in(s);
    le_desktop_context_set_current_session(le_desktop_context, s);
}

IMText *le_session_reset(iml_session_t * s)
{
    return ((IMText *) NULL);
}

/*****************************************
      LE Session Functions for iml_session_t
*****************************************/
LeDesktopContextRec *le_session_get_desktop_context(iml_session_t * s)
{
    return ((LeDesktopContextRec *) s->desktop->specific_data);
}

LeSessionContextRec *le_session_get_session_context(iml_session_t * s)
{
    return (LeSessionContextRec *)s->specific_data;
}

ImeModuleRec *le_session_get_ime_module_by_uuid(iml_session_t * s,
                                                char *uuid)
{
    LeDesktopContextRec *le_desktop_context = NULL;
    int i;

    le_desktop_context = (LeDesktopContextRec *) le_session_get_desktop_context(s);
    if (le_desktop_context == NULL || le_desktop_context->ime_modules == NULL)
        return (NULL);

    for (i = 0; i < le_desktop_context->num_ime_modules; i++) {
        ImeModuleRec *ime_module =
            le_desktop_context->ime_modules[i]->ime_module;
        if (!strncmp
            (ime_module->info->uuid, uuid, strlen(ime_module->info->uuid)))
            return (ime_module);
    }
    return (NULL);
}

ImeModuleRec *le_session_get_current_ime_module(iml_session_t * s)
{
    LeSessionContextRec *le_session_context = NULL;

    le_session_context = le_session_get_session_context(s);
    if (le_session_context == NULL)
        return (NULL);

    return (le_session_context->current_ime_module);
}

ImePropertyListRec *le_session_get_current_ime_module_property_list(
    iml_session_t * s)
{
    LeDesktopContextRec *le_desktop_context = NULL;
    LeSessionContextRec *le_session_context = NULL;
    ImeModuleRec *current_ime_module;
    ImePropertyListRec *pl;
    int i;

    le_session_context = le_session_get_session_context(s);
    if (le_session_context == NULL)
        return (NULL);

    current_ime_module = le_session_context->current_ime_module;
    if (current_ime_module == NULL)
        return (NULL);

    le_desktop_context =
        (LeDesktopContextRec *) le_session_get_desktop_context(s);
    if (le_desktop_context == NULL ||
        le_desktop_context->ime_modules == NULL)
        return (current_ime_module->info->pl);

    for (i = 0; i < le_desktop_context->num_ime_modules; i++) {
	ImeModuleContextRec *ime_module_context = le_desktop_context->ime_modules[i];
	if (ime_module_context == NULL)
	    continue;

	if (current_ime_module == ime_module_context->ime_module) {
	    if (ime_module_context->pl)
	        return (ime_module_context->pl);
	}
    }

    return (current_ime_module->info->pl);
}

ImeModuleRec *le_session_get_next_ime_module(iml_session_t * s)
{
    LeDesktopContextRec *le_desktop_context = NULL;
    LeSessionContextRec *le_session_context = NULL;
    ImeModuleRec *current_ime_module;
    int current_ime_id;
    int i;

    le_session_context = le_session_get_session_context(s);
    if (le_session_context == NULL)
        return (NULL);

    current_ime_module = le_session_context->current_ime_module;
    le_desktop_context =
        (LeDesktopContextRec *) le_session_get_desktop_context(s);
    if (le_desktop_context == NULL ||
        le_desktop_context->ime_modules == NULL)
        return (NULL);

#if 0
    if (current_ime_module == NULL)
        return ((ImeModuleRec *)
                le_desktop_context_get_default_ime_module
                (le_desktop_context));
#endif
    current_ime_id = -1;
    if (current_ime_module != NULL) {
        for (i = 0; i < le_desktop_context->num_ime_modules; i++) {
            if (current_ime_module ==
                le_desktop_context->ime_modules[i]->ime_module) {
                current_ime_id = i;
                break;
            }
        }
    }
    for (i = 0; i < le_desktop_context->num_ime_modules; i++) {
        ImeModuleContextRec *ime_module_context;
        int ime_module_id;

        ime_module_id = current_ime_id + i + 1;
        ime_module_id %= le_desktop_context->num_ime_modules;

        ime_module_context = le_desktop_context->ime_modules[ime_module_id];
        if (ime_module_context->enabled)
            return (ime_module_context->ime_module);
    }

    return (NULL);
}


void le_session_switch_to_new_ime_module(iml_session_t * s, ImeModuleRec * new_ime_module)
{
    DEBUG_printf("le_session_switch_to_new_ime_module: %x(%s)\n", 
                  new_ime_module, (new_ime_module)?(new_ime_module->info->uuid):"NULL");

    LeSessionContextRec *le_session_context = (LeSessionContextRec *)le_session_get_session_context(s);

    if (le_session_context == NULL) return;

    le_session_focus_out(s);
    session_detach_ime(le_session_context);
    session_attach_ime(le_session_context, new_ime_module);
    le_session_focus_in(s);

    return;
}

void le_session_switch_to_next_ime_module(iml_session_t * s)
{
    ImeModuleRec *next_ime_module;

    next_ime_module = le_session_get_next_ime_module(s);
    le_session_switch_to_new_ime_module(s, next_ime_module);
    return;
}

LeBoolean le_session_check_if_ime_available(iml_session_t * s)
{
    ImeModuleRec *current_ime_module =
        (ImeModuleRec *) le_session_get_current_ime_module(s);
    if (current_ime_module == NULL)
        return (LE_FALSE);
    return (LE_TRUE);
}

ImeEncoding le_session_get_current_ime_encoding(iml_session_t * s)
{
    ImeModuleRec *current_ime_module =
        (ImeModuleRec *) le_session_get_current_ime_module(s);
    if (current_ime_module == NULL)
        return (ENCODE_INVALID);
    return (current_ime_module->info->encoding);
}

ImeEncoding le_session_get_client_encoding(iml_session_t * s)
{
    LeSessionContextRec *le_session_context = NULL;

    le_session_context = le_session_get_session_context(s);
    if (le_session_context == NULL)
        return (ENCODE_UTF8);

    return (le_session_context->client_encoding);
}

LeResult le_session_set_client_encoding(iml_session_t * s,
                                        ImeEncoding encoding)
{
    LeSessionContextRec *le_session_context = NULL;

    le_session_context = le_session_get_session_context(s);
    if (le_session_context == NULL)
        return (LE_FAIL);

    le_session_context->client_encoding = encoding;
    return (LE_OK);
}

QjBjStatus le_session_get_qjbj_status(iml_session_t * s)
{
    LeSessionContextRec *le_session_context = NULL;

    le_session_context = le_session_get_session_context(s);
    if (le_session_context == NULL)
        return (QJBJ_HALFWIDTH);

    return (le_session_context->current_qjbj_status);
}

LeResult le_session_set_qjbj_status(iml_session_t * s,
                                    QjBjStatus qjbj_status)
{
    LeSessionContextRec *le_session_context = NULL;

    le_session_context = le_session_get_session_context(s);
    if (le_session_context == NULL)
        return (LE_FAIL);

    if (qjbj_status) {
        le_session_context->current_qjbj_status = QJBJ_FULLWIDTH;
    } else {
        le_session_context->current_qjbj_status = QJBJ_HALFWIDTH;
    }
    return (LE_OK);
}

LeResult le_session_toggle_qjbj_status(iml_session_t * s)
{
    LeSessionContextRec *le_session_context = NULL;
    QjBjStatus qjbj_status;
    ImeModuleRec *current_ime_module;
    ImeEventRec trigger;
    int result = IME_UNPROCESSED_EVENT;

    le_session_context =  le_session_get_session_context(s);
    if (le_session_context == NULL) return (LE_FAIL);
    qjbj_status = le_session_context->current_qjbj_status;

    current_ime_module = (ImeModuleRec *) le_session_get_current_ime_module(s);
    if (current_ime_module == NULL || current_ime_module->methods == NULL)
        return (LE_FAIL);

    trigger.notify_event.type = IME_EVENT_IMM_NOTIFY;
    trigger.notify_event.peer = 0;	// should not be used, it is from IMM
    trigger.notify_event.ic = (ImeInputContext) le_session_context;
    trigger.notify_event.trigger = IMM_TRIGGER_FULL_HALF_SIMBOL;
    trigger.notify_event.value = (qjbj_status == QJBJ_FULLWIDTH) ? 0 : 1;

    if (current_ime_module->methods->ImeProcessUIEvent != NULL)
        result = current_ime_module->methods-> ImeProcessUIEvent((ImeInputContext)le_session_context, &trigger);

    if (result == IME_OK || result == IME_UNPROCESSED_EVENT) {
        if (qjbj_status == QJBJ_FULLWIDTH) {
            le_session_context->current_qjbj_status = QJBJ_HALFWIDTH;
        } else {
            le_session_context->current_qjbj_status = QJBJ_FULLWIDTH;
        }
        DEBUG_printf("le_session_toggle_qjbj_status: %d\n",
                     le_session_context->current_qjbj_status);

        le_update_paletteaux_qjbj_notify(s);
        return (LE_OK);
    }
    return LE_FAIL;
}

PunctStatus le_session_get_punct_status(iml_session_t * s)
{
    LeSessionContextRec *le_session_context = le_session_get_session_context(s);
    if (le_session_context == NULL)
        return (PUNCT_ENGLISH);

    return (le_session_context->current_punct_status);
}

LeResult le_session_set_punct_status(iml_session_t * s,
                                     PunctStatus punct_status)
{
    LeSessionContextRec *le_session_context = NULL;

    le_session_context = le_session_get_session_context(s);
    if (le_session_context == NULL)
        return (LE_FAIL);

    if (punct_status) {
        le_session_context->current_punct_status = PUNCT_CHINESE;
    } else {
        le_session_context->current_punct_status = PUNCT_ENGLISH;
    }
    return (LE_OK);
}

LeResult le_session_toggle_punct_status(iml_session_t * s)
{
    LeSessionContextRec *le_session_context = NULL;
    PunctStatus punct_status;
    ImeModuleRec *current_ime_module;
    ImeEventRec trigger;
    int result = IME_UNPROCESSED_EVENT;

    le_session_context = le_session_get_session_context(s);
    if (le_session_context == NULL)
        return (LE_FAIL);
    punct_status = le_session_context->current_punct_status;

    current_ime_module =
        (ImeModuleRec *) le_session_get_current_ime_module(s);
    if (current_ime_module == NULL || current_ime_module->methods == NULL)
        return (LE_FAIL);

    trigger.notify_event.type = IME_EVENT_IMM_NOTIFY;
    trigger.notify_event.peer = 0;	// should not be used, it is from IMM
    trigger.notify_event.ic = (ImeInputContext) le_session_context;
    trigger.notify_event.trigger = IMM_TRIGGER_FULL_HALF_PUNC;
    trigger.notify_event.value = (punct_status == PUNCT_CHINESE) ? 0 : 1;

    if (current_ime_module->methods->ImeProcessUIEvent != NULL)
        result =
            current_ime_module->methods->
            ImeProcessUIEvent((ImeInputContext) le_session_context,
                              &trigger);
    if (result == IME_OK || result == IME_UNPROCESSED_EVENT) {
        if (punct_status == PUNCT_CHINESE) {
            le_session_context->current_punct_status = PUNCT_ENGLISH;
        } else {
            le_session_context->current_punct_status = PUNCT_CHINESE;
        }
        DEBUG_printf("le_session_toggle_punct_status: %d\n",
                     le_session_context->current_punct_status);

        le_update_paletteaux_punct_notify(s);
        return (LE_OK);
    }
    return LE_FAIL;
}

ConversionStatus le_session_get_conversion_status(iml_session_t * s)
{
    LeSessionContextRec *le_session_context = NULL;

    le_session_context = le_session_get_session_context(s);
    if (le_session_context == NULL)
        return (CONVERSION_OFF);

    return (le_session_context->current_conversion_status);
}

LeResult le_session_set_conversion_status(iml_session_t    *s,
                                          ConversionStatus  conversion_status)
{
    LeSessionContextRec *le_session_context = NULL;
    ImeModuleRec *current_ime_module;
    ImeEventRec trigger;

    DEBUG_printf("le_session_set_conversion_status: %d\n", conversion_status);
    le_session_context = le_session_get_session_context(s);
    if (le_session_context == NULL) {
        DEBUG_printf("le_session_set_conversion_status: create session context for 0x%x\n", s);
        le_session_context = (LeSessionContextRec *) le_session_create(s);
    }
    if (le_session_context == NULL) return (LE_FAIL);

    current_ime_module = (ImeModuleRec *) le_session_get_current_ime_module(s);
    DEBUG_printf ("le_session_set_conversion_status: current_ime_module: %p\n", current_ime_module);

    if (conversion_status == CONVERSION_OFF) {
        DEBUG_printf("le_session_set_conversion_status(): CONVERSION_OFF\n");

        le_hide_paletteaux_notify(s);
        le_session_focus_out(s);
        session_detach_ime(le_session_context);

        le_iml_conversion_off(s);

    } else {
        DEBUG_printf("le_session_set_conversion_status(): CONVERSION_ON\n");

        le_iml_conversion_on(s);

        if (current_ime_module == NULL) {
            current_ime_module = le_session_get_next_ime_module(s);
        }
        session_attach_ime(le_session_context, current_ime_module);

        le_session_focus_in(s);
        le_change_paletteaux_focus_notify(s);
    }

    return (LE_OK);
}

LeResult le_session_toggle_conversion_status(iml_session_t * s)
{
    LeSessionContextRec *le_session_context = NULL;
    ConversionStatus conversion_status;
    LeResult le_result;

    le_session_context =  le_session_get_session_context(s);
    if (le_session_context == NULL) return (LE_FAIL);

    conversion_status = le_session_context->current_conversion_status;
    DEBUG_printf("le_session_toggle_conversion_status: %d\n", ~conversion_status);
    if (conversion_status == CONVERSION_OFF) {
        le_result = le_session_set_conversion_status(s, CONVERSION_ON);
    } else {
        le_result = le_session_set_conversion_status(s, CONVERSION_OFF);
    }

    return (le_result);
}

LeResult le_session_update_status_string(iml_session_t * s,
                                         ConversionStatus
                                         conversion_status)
{
    UTFCHAR tmp_buf[128];
    UTFCHAR *tmp_ptr = tmp_buf;
    int from_len, to_left, ret;

    unsigned char *status_str = English_Status_UTF;
    ImeEncoding encoding = ENCODE_UTF8;

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

    if (conversion_status == CONVERSION_ON) {
        ImeModuleRec *current_ime_module;

        current_ime_module = le_session_get_current_ime_module(s);
        if (current_ime_module != NULL) {
/*
            encoding = current_ime_module->info->encoding;
            status_str = (unsigned char *)current_ime_module->info->name;
*/
            status_str = Chinese_Status_UTF;
        }
    }

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

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

    le_iml_status_start(s);
    le_iml_status_draw(s, tmp_buf);
    return (LE_OK);
}

LeResult le_session_set_as_desktop_current_session(iml_session_t * s)
{
    LeDesktopContextRec *le_desktop_context = NULL;

    le_desktop_context =
        (LeDesktopContextRec *) le_session_get_desktop_context(s);
    le_desktop_context_set_current_session(le_desktop_context, s);

    return (LE_OK);
}

LeResult session_proc_style_change(iml_session_t* s, int* pvstyle)
{
    LeSessionContextRec *le_session_context = le_session_get_session_context(s);
    if (le_session_context && session_get_pc_style(le_session_context)) {
        DEBUG_printf("******************************pc style changed, got it***********\n");
        *session_get_pc_style(le_session_context) = *(TImePCAuxOption*)pvstyle;
        le_change_compositeaux_option_notify(le_session_context);
    }
}

LeResult session_proc_pc_move(iml_session_t* s, int x, int y, int w, int h)
{
    LeSessionContextRec *le_session_context = le_session_get_session_context(s);
    if (le_session_context) {
        session_set_pc_position(le_session_context, x, y, w, h);
    }
}

LeResult session_proc_candidate_selection(iml_session_t*s, int idx)
{
    ImeEventRec event;
    ImeModuleRec *ime = NULL;
    LeSessionContextRec *le_session_context = le_session_get_session_context(s);

    int result = IME_UNPROCESSED_EVENT;
    if (le_session_context)
        ime = le_session_context->current_ime_module;

    if (ime && ime->methods && ime->methods->ImeProcessUIEvent) {
        event.type              = IME_EVENT_CANDI_SELECT;
        event.any_event.peer    = 0;      // should not be used, it is from IMM
        event.any_event.ic      = (ImeInputContext)le_session_context;
        event.any_event.param   = idx;

        result = ime->methods-> ImeProcessUIEvent((ImeInputContext)le_session_context, &event);
    }

    /* try to fake key_press if IME do not process it */
    if (result == IME_UNPROCESSED_EVENT && ime && ime->methods && ime->methods->ImeProcessKeyEvent) {
        char c = 0;
        ImeCandidatesRec *pcs = &le_session_context->candidates_backup;
        if (pcs->numbers != NULL) {
            c = pcs->numbers[idx];
        } else if (idx < 9) {
            c = '1' + idx;
        } else if (idx == 9) {
            c = '0';
        } else if (idx < 16) {
            c = 'A' + idx - 10;
        }
        if (c != 0) {
            ImeKeyRec key = {c, c, 0, 0};
            result = ime->methods->ImeProcessKeyEvent((ImeInputContext)le_session_context, &key);
        }
    }

    return LE_OK;
}

LeResult session_proc_candidate_page(iml_session_t* s, int pgop)
{
    ImeEventRec event;
    ImeModuleRec* ime;
    LeSessionContextRec *le_session_context = le_session_get_session_context(s);

    int result = IME_UNPROCESSED_EVENT;
    if (le_session_context)
        ime = le_session_context->current_ime_module;

    if (ime && ime->methods && ime->methods->ImeProcessUIEvent) {
        event.type              = IME_EVENT_CANDI_PAGE;
        event.any_event.peer    = 0;      // should not be used, it is from IMM
        event.any_event.ic      = (ImeInputContext)le_session_context;
        event.any_event.param   = pgop;
        result = ime->methods-> ImeProcessUIEvent((ImeInputContext)le_session_context, &event);
    }

    if (result == IME_UNPROCESSED_EVENT && ime && ime->methods && ime->methods->ImeProcessKeyEvent) {
        ImeKeyRec key = {0, 0, 0, 0};
        switch (pgop) {
        case 1: //prev page
            key.keycode = IME_VK_PAGE_UP; break;
        case 2: //next page
            key.keycode = IME_VK_PAGE_DOWN; break;
        }
        if (key.keycode != 0)
            result = ime->methods->ImeProcessKeyEvent((ImeInputContext)le_session_context, &key);
    }

    return LE_OK;
}


