/*
Copyright 1990-2001 Sun Microsystems, Inc. All Rights Reserved.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions: The above copyright notice and this
permission notice shall be included in all copies or substantial
portions of the Software.


THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE OPEN GROUP OR SUN MICROSYSTEMS, INC. BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE EVEN IF
ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.


Except as contained in this notice, the names of The Open Group and/or
Sun Microsystems, Inc. shall not be used in advertising or otherwise to
promote the sale, use or other dealings in this Software without prior
written authorization from The Open Group and/or Sun Microsystems,
Inc., as applicable.


X Window System is a trademark of The Open Group

OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF
logo, LBX, X Window System, and Xinerama are trademarks of the Open
Group. All other trademarks and registered trademarks mentioned herein
are the property of their respective owners. No right, title or
interest in or to any trademark, service mark, logo or trade name of
Sun Microsystems, Inc. or its licensors is granted.

*/
#ifdef	WIN32
#include <windows.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

#include "SunIM.h"

Bool if_sampleja_OpenIF(iml_if_t *);
Bool if_sampleja_CloseIF(iml_if_t *);
Bool if_sampleja_GetIFValue(iml_if_t *, IMArgList, int);
Bool if_sampleja_SetIFValue(iml_if_t *, IMArgList, int);
Bool if_sampleja_OpenDesktop(iml_desktop_t *, IMArgList, int);
Bool if_sampleja_CloseDesktop(iml_desktop_t *);
Bool if_sampleja_CreateSC(iml_session_t *, IMArgList, int);
Bool if_sampleja_DestroySC(iml_session_t *);
Bool if_sampleja_GetSCValue(iml_session_t *, IMArgList, int);
Bool if_sampleja_SetSCValue(iml_session_t *, IMArgList, int);
IMText *if_sampleja_ResetSC(iml_session_t *);
void if_sampleja_SetSCFocus(iml_session_t *);
void if_sampleja_UnsetSCFocus(iml_session_t *);
void if_sampleja_SendEvent(iml_session_t *, IMInputEvent * ev);

/* IF Method */
if_methods_t sampleja_methods2 = {
    if_sampleja_OpenIF,
    if_sampleja_CloseIF,
    if_sampleja_GetIFValue,
    if_sampleja_SetIFValue,
    if_sampleja_OpenDesktop,
    if_sampleja_CloseDesktop,
    if_sampleja_CreateSC,
    if_sampleja_DestroySC,
    if_sampleja_GetSCValue,
    if_sampleja_SetSCValue,
    if_sampleja_ResetSC,
    if_sampleja_SetSCFocus,
    if_sampleja_UnsetSCFocus,
    if_sampleja_SendEvent
};

UTFCHAR lename_string[] = {0x30b5, 0x30f3, 0x30d7, 0x30eb, 0x65e5, 0x672c, 0x8a9e, 0x30a8, 0x30f3, 0x30b8, 0x30f3, 0x0};
UTFCHAR jahrn_string[] = {0x65e5, 0x672c, 0x8a9e, 0x0};

static IMLEName lename = {
    "sampleja", lename_string	/* LE id, HRN */
};

static IMLocale locales[] = {
    {"ja", jahrn_string},	/* locale id, HRN */
    NULL
};

IMObjectDescriptorStruct *objects = NULL;

void init_objects();

#ifdef	WIN32
#define EXPORT extern __declspec(dllexport)

EXPORT

#endif

void
if_GetIfInfo(
    IMArgList args,
    int num_args
)
{
    int i;
    init_objects();
    for (i = 0; i < num_args; i++, args++) {
        switch (args->id) {
            case IF_VERSION:
                args->value = (IMArgVal) "1.2";
                break;
            case IF_METHOD_TABLE:
                args->value = (IMArgVal) & sampleja_methods2;
                break;
            case IF_LE_NAME:
                args->value = (IMArgVal) & lename;
                break;
            case IF_SUPPORTED_LOCALES:
                args->value = (IMArgVal) & locales;
                break;
            case IF_SUPPORTED_OBJECTS:
                args->value = (IMArgVal) objects;
                break;
            case IF_NEED_THREAD_LOCK:
                args->value = (IMArgVal) False;
                break;
            default:
                break;
            }
    }
}

Bool receive_keylist(iml_session_t *, IMKeyListEvent *);
void preedit_test(iml_session_t *);
void lookup_test(iml_session_t *);

#ifdef	test
char *class_names[] = {
    "wnn_aux_sample",
    "wnn_aux_sample",
};
#else
char *class_names[] = {
    "com.sun.iiim.sample.sampleja.SamplePanel",
    "com.sun.iiim.sample.sampleja.SampleAux"
};
#endif

enum {
    SAMPLE_AUX_PANEL = 0,
    SAMPLE_AUX_DICT = 1
};

#define	MAX_AUX	2

void aux_start(iml_session_t *, int);
void aux_draw(iml_session_t *, int, int, int *, int, UTFCHAR **);
void aux_done(iml_session_t *, int);
void receive_aux(iml_session_t *, IMAuxDrawCallbackStruct *);

void my_conversion_on(iml_session_t *);
void my_conversion_off(iml_session_t *);

void status_draw(iml_session_t *);
void preedit_draw(iml_session_t *);
void preedit_draw_reverse(iml_session_t *);
void shrink_preedit(iml_session_t *);
void expand_preedit(iml_session_t *);
void caret_move_left(iml_session_t *);
void caret_move_right(iml_session_t *);
void caret_move_home(iml_session_t *);
void caret_move_end(iml_session_t *);
void commit(iml_session_t *);
void commit_onechar(iml_session_t *, int);
void commit_partial(iml_session_t *);
void luc_draw(iml_session_t *);

void lookup_next(iml_session_t *);
void lookup_prev(iml_session_t *);

void lookup_commit(iml_session_t *, int);

void list_test(iml_session_t *);

void to_kana(iml_session_t *);
void to_hira(iml_session_t *);

IMText *make_preedit_imtext(iml_session_t *);
IMText *make_imtext(iml_session_t *, UTFCHAR *);

Bool do_convert(iml_session_t *);

void free_objects();

int UTFCHARLen(UTFCHAR *);
int UTFCHARCpy(UTFCHAR *, UTFCHAR *);
Bool UTFCHARCmp2(UTFCHAR *, char *, int);
Bool UTFCHARCmp(UTFCHAR *, UTFCHAR *);

void preedit_buf_print(iml_session_t *);

void iml_make_preedit_draw_with_chgpos_inst_test(iml_session_t *);

IMFeedbackList *create_feedback(iml_session_t * s, int size);
IMFeedbackList *create_feedback2(iml_session_t * s, int size);
IMFeedbackList *create_feedback_with_color(iml_session_t * s, int size, int feedback, int fg, int bg);
void set_feedback_private(IMFeedbackList *, int, int, int, int);
void set_feedback(IMFeedbackList *, int);
int get_feedback(IMFeedbackList *);


typedef struct henkan_table3_ {
    UTFCHAR *from;
    UTFCHAR *to;
}   henkan_table3;

/* data per desktop */
typedef struct {
    iml_session_t *auxproxy_session;
    int aux_start[3];
    int wordcount;
    henkan_table3 *userdict[100];
}   MyDataPerDesktop;

/* data per session */
typedef struct {
    int status_start;
    int preedit_start;
    int luc_start;
    int conv_on;
    
    IMText **luc_candidates;
    IMText **luc_labels;
    
    UTFCHAR *conversion_string;	/* reversed */
    UTFCHAR *preedit_string;	/* underlined */
    
    int luc_top;
    int luc_nchoices;
    int luc_current_candidate;	/* index of current candidate */
    int luc_type;		/* Clinet or IM Master */
    int max_candidates;
    
    UTFCHAR *preedit_buf;	/* preedit */
    IMFeedbackList *preedit_feedback;	/* feedback for preedit */
    int caret_pos;
    
    IMFeedbackList *luc_fbs_reverse;
    IMFeedbackList *luc_fbs_normal;
}   MyDataPerSession;

void add_dict(MyDataPerDesktop *, UTFCHAR *, UTFCHAR *);

#define	DEBUG

Bool
if_sampleja_OpenIF(
    iml_if_t * If
)
{
#ifdef	DEBUG
    printf("if_sampleja_OpenIF()\n");
    printf("	If=[%x]\n", If);
    printf("	locale=[%s]\n", If->locale);
    printf("	if_name=[%s]\n", If->if_name);
#endif
    init_objects();
    return True;
}

Bool
if_sampleja_CloseIF(
    iml_if_t * If
)
{
#ifdef	DEBUG
    printf("if_sampleja_CloseIF()\n");
    printf("	If=[%x]\n", If);
    printf("	locale=[%s]\n", If->locale);
    printf("	if_name=[%s]\n", If->if_name);
#endif
    
#ifdef	notdef
    free_objects();
#endif
    return True;
}

UTFCHAR aux_name_panel[] = {0x30b5, 0x30f3, 0x30d7, 0x30eb, 0xff21, 0xff35, 0xff38, '-', 0x30d1, 0x30cd, 0x30eb, 0};
UTFCHAR aux_name_aux[] = {0x30b5, 0x30f3, 0x30d7, 0x30eb, 0xff21, 0xff35, 0xff38, '-', 0xff21, 0xff35, 0xff38, 0};

void
free_objects()
{
    IMObjectDescriptorStruct *l = objects;
    
    while (l->leid) {
        free(l->name);
        l++;
    };
    
    free(objects);
    
    objects = NULL;
}

void
init_objects()
{
    IMObjectDescriptorStruct *l;
    objects = (IMObjectDescriptorStruct *) calloc(3, sizeof(IMObjectDescriptorStruct));
    l = objects;
    
    l->leid = "sampleja";			/* engine id */
    l->type = IM_DOWNLOADINGOBJECT_JARGUI_TYPE;	/* object type */
    l->name = aux_name_panel;			/* HRN */
    l->name_length = 11;			/* len of HRN */
    l->domain = "com.sun";			/* reversed domain */
    l->scope = "sampleja";			/* only for sampleja */

#ifdef	WIN32
    l->path = "d:\\sampleja_obj.jar";		/* path */
#else
    l->path = "/usr/lib/im/locale/ja/sampleja/sampleja_obj.jar";	/* path */
#endif
    l->signature = "";
    l->class_names = class_names;
    l->count_names = 2;

    l++;
    l->leid = "sampleja";			/* engine id */
    l->type = IM_DOWNLOADINGOBJECT_BINGUI_TYPE;	/* object type */
    l->name = aux_name_panel;			/* HRN */
    l->name_length = 11;
    l->domain = "com.sun";
    l->scope = "sampleja";			/* only for sampleja */
    l->path = "./locale/ja/sampleja/aux.so";	/* path for .so from /usr/lib/im/ */
						/* this will be
						    /usr/lib/im/locale/ja/sampleja/aux.so
						*/
    l->signature = "";
    l->basepath = NULL;		/* only for CCDEF */
    l->encoding = NULL;		/* only for CCDEF */
}

Bool
if_sampleja_GetIFValue(
    iml_if_t * If,
    IMArgList args,
    int num_args
)
{
    int i;
#ifdef	DEBUG
    printf("if_sampleja_GetIFValue()\n");
    printf("	If=[%x]\n", If);
    printf("	locale=[%s]\n", If->locale);
    printf("	if_name=[%s]\n", If->if_name);
#endif
    return True;
}

Bool
if_sampleja_SetIFValue(
    iml_if_t * If,
    IMArgList args,
    int num_args
)
{
    int i;
#ifdef	DEBUG
    printf("if_sampleja_SetIFValue()\n");
    printf("	If=[%x]\n", If);
    printf("	locale=[%s]\n", If->locale);
    printf("	if_name=[%s]\n", If->if_name);
#endif
    for (i = 0; i < num_args; i++, args++) {
        switch (args->id) {
        }
    }
    return True;
}

Bool
if_sampleja_OpenDesktop(
    iml_desktop_t * desktop,
    IMArgList args,
    int num_args
)
{
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) calloc(1, sizeof(MyDataPerDesktop));
    int i;
#ifdef	DEBUG
    printf("if_sampleja_OpenDesktop()\n");
    printf("	If=[%x]\n", desktop->If);
    printf("	desktop=[%x]\n", desktop);
    printf("	locale=[%s]\n", desktop->If->locale);
    printf("	if_name=[%s]\n", desktop->If->if_name);
    
    printf("	BASIC INFO - USER:%s\n", desktop->user_name);
    printf("	BASIC INFO - HOST:%s\n", desktop->host_name);
    printf("	BASIC INFO - DISPLAY:%s\n", desktop->display_id);
    
    for (i = 0; i < num_args; i++, args++) {
        switch (args->id) {
            case UI_USER_NAME:
                if (args->value) {
                    printf("	UI_USER_NAME=%s\n", args->value);
                }
                break;
            case UI_HOST_NAME:
                if (args->value) {
                    printf("	UI_HOST_NAME=%s\n", args->value);
                }
                break;
            case UI_DISPLAY_ID:
                if (args->value) {
                    printf("	UI_DISPLAY_ID=%s\n", args->value);
                }
                break;
            case UI_PROTOCOL_TYPE:
                if (args->value) {
                    printf("	UI_PROTOCOL_TYPE=%s\n", args->value);
                }
                break;
            case UI_CLIENT_TYPE:
                if (args->value) {
                    printf("	UI_CLIENT_TYPE=%s\n", args->value);
                }
                break;
            case UI_XSERVER_VENDOR:
                if (args->value) {
                    printf("	UI_XSERVER_VENDOR=%s\n", args->value);
                }
                break;
            case UI_OS_NAME:
                if (args->value) {
                    printf("	UI_OS_NAME=%s\n", args->value);
                }
                break;
            case UI_OS_ARCH:
                if (args->value) {
                    printf("	UI_OS_ARCH=%s\n", args->value);
                }
                break;
            case UI_OS_VERSION:
                if (args->value) {
                    printf("	UI_OS_VERSION=%s\n", args->value);
                }
                break;
            case UI_AUTH_PASSWD:
                if (args->value) {
                    printf("	UI_AUTH_PASSWD=%s\n", args->value);
                }
                break;
            }
    }
#endif
    
    
    for (i = 0; i < MAX_AUX; i++) {
        desktop_data->aux_start[i] = False;
    }
    desktop_data->auxproxy_session = 0;
    desktop->specific_data = (void *) desktop_data;
    return True;
}

Bool
if_sampleja_CloseDesktop(
    iml_desktop_t * desktop
)
{
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) desktop->specific_data;
    int i;
#ifdef	DEBUG
    printf("if_sampleja_CloseDesktop()\n");
    printf("	If=[%x]\n", desktop->If);
    printf("	desktop=[%x]\n", desktop);
    printf("	locale=[%s]\n", desktop->If->locale);
    printf("	if_name=[%s]\n", desktop->If->if_name);
    printf("	USER:%s\n", desktop->user_name);
    printf("	HOST:%s\n", desktop->host_name);
    printf("	DISPLAY:%s\n", desktop->display_id);
#endif
    for (i = 0; i < desktop_data->wordcount; i++) {
        henkan_table3 *p = desktop_data->userdict[i];
        free(p->from);
        free(p->to);
        free(p);
    }
    
    free(desktop_data);
    return True;
}

#define	BUFSIZE	256
#define	MAXCANDIDATES	40

Bool
if_sampleja_CreateSC(
    iml_session_t * s,
    IMArgList args,
    int num_args
)
{
    iml_desktop_t *desktop = s->desktop;
    IMFeedbackList *fbl;
    IMFeedback *fb;
    int i;
    MyDataPerSession *p = (MyDataPerSession *) calloc(1, sizeof(MyDataPerSession));
    p->status_start = False;
    p->luc_start = False;
    p->preedit_start = False;
    p->preedit_buf = (UTFCHAR *) calloc(1, sizeof(UTFCHAR) * BUFSIZE);
    
    p->conversion_string = (UTFCHAR *) calloc(1, sizeof(UTFCHAR) * BUFSIZE);
    p->preedit_string = (UTFCHAR *) calloc(1, sizeof(UTFCHAR) * BUFSIZE);
    p->luc_candidates = NULL;
    p->luc_labels = NULL;
    p->luc_nchoices = 36;
    p->caret_pos = -1;
    p->max_candidates = MAXCANDIDATES - 1;
    p->luc_current_candidate = 0;
    
    p->preedit_feedback = create_feedback(0, BUFSIZE);
    p->luc_fbs_reverse = create_feedback(0, BUFSIZE);
    p->luc_fbs_normal = create_feedback(0, BUFSIZE);
    
    for (i = 0; i < BUFSIZE; i++) {
        set_feedback(&p->preedit_feedback[i], IMUnderline);
        set_feedback(&p->luc_fbs_reverse[i], IMReverse);
        set_feedback(&p->luc_fbs_normal[i], IMNormal);
    }
    
#ifdef	DEBUG
    printf("if_sampleja_CreateSC()\n");
    printf("	If=[%x]\n", desktop->If);
    printf("	desktop=[%x]\n", desktop);
    printf("	locale=[%s]\n", desktop->If->locale);
    printf("	if_name=[%s]\n", desktop->If->if_name);
    
    printf("	BASIC INFO - USER:%s\n", desktop->user_name);
    printf("	BASIC INFO - HOST:%s\n", desktop->host_name);
    printf("	BASIC INFO - DISPLAY:%s\n", desktop->display_id);
    
    for (i = 0; i < num_args; i++, args++) {
        switch (args->id) {
            case UI_USER_NAME:
                if (args->value) {
                    printf("	UI_USER_NAME=%s\n", args->value);
                }
                break;
            case UI_HOST_NAME:
                if (args->value) {
                    printf("	UI_HOST_NAME=%s\n", args->value);
                }
                break;
            case UI_DISPLAY_ID:
                if (args->value) {
                    printf("	UI_DISPLAY_ID=%s\n", args->value);
                }
                break;
            case UI_PROTOCOL_TYPE:
                if (args->value) {
                    printf("	UI_PROTOCOL_TYPE=%s\n", args->value);
                }
                break;
            case UI_XSERVER_VENDOR:
                if (args->value) {
                    printf("	UI_XSERVER_VENDOR=%s\n", args->value);
                }
                break;
            case UI_CLIENT_TYPE:
                if (args->value) {
                    printf("	UI_CLIENT_TYPE=%s\n", args->value);
                }
                break;
            case UI_OS_NAME:
                if (args->value) {
                    printf("	UI_OS_NAME=%s\n", args->value);
                }
                break;
            case UI_OS_ARCH:
                if (args->value) {
                    printf("	UI_OS_ARCH=%s\n", args->value);
                }
                break;
            case UI_OS_VERSION:
                if (args->value) {
                    printf("	UI_OS_VERSION=%s\n", args->value);
                }
            case UI_AUTH_PASSWD:
                if (args->value) {
                    printf("	UI_AUTH_PASSWD=%s\n", args->value);
                }
                break;
            }
    }
#endif
    
    s->specific_data = (void *) p;
    return True;
}

Bool
if_sampleja_DestroySC(
    iml_session_t * s
)
{
    int i;
    MyDataPerSession *p = (MyDataPerSession *) s->specific_data;
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop*) s->desktop->specific_data;

    iml_session_t *j = s->desktop->session_list;
    
    if (p->preedit_buf) {
        free((char *) p->preedit_buf);
    }
    if (p->conversion_string) {
        free((char *) p->conversion_string);
    }
    if (p->preedit_string) {
        free((char *) p->preedit_string);
    }
    if (p->preedit_feedback) {
        free((char *) p->preedit_feedback);
    }
    if (p->luc_fbs_reverse) {
        free((char *) p->luc_fbs_reverse);
    }
    if (p->luc_fbs_normal) {
        free((char *) p->luc_fbs_normal);
    }
    free((char *) p);

    if(desktop_data->auxproxy_session == s){
	printf("auxproxy_session is destroyed\n");
	desktop_data->auxproxy_session = 0;
    }

#ifdef	DEBUG
    printf("if_sampleja_DestroySC(s=%x)\n", s);
    printf("	s=[%x]\n", s);
    printf("	If=[%x]\n", s->desktop->If);
    printf("	desktop=[%x]\n", s->desktop);
    printf("	locale=[%s]\n", s->desktop->If->locale);
    printf("	if_name=[%s]\n", s->desktop->If->if_name);
    printf("	USER:%s\n", s->desktop->user_name);
    printf("	HOST:%s\n", s->desktop->host_name);
    
    i = 1;
    
    i = 1;
    printf("	== Remaining Sessions START ==\n");
    while (j) {
        if (j == s) {
        } else {
            printf("           session %d = %x\n", i, j);
        }
        
        
        if (j->next) {
            j = j->next;
        } else {
            break;
        }
        i++;
    }
    printf("	== Remaining Sessions END ==\n");
#endif
    return True;
}

Bool
if_sampleja_GetSCValue(
    iml_session_t * s,
    IMArgList args,
    int num_args
)
{
    int i;
    IMArg *p = args;
    
    static int charsubset[] = {
        67,			/* LATIN */
        47,			/* HIRAGANA */
        48,			/* KATAKANA */
        71,			/* KANJI */
        0
    };
    
#ifdef	DEBUG
    printf("if_sampleja_GetSCValue(s=%x)\n", s);
    printf("	s=[%x]\n", s);
    printf("	If=[%x]\n", s->desktop->If);
    printf("	desktop=[%x]\n", s->desktop);
    printf("	locale=[%s]\n", s->desktop->If->locale);
    printf("	if_name=[%s]\n", s->desktop->If->if_name);
    printf("	USER:%s\n", s->desktop->user_name);
    printf("	HOST:%s\n", s->desktop->host_name);
#endif
    for (i = 0; i < num_args; i++, p++) {
        switch (p->id) {
            case SC_SUPPORTED_CHARACTER_SUBSETS:
                /* specify CHARACTER_SUBSETS */
                p->value = (IMArgVal) charsubset;
                break;
            default:
                break;
            }
    }
    return True;
}

UTFCHAR on_string[] = {0x65e5, 0x672c, 0x8a9e, 0x30aa, 0x30f3, 0};
UTFCHAR off_string[] = {0x65e5, 0x672c, 0x8a9e, 0x30aa, 0x30d5, 0};
UTFCHAR title_string[] = {0x9078, 0x629e, 0x30a6, 0x30a3, 0x30f3, 0x30c9, 0x30a6, 0};
UTFCHAR candidate_string[] = {0x9078, 0x629e, 0x30a6, 0x30a3, 0x30f3, 0x30c9, 0x30a6, 0};
UTFCHAR add_string[] = {0x8ffd,0x52a0,0x3057,0x307e,0x3057,0x305f,0x0};

void
my_conversion_on(
    iml_session_t * s
)
{
    iml_inst *lp;
    iml_inst *rrv = NULL;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    int aux_int_data[] = {2};
    session_data->conv_on = True;
    
    lp = s->If->m->iml_make_start_conversion_inst(s);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    
    if (session_data->preedit_start == False) {
        lp = s->If->m->iml_make_preedit_done_inst(s);
        s->If->m->iml_link_inst_tail(&rrv, lp);
        session_data->preedit_start = True;
    }
    lp = s->If->m->iml_execute(s, &rrv);
    
    status_draw(s);
}

void
my_conversion_off(
    iml_session_t * s
)
{
    iml_inst *lp;
    iml_inst *rrv = NULL;
    int aux_int_data[] = {3};
    
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    session_data->conv_on = False;
    
    /* if preedit exists, commit the string */
    commit(s);
    
    if (session_data->luc_start == True) {
        lp = s->If->m->iml_make_lookup_done_inst(s);
        s->If->m->iml_link_inst_tail(&rrv, lp);
        session_data->luc_start = False;
    }
    if (session_data->preedit_start == True) {
        lp = s->If->m->iml_make_preedit_done_inst(s);
        s->If->m->iml_link_inst_tail(&rrv, lp);
        session_data->preedit_start = False;
        session_data->caret_pos = -1;
    }
    lp = s->If->m->iml_make_end_conversion_inst(s);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    
    s->If->m->iml_execute(s, &rrv);
    
    status_draw(s);
}

Bool
if_sampleja_SetSCValue(
    iml_session_t * s,
    IMArgList args,
    int num_args
)
{
    int i;
    IMArg *p = args;
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;

#ifdef	DEBUG
    printf("if_sampleja_SetSCValue()\n");
    printf("	s=[%x]\n", s);
    printf("	If=[%x]\n", s->desktop->If);
    printf("	desktop=[%x]\n", s->desktop);
    printf("	locale=[%s]\n", s->desktop->If->locale);
    printf("	if_name=[%s]\n", s->desktop->If->if_name);
    printf("	USER:%s\n", s->desktop->user_name);
    printf("	HOST:%s\n", s->desktop->host_name);
#endif
    for (i = 0; i < num_args; i++, p++) {
        switch (p->id) {
            case SC_TRIGGER_ON_NOTIFY:
                my_conversion_on(s);
                break;
                
            case SC_TRIGGER_OFF_NOTIFY:
                my_conversion_off(s);
                break;
                
            case SC_REALIZE:
                if (!desktop_data->auxproxy_session){
                    desktop_data->auxproxy_session = s;
	 	    printf("new auxproxy_session %x count=%d\n", desktop_data->auxproxy_session, s->desktop->session_count);
                    if (getenv("DONOTSTART_AUX_AT_SC_REALIZE") == NULL) {
                        aux_start(desktop_data->auxproxy_session, SAMPLE_AUX_PANEL);
                    }
                }
                break;
            case SC_LOOKUP_LABELTYPE:
                break;
            default:
                break;
            }
    }
    return True;
}

IMText *
if_sampleja_ResetSC(
    iml_session_t * s
)
{
    int i;
    iml_inst *lp;
    IMText *p = make_preedit_imtext(s);
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    
#ifdef	DEBUG
    printf("if_sampleja_ResetSC(s=%x)\n", s);
    printf("	s=[%x]\n", s);
    printf("	If=[%x]\n", s->desktop->If);
    printf("	desktop=[%x]\n", s->desktop);
    printf("	locale=[%s]\n", s->desktop->If->locale);
    printf("	if_name=[%s]\n", s->desktop->If->if_name);
    printf("	USER:%s\n", s->desktop->user_name);
    printf("	HOST:%s\n", s->desktop->host_name);
    printf("	DISPLAY:%s\n", s->desktop->display_id);
#endif
    
    /*
    * when you return IMText for commit string, you need to call
    * iml_make_preedit_erase_inst() here.
    */
    lp = s->If->m->iml_make_preedit_erase_inst(s);
    s->If->m->iml_execute(s, &lp);
    
    /*
    * reset buffer
    */
    for (i = 0; i < BUFSIZE; i++) {
        set_feedback(&session_data->preedit_feedback[i], IMUnderline);
    }
    memset(session_data->preedit_buf, 0, sizeof(UTFCHAR) * BUFSIZE);
    memset(session_data->preedit_string, 0, sizeof(UTFCHAR) * BUFSIZE);
    memset(session_data->conversion_string, 0, sizeof(UTFCHAR) * BUFSIZE);
    session_data->caret_pos = -1;
    
    /*
    * return committed string
    */
    if (p->char_length) {
        return p;
    }
    return (IMText *) NULL;
}

void
if_sampleja_SetSCFocus(
    iml_session_t * s
)
{
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;
#ifdef	DEBUG
    printf("if_sampleja_SetSCFocus()\n");
    printf("	s=[%x]\n", s);
    printf("	If=[%x]\n", s->desktop->If);
    printf("	desktop=[%x]\n", s->desktop);
    printf("	locale=[%s]\n", s->desktop->If->locale);
    printf("	if_name=[%s]\n", s->desktop->If->if_name);
    printf("	USER:%s\n", s->desktop->user_name);
    printf("	HOST:%s\n", s->desktop->host_name);
    printf("	DISPLAY:%s\n", s->desktop->display_id);
#endif
    status_draw(s);
}

void
if_sampleja_UnsetSCFocus(
    iml_session_t * s
)
{
#ifdef	DEBUG
    printf("if_sampleja_UnsetSCFocus()\n");
    printf("	s=[%x]\n", s);
    printf("	If=[%x]\n", s->desktop->If);
    printf("	desktop=[%x]\n", s->desktop);
    printf("	locale=[%s]\n", s->desktop->If->locale);
    printf("	if_name=[%s]\n", s->desktop->If->if_name);
    printf("	USER:%s\n", s->desktop->user_name);
    printf("	HOST:%s\n", s->desktop->host_name);
    printf("	DISPLAY:%s\n", s->desktop->display_id);
#endif
    /*
    * status_draw(s);
    */
}

void
if_sampleja_SendEvent(
    iml_session_t * s,
    IMInputEvent * ev
)
{
#ifdef	DEBUG
    printf("if_sampleja_SendEvent s=%x ev=%x\n", s, ev);
#endif
    if (ev) {
        if (ev->type == IM_EventKeyList) {
            if (receive_keylist(s, (IMKeyListEvent *) ev) == False) {
                IMKeyListEvent *keylist = (IMKeyListEvent *) ev;
                iml_inst *lp = s->If->m->iml_make_keypress_inst(s, (IMKeyEventStruct *) keylist->keylist);
                s->If->m->iml_execute(s, &lp);
            }
        } else if (ev->type == IM_EventAux) {
            IMAuxEvent *aux = (IMAuxEvent *) ev;
            IMAuxDrawCallbackStruct *data = aux->aux;
            receive_aux(s, data);
        } else if (ev->type == IM_EventString) {
            /* String Event */
        } else if (ev->type == IM_EventText) {
            /* Text Event */
        }
    }
}

typedef struct henkan_table_ {
    int contents;
    int key;
    int result;
}   henkan_table;

henkan_table htable[] = {
    {0, '.', 0x3002},
    {0, ',', 0x3001},
    {0, '-', 0x30fc},
    {0, 'a', 0x3042},
    {0, 'i', 0x3044},
    {0, 'u', 0x3046},
    {0, 'e', 0x3048},
    {0, 'o', 0x304a},
    {'k', 'a', 0x304b},
    {'k', 'i', 0x304d},
    {'k', 'u', 0x304f},
    {'k', 'e', 0x3051},
    {'k', 'o', 0x3053},
    {'n', 'a', 0x306a},
    {'n', 'i', 0x306b},
    {'n', 'u', 0x306c},
    {'n', 'e', 0x306d},
    {'n', 'o', 0x306e},
    {'h', 'a', 0x306f},
    {'h', 'i', 0x3072},
    {'h', 'u', 0x3075},
    {'h', 'e', 0x3078},
    {'h', 'o', 0x307b},
    {'m', 'a', 0x307e},
    {'m', 'i', 0x307f},
    {'m', 'u', 0x3080},
    {'m', 'e', 0x3081},
    {'m', 'o', 0x3082},
    {'y', 'a', 0x3084},
    {'y', 'i', 0x3044},
    {'y', 'u', 0x3086},
    {'y', 'e', 0x3048},
    {'y', 'o', 0x3088},
    {'r', 'a', 0x3089},
    {'r', 'i', 0x308a},
    {'r', 'u', 0x308b},
    {'r', 'e', 0x308c},
    {'r', 'o', 0x308d},
    {'t', 'a', 0x305f},
    {'t', 'i', 0x3061},
    {'t', 'u', 0x3064},
    {'t', 'e', 0x3066},
    {'t', 'o', 0x3068},
    {'s', 'a', 0x3055},
    {'s', 'i', 0x3057},
    {'s', 'u', 0x3059},
    {'s', 'e', 0x305b},
    {'s', 'o', 0x305d},
    {'n', 'n', 0x3093},
    {'d', 'a', 0x3060},
    {'d', 'i', 0x3062},
    {'d', 'u', 0x3065},
    {'d', 'e', 0x3067},
    {'d', 'o', 0x3069},
    {'g', 'a', 0x304c},
    {'g', 'i', 0x304e},
    {'g', 'u', 0x3050},
    {'g', 'e', 0x3052},
    {'g', 'o', 0x3054},
    {'z', 'a', 0x3056},
    {'z', 'i', 0x3058},
    {'z', 'u', 0x305a},
    {'z', 'e', 0x305c},
    {'z', 'o', 0x305e},
    {'p', 'a', 0x3071},
    {'p', 'i', 0x3074},
    {'p', 'u', 0x3077},
    {'p', 'e', 0x307a},
    {'p', 'o', 0x307d},
    {'b', 'a', 0x3070},
    {'b', 'i', 0x3073},
    {'b', 'u', 0x3076},
    {'b', 'e', 0x3079},
    {'b', 'o', 0x307c},
    {'j', 'i', 0x3058},
    {'w', 'a', 0x308f},
    {'w', 'o', 0x3092},
    {'l', 'a', 0x3041},
    {'l', 'i', 0x3043},
    {'l', 'u', 0x3045},
    {'l', 'e', 0x3047},
    {'l', 'o', 0x3049},
    {0, 0, 0}
};

typedef struct henkan_table2_ {
    char contents[3];
    int key;
    int result1;
    int result2;
}   henkan_table2;

henkan_table2 htable2[] = {
    {"ky", 'a', 0x304d, 0x3083},
    {"ky", 'u', 0x304d, 0x3085},
    {"ky", 'o', 0x304d, 0x3087},
    
    {"sy", 'a', 0x3057, 0x3083},
    {"sy", 'u', 0x3057, 0x3085},
    {"sy", 'o', 0x3057, 0x3087},
    {"sh", 'a', 0x3057, 0x3083},
    {"sh", 'u', 0x3057, 0x3085},
    {"sh", 'o', 0x3057, 0x3087},
    
    {"jy", 'a', 0x3058, 0x3083},
    {"jy", 'u', 0x3058, 0x3085},
    {"jy", 'o', 0x3058, 0x3087},
    
    {"gy", 'a', 0x304e, 0x3083},
    {"gy", 'u', 0x304e, 0x3085},
    {"gy", 'o', 0x304e, 0x3087},
    
    {"ch", 'a', 0x3061, 0x3083},
    {"ch", 'u', 0x3061, 0x3085},
    {"ch", 'o', 0x3061, 0x3087},
    
    {"dh", 'a', 0x3062, 0x3083},
    {"dh", 'u', 0x3062, 0x3085},
    {"dh", 'o', 0x3062, 0x3087},
    {"dy", 'a', 0x3062, 0x3083},
    {"dy", 'u', 0x3062, 0x3085},
    {"dy", 'o', 0x3062, 0x3087},
    
    {"ny", 'a', 0x306b, 0x3083},
    {"ny", 'u', 0x306b, 0x3085},
    {"ny", 'o', 0x306b, 0x3087},
    
    {"hy", 'a', 0x3072, 0x3083},
    {"hy", 'u', 0x3072, 0x3085},
    {"hy", 'o', 0x3072, 0x3087},
    
    {"by", 'a', 0x3073, 0x3083},
    {"by", 'u', 0x3073, 0x3085},
    {"by", 'o', 0x3073, 0x3087},
    
    {"py", 'a', 0x3074, 0x3083},
    {"py", 'u', 0x3074, 0x3085},
    {"py", 'o', 0x3074, 0x3087},
    
    {"my", 'a', 0x307f, 0x3083},
    {"my", 'u', 0x307f, 0x3085},
    {"my", 'o', 0x307f, 0x3087},
    
    {"ry", 'a', 0x308a, 0x3083},
    {"ry", 'u', 0x308a, 0x3085},
    {"ry", 'o', 0x308a, 0x3087},
    
    {"tt", 'e', 0x3063, 0x3066},
    {"tt", 'a', 0x3063, 0x305f},
    {(char) NULL, 0, 0, 0}
};

henkan_table2 htable2_1[] = {
    {"j", 'a', 0x3058, 0x3083},
    {"j", 'u', 0x3058, 0x3085},
    {"j", 'o', 0x3058, 0x3087},
    {(char) NULL, 0, 0, 0}
};

int hira_table[] = {
    0x3041, 0x3042, 0x3043, 0x3044, 0x3045, 0x3046, 0x3047, 0x3048, 0x3049, 0x304a, 0x304b, 0x304c, 0x304d, 0x304e, 0x304f,
    0x3050, 0x3051, 0x3052, 0x3053, 0x3054, 0x3055, 0x3056, 0x3057, 0x3058, 0x3059, 0x305a, 0x305b, 0x305c, 0x305d, 0x305e, 0x305f,
    0x3060, 0x3061, 0x3062, 0x3063, 0x3064, 0x3065, 0x3066, 0x3067, 0x3068, 0x3069, 0x306a, 0x306b, 0x306c, 0x306d, 0x306e, 0x306f,
    0x3070, 0x3071, 0x3072, 0x3073, 0x3074, 0x3075, 0x3076, 0x3077, 0x3078, 0x3079, 0x307a, 0x307b, 0x307c, 0x307d, 0x307e, 0x307f,
    0x3080, 0x3081, 0x3082, 0x3083, 0x3084, 0x3085, 0x3086, 0x3087, 0x3088, 0x3089, 0x308a, 0x308b, 0x308c, 0x308d, 0x308e, 0x308f,
    0x3090, 0x3091, 0x3092, 0x3093, 0x0
};

int kana_table[] = {
    0x30a1, 0x30a2, 0x30a3, 0x30a4, 0x30a5, 0x30a6, 0x30a7, 0x30a8, 0x30a9, 0x30aa, 0x30ab, 0x30ac, 0x30ad, 0x30ae, 0x30af,
    0x30b0, 0x30b1, 0x30b2, 0x30b3, 0x30b4, 0x30b5, 0x30b6, 0x30b7, 0x30b8, 0x30b9, 0x30ba, 0x30bb, 0x30bc, 0x30bd, 0x30be, 0x30bf,
    0x30c0, 0x30c1, 0x30c2, 0x30c3, 0x30c4, 0x30c5, 0x30c6, 0x30c7, 0x30c8, 0x30c9, 0x30ca, 0x30cb, 0x30cc, 0x30cd, 0x30ce, 0x30cf,
    0x30d0, 0x30d1, 0x30d2, 0x30d3, 0x30d4, 0x30d5, 0x30d6, 0x30d7, 0x30d8, 0x30d9, 0x30da, 0x30db, 0x30dc, 0x30dd, 0x30de, 0x30df,
    0x30e0, 0x30e1, 0x30e2, 0x30e3, 0x30e4, 0x30e5, 0x30e6, 0x30e7, 0x30e8, 0x30e9, 0x30ea, 0x30eb, 0x30ec, 0x30ed, 0x30ee, 0x30ef,
    0x30f0, 0x30f1, 0x30f2, 0x30f3, 0x30f4, 0x30f5, 0x30f6, 0x0,
};


/*
 * UTFCHAR naoyuki_string[] = {0x3044,0x3057,0x3080,0x3089}
 */

Bool
receive_keylist(
    iml_session_t * s,
    IMKeyListEvent * keylist
)
{
    int i;
    int m;
    int j;
    IMKeyEventStruct *k = (IMKeyEventStruct *) keylist->keylist;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;
    i = UTFCHARLen(session_data->preedit_buf);

    printf("iml_session_t() keycode=%x,keychar=%x, state=%x\n", k->keyCode, k->keyChar, k->modifier);
    
    if (session_data->luc_start == True) {
        int index = 0;
        if (session_data->luc_type == IMIsMaster) {
            if ('1' <= k->keyChar && '9' >= k->keyChar) {
                index = k->keyChar - '1';
            } else if ('A' <= k->keyChar && 'Z' >= k->keyChar) {
                index = k->keyChar - 'A' + 9;
            } else if ('a' <= k->keyChar && 'z' >= k->keyChar) {
                index = k->keyChar - 'a' + 35;
            } else if (k->modifier & IM_CTRL_MASK) {
                if (k->keyCode == IM_VK_N) {
                    lookup_next(s);
                    lookup_test(s);
                } else if (k->keyCode == IM_VK_P) {
                    lookup_prev(s);
                    lookup_test(s);
                }
                return True;
            } else if (k->keyCode == IM_VK_ENTER || k->keyCode == IM_VK_ACCEPT) {
                index = session_data->luc_current_candidate;
            } else if (k->keyCode == IM_VK_SPACE || k->keyCode == IM_VK_CONVERT) {
                session_data->luc_current_candidate++;
                if (session_data->luc_current_candidate == session_data->luc_nchoices) {
                    lookup_next(s);
                }
                if (session_data->luc_top + session_data->luc_current_candidate > session_data->max_candidates) {
                    lookup_next(s);
                }
                lookup_test(s);
                return True;
            } else {
                return True;
            }
            if (index >= session_data->luc_nchoices) {
                return True;
            }
            lookup_commit(s, index);
        }
        return True;
    }
    if (k->modifier & IM_CTRL_MASK) {
        switch (k->keyCode) {
            case IM_VK_SPACE:
            case IM_VK_SLASH:
                my_conversion_off(s);
                return True;
                break;
            case IM_VK_I:
                if (i > 0) {
                    to_kana(s);
                    return True;
                } else {
                    return False;
                }
                break;
            case IM_VK_U:
                if (i > 0) {
                    to_hira(s);
                    return True;
                } else {
                    return False;
                }
                break;
            case IM_VK_LEFT:
                if (i > 0) {
                    caret_move_left(s);
                    return True;
                } else {
                    return False;
                }
                break;
            case IM_VK_RIGHT:
                if (i > 0) {
                    caret_move_right(s);
                    return True;
                } else {
                    return False;
                }
                break;
            case IM_VK_L:
                if (i > 0) {
                    expand_preedit(s);
                    return True;
                } else {
                    return False;
                }
                break;
            case IM_VK_K:
                if (i > 0) {
                    shrink_preedit(s);
                    return True;
                } else {
                    return False;
                }
                break;
            case IM_VK_N:
                if (i > 0) {
                    commit_partial(s);
                    return True;
                } else {
                    return False;
                }
                break;
            case IM_VK_J:
                if (i > 4) {
                    iml_make_preedit_draw_with_chgpos_inst_test(s);
                    return True;
                } else {
                    return False;
                }
            case IM_VK_Q:
                aux_start(desktop_data->auxproxy_session, SAMPLE_AUX_PANEL);
                break;
            case IM_VK_W:
                {
                    
                    int aux_int_data[] = {3};
                    
                    static UTFCHAR aux_candidate1[] = {'1', ' ', 0x304b, 0x3093, 0x3058, 0x0};
                    static UTFCHAR aux_candidate2[] = {'2', ' ', 0x52d8, 0x6b21, 0x0};
                    static UTFCHAR aux_candidate3[] = {'3', ' ', 0x611f, 0x3058, 0x0};
                    static UTFCHAR aux_candidate4[] = {'4', ' ', 0x6f22, 0x5b57, 0x0};
                    static UTFCHAR aux_candidate5[] = {'5', ' ', 0x76e3, 0x4e8b, 0x0};
                    static UTFCHAR aux_candidate6[] = {'6', ' ', 0x5b8c, 0x6cbb, 0x0};
                    static UTFCHAR aux_candidate7[] = {'7', ' ', 0x5e79, 0x4e8b, 0x0};
                    static UTFCHAR aux_candidate8[] = {'8', ' ', 0x5bdb, 0x4e8c, 0x0};
                    static UTFCHAR aux_candidate9[] = {'9', ' ', 0x5bdb, 0x53f8, 0x0};
                    
                    UTFCHAR *aux_string_data[] = {
                        aux_candidate1,
                        aux_candidate2,
                        aux_candidate3,
                        aux_candidate4,
                        aux_candidate5,
                        aux_candidate6,
                        aux_candidate7,
                        aux_candidate8,
                        aux_candidate9,
                    };
                    
                    if (desktop_data->aux_start[SAMPLE_AUX_DICT] == False) {
                        aux_start(s, SAMPLE_AUX_DICT);
                    }
                    aux_draw(s, SAMPLE_AUX_DICT, 1, aux_int_data, 9, aux_string_data);
                }
                break;
            case IM_VK_E:
                {
                    int aux_int_data[] = {1};
                    UTFCHAR *aux_string_data[] = {candidate_string};
                    if (desktop_data->aux_start[SAMPLE_AUX_PANEL] == False) {
                        aux_start(desktop_data->auxproxy_session, SAMPLE_AUX_PANEL);
                    }
                    aux_draw(desktop_data->auxproxy_session, SAMPLE_AUX_PANEL, 1, aux_int_data, 1, aux_string_data);
                }
                break;
            case IM_VK_R:
                list_test(s);
                break;
            default:
                return False;
                break;
            }
        return True;
    }
    if (k->keyCode == IM_VK_KANJI) {
	my_conversion_off(s);
    } else if (k->keyCode == IM_VK_HOME) {
        if (i > 0) {
            caret_move_home(s);
            return True;
        } else {
            return False;
        }
    } else if (k->keyCode == IM_VK_END) {
        if (i > 0) {
            caret_move_end(s);
            return True;
        } else {
            return False;
        }
    } else if (k->keyCode == IM_VK_ENTER || k->keyCode == IM_VK_ACCEPT) {
        if (i > 0) {
            commit(s);
            return True;
        } else {
            return False;
        }
    } else if (k->keyCode == IM_VK_BACK_SPACE) {
        if (i > 0) {
            session_data->preedit_buf[i - 1] = 0;
            preedit_draw(s);
            return True;
        } else {
            return False;
        }
    } else if (k->keyCode == IM_VK_RIGHT) {
        if (i > 0) {
            expand_preedit(s);
            return True;
        } else {
            return False;
        }
    } else if (k->keyCode == IM_VK_LEFT) {
        if (i > 0) {
            shrink_preedit(s);
            return True;
        } else {
            return False;
        }
    } else if (k->keyCode == IM_VK_DOWN) {
        if (i > 0) {
            commit_partial(s);
            return True;
        } else {
            return False;
        }
    } else if (k->keyCode == IM_VK_SPACE ||
      k->keyCode == IM_VK_CONVERT) {
        if (i > 0) {
            if (do_convert(s) == True) {
                return True;
            }
            preedit_draw_reverse(s);
            return True;
        } else {
            return False;
        }
    } else if (k->keyChar >= '!' && k->keyChar <= '~') {
        m = 0;
        if (i > 1) {
            char last2[3];
            last2[0] = (char) session_data->preedit_buf[i - 2];
            last2[1] = (char) session_data->preedit_buf[i - 1];
            last2[2] = '\0';
#ifdef	notdef
            printf("last0=%x last1=%x keychar=%x\n", last2[0], last2[1], k->keyChar);
            printf("%s\n", last2);
#endif
            if (last2[0] <= 'z' && last2[1] <= 'z') {
                for (j = 0; htable2[j].key; j++) {
                    if (htable2[j].key == k->keyChar &&
                      !strcmp(htable2[j].contents, last2)) {
                        session_data->preedit_buf[i - 2] = htable2[j].result1;
                        session_data->preedit_buf[i - 1] = htable2[j].result2;
                        session_data->preedit_buf[i] = 0;
                        set_feedback(&session_data->preedit_feedback[i - 2], IMUnderline);
                        set_feedback(&session_data->preedit_feedback[i - 1], IMUnderline);
                        m = 1;
                        break;
                    }
                }
            }
        }
        if (m == 0) {
            if (i > 0) {
                int last = session_data->preedit_buf[i - 1];
                if (last > 'z') {
                    last = 0;
                }
                for (j = 0; htable2_1[j].key; j++) {
                    if (htable2_1[j].key == k->keyChar &&
                      htable2_1[j].contents[0] == last) {
                        session_data->preedit_buf[i - 1] = htable2_1[j].result1;
                        session_data->preedit_buf[i] = htable2_1[j].result2;
                        session_data->preedit_buf[i + 1] = 0;
                        set_feedback(&session_data->preedit_feedback[i - 1], IMUnderline);
                        set_feedback(&session_data->preedit_feedback[i], IMUnderline);
                        m = 1;
                        break;
                    }
                }
                if (m == 0) {
                    for (j = 0; htable[j].key; j++) {
                        if (htable[j].key == k->keyChar &&
                          htable[j].contents == last) {
                            if (last == 0) {
                                session_data->preedit_buf[i] = htable[j].result;
                                session_data->preedit_buf[i + 1] = 0;
                                set_feedback(&session_data->preedit_feedback[i], IMUnderline);
                            } else {
                                session_data->preedit_buf[i - 1] = htable[j].result;
                                session_data->preedit_buf[i] = 0;
                                set_feedback(&session_data->preedit_feedback[i - 1], IMUnderline);
                            }
                            m = 1;
                            break;
                        }
                    }
                }
            } else {
                /* i == 0 */
                for (j = 0; htable[j].key; j++) {
                    if (htable[j].key == k->keyChar &&
                      htable[j].contents == 0) {
                        session_data->preedit_buf[0] = htable[j].result;
                        session_data->preedit_buf[1] = 0;
                        set_feedback(&session_data->preedit_feedback[0], IMUnderline);
                        m = 1;
                        break;
                    }
                }
            }
        }
        if (m == 0) {
            session_data->preedit_buf[i] = k->keyChar;
            session_data->preedit_buf[i + 1] = 0;
            set_feedback(&session_data->preedit_feedback[i], IMUnderline);
        }
    } else {
        return False;
    }
    
#ifdef	DEBUG
    printf("	keycode=%x,keychar=%x, state=%x\n", k->keyCode, k->keyChar, k->modifier);
#endif
    
    preedit_draw(s);
    
#ifdef	notdef
    IMOperation *op;
    for (i = 0, k = (IMKeyEventStruct *) keylist->keylist; i < keylist->n_key; i++, k++) {
        printf("k->keyCode=%x\n", k->keyCode);
        printf("k->keyChar=%x\n", k->keyChar);
        printf("k->modifier=%x\n", k->modifier);
        if (keylist->operation_list) {
            for (i = 0, op = (IMOperation *) keylist->operation_list; i < keylist->n_operation; i++, op++) {
                printf("op->id=%d\n", op->id);
                printf("op->length=%d\n", op->length);
                printf("op->value=[%s]\n", op->value);
            }
        }
    }
#endif
    return True;
}

UTFCHARCat(
    UTFCHAR * dest,
    UTFCHAR * str1,
    UTFCHAR * str2
)
{
    int i;
    for (i = 0; *str1; i++) {
        *dest++ = *str1++;
    }
    for (i = 0; *str2; i++) {
        *dest++ = *str2++;
    }
    *dest = 0;
    return i;
}

Bool
UTFCHARCmp(
    UTFCHAR * s1,
    UTFCHAR * s2
)
{
    int i;
    if (UTFCHARLen(s1) != UTFCHARLen(s2)) {
        return False;
    }
    for (i = 0; i < UTFCHARLen(s1); i++) {
        if (s1[i] != s2[i]) {
            return False;
        }
    }
    return True;
}

Bool
UTFCHARCmp2(
    UTFCHAR * s1,
    char *s2,
    int len
)
{
    int i;
    for (i = 0; i < len; i++) {
        if (s2[i] == 0) {
            return False;
        }
        if (s1[i] != s2[i]) {
            return False;
        }
    }
    if (s2[i] != 0) {
        return False;
    }
    return True;
}

int
UTFCHARCpy(
    UTFCHAR * dest,
    UTFCHAR * original
)
{
    int i;
    for (i = 0; *original; i++) {
        *dest++ = *original++;
    }
    *dest = 0;
    return i;
}

int
UTFCHARLen(
    UTFCHAR * p
)
{
    int i;
    for (i = 0; *p; i++)
    p++;
    return i;
}

void
to_hira(
    iml_session_t * s
)
{
    int i, j;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    
    for (i = 0; session_data->preedit_buf[i]; i++) {
        int hira = session_data->preedit_buf[i];
        for (j = 0; kana_table[j]; j++) {
            if (session_data->preedit_buf[i] == kana_table[j]) {
                hira = hira_table[j];
            }
        }
        session_data->preedit_buf[i] = hira;
    }
    
    preedit_draw(s);
}

void
to_kana(
    iml_session_t * s
)
{
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    
    int i, j;
    for (i = 0; session_data->preedit_buf[i]; i++) {
        int kana = session_data->preedit_buf[i];
        for (j = 0; hira_table[j]; j++) {
            if (session_data->preedit_buf[i] == hira_table[j]) {
                kana = kana_table[j];
            }
        }
        session_data->preedit_buf[i] = kana;
    }
    
    preedit_draw(s);
}

void
commit_onechar(
    iml_session_t * s,
    int achar
)
{
    int i;
    iml_inst *lp;
    IMFeedbackList *fbl;
    IMFeedback *fb;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    
    IMText *p = (IMText *) s->If->m->iml_new(s, sizeof(IMText));
    memset(p, 0, sizeof(IMText));
    p->encoding = UTF16_CODESET;
    p->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR) * 2);
    p->text.utf_chars[0] = achar;
    p->text.utf_chars[1] = 0;
    p->char_length = 1;
    p->feedback = create_feedback(s, p->char_length);
    lp = s->If->m->iml_make_commit_inst(s, p);
    s->If->m->iml_execute(s, &lp);
}

void
commit_partial(
    iml_session_t * s
)
{
    int i;
    int len;
    int last_reverse = -1;
    iml_inst *lp;
    iml_inst *rrv = NULL;
    IMText *p;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    len = UTFCHARLen(session_data->preedit_buf);
    
    for (i = 0; i < len; i++) {
        if (get_feedback(&session_data->preedit_feedback[i]) == IMReverse) {
            last_reverse = i;
        }
    }
    
    if (last_reverse == -1 || (last_reverse + 1) == len) {
        /* commit whole preedit */
        commit(s);
        return;
    }
    p = (IMText *) s->If->m->iml_new(s, sizeof(IMText));
    memset(p, 0, sizeof(IMText));
    p->encoding = UTF16_CODESET;
    p->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR) * (last_reverse + 1));
    for (i = 0; i <= last_reverse; i++) {
        p->text.utf_chars[i] = session_data->preedit_buf[i];
    }
    
    p->char_length = last_reverse + 1;
    p->feedback = create_feedback(s, p->char_length);
    
    for (i = (last_reverse + 1);; i++) {
        session_data->preedit_buf[i - (last_reverse + 1)] = session_data->preedit_buf[i];
        set_feedback(&session_data->preedit_feedback[i - (last_reverse + 1)],
            get_feedback(&session_data->preedit_feedback[i]));
        if (session_data->preedit_buf[i - (last_reverse + 1)] == 0) {
            break;
        }
    }
    
    /* erase first */
    lp = s->If->m->iml_make_preedit_erase_inst(s);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    
    lp = s->If->m->iml_make_commit_inst(s, p);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    
    s->If->m->iml_execute(s, &rrv);
    
    preedit_draw(s);
    
    session_data->caret_pos = -1;
}

void
commit(
    iml_session_t * s
)
{
    int len, i;
    iml_inst *lp;
    iml_inst *rrv = NULL;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    IMText *p = (IMText *) s->If->m->iml_new(s, sizeof(IMText));
    memset(p, 0, sizeof(IMText));
    p->encoding = UTF16_CODESET;
    
    len = UTFCHARLen(session_data->preedit_buf);
    
    if (len == 0) {
        /* no preedit */
        return;
    }
    lp = s->If->m->iml_make_preedit_erase_inst(s);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    
    p->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR) * (len + 1));
    UTFCHARCpy(p->text.utf_chars, session_data->preedit_buf);
    p->char_length = len;
    p->feedback = create_feedback(s, p->char_length);
    
    lp = s->If->m->iml_make_commit_inst(s, p);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    s->If->m->iml_execute(s, &rrv);
    
    for (i = 0; i < BUFSIZE; i++) {
        set_feedback(&session_data->preedit_feedback[i], IMUnderline);
    }
    
    memset(session_data->preedit_buf, 0, sizeof(UTFCHAR) * BUFSIZE);
    memset(session_data->preedit_string, 0, sizeof(UTFCHAR) * BUFSIZE);
    memset(session_data->conversion_string, 0, sizeof(UTFCHAR) * BUFSIZE);
    
    session_data->caret_pos = -1;
}

void
list_test(iml_session_t * s)
{
    iml_session_t *p = s->desktop->session_list;
    while (p) {
        iml_inst *lp = p->If->m->iml_make_status_draw_inst(p, make_imtext(p, candidate_string));
        p->If->m->iml_execute(p, &lp);
        
        if (p->next)
            p = p->next;
        else
        break;
    }
}

void
status_draw(
    iml_session_t * s
)
{
    int len, i;
    iml_inst *lp;
    iml_inst *rrv = NULL;
    UTFCHAR *str;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;
    IMText *p = (IMText *) s->If->m->iml_new(s, sizeof(IMText));

    int aux_int_data_convon[] = {2};
    int aux_int_data_convoff[] = {3};

    memset(p, 0, sizeof(IMText));
    p->encoding = UTF16_CODESET;
    
    if (session_data->conv_on) {
        str = on_string;
        aux_draw(desktop_data->auxproxy_session, SAMPLE_AUX_PANEL, 1, aux_int_data_convon, 0, NULL);
    } else {
        str = off_string;
        aux_draw(desktop_data->auxproxy_session, SAMPLE_AUX_PANEL, 1, aux_int_data_convoff, 0, NULL);
    }
    
    len = UTFCHARLen(str);
    p->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR) * (len + 1));
    
    UTFCHARCpy(p->text.utf_chars, str);
    
    p->char_length = len;
    
#ifdef	USE_COLOR_FEEDBACK
        if (0) {
            /* specified both fg and bg */
            p->feedback = create_feedback_with_color(s, p->char_length,
                IMNormal,
                IM_RGB_COLOR(255, 0, 0),
            IM_RGB_COLOR(255, 192, 203));
        }
        if (0) {
            /* specified only bg */
            p->feedback = create_feedback_with_color(s, p->char_length,
                IMNormal,
                -1,
                IM_RGB_COLOR(255, 192, 203));
        }
        if (0) {
            /* specified only fg */
            p->feedback = create_feedback_with_color(s, p->char_length,
                IMNormal,
                IM_RGB_COLOR(255, 0, 0),
            -1);
        }
        p->feedback = create_feedback(s, p->char_length);
        for (i = 0; i < 3; i++) {
            set_feedback_private(&p->feedback[i],
                IMNormal,
                IM_RGB_COLOR(255, 0, 0),
            IM_RGB_COLOR(255, 192, 203),
            -1);
        }
        if (session_data->conv_on) {
            for (i = 3; i < 5; i++) {
                set_feedback_private(&p->feedback[i],
                    IMNormal,
                    IM_RGB_COLOR(0, 0, 0),
                IM_RGB_COLOR(255, 255, 0),
                -1);
            }
            
        } else {
            for (i = 3; i < 5; i++) {
                set_feedback_private(&p->feedback[i],
                    IMNormal,
                    IM_RGB_COLOR(0, 0, 0),
                IM_RGB_COLOR(192, 192, 192),
                -1);
            }
            
        }
#else
        p->feedback = create_feedback(s, p->char_length);
#endif
    
    if (session_data->status_start == False) {
        lp = s->If->m->iml_make_status_start_inst(s);
        s->If->m->iml_link_inst_tail(&rrv, lp);
        session_data->status_start = True;
    }
    lp = s->If->m->iml_make_status_draw_inst(s, p);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    
    s->If->m->iml_execute(s, &rrv);
}

/*
 * test for iml_make_preedit_caret_inst()
 */
void
caret_move_right(
    iml_session_t * s
)
{
    iml_inst *lp;
    int len;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    len = UTFCHARLen(session_data->preedit_buf);
    if (session_data->caret_pos == -1) {
        session_data->caret_pos = len;
    }
    session_data->caret_pos++;
    
    if (session_data->caret_pos > len) {
        session_data->caret_pos = 0;
    }
#ifdef	notdef
    printf("iml_make_preedit_caret_inst()\n");
    printf("	caret_pos=%d\n", session_data->caret_pos);
#endif
    
    lp = s->If->m->iml_make_preedit_caret_inst(s, session_data->caret_pos);
    s->If->m->iml_execute(s, &lp);
}

/*
 * test for iml_make_preedit_caret_inst()
 */

void
caret_move_left(
    iml_session_t * s
)
{
    int len;
    iml_inst *lp;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    len = UTFCHARLen(session_data->preedit_buf);
    if (session_data->caret_pos == -1) {
        session_data->caret_pos = len;
    }
    session_data->caret_pos--;
    if (session_data->caret_pos == -1) {
        session_data->caret_pos = len;
    }
#ifdef	notdef
    printf("iml_make_preedit_caret_inst()\n");
    printf("	caret_pos=%d\n", session_data->caret_pos);
#endif
    lp = s->If->m->iml_make_preedit_caret_inst(s, session_data->caret_pos);
    s->If->m->iml_execute(s, &lp);
}

/*
 * test for iml_make_preedit_caret_inst()
 */
void
caret_move_home(
    iml_session_t * s
)
{
    iml_inst *lp;
    int len;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    len = UTFCHARLen(session_data->preedit_buf);
    
    session_data->caret_pos = 0;
    
#ifdef	notdef
    printf("iml_make_preedit_caret_inst()\n");
    printf("	caret_pos=%d\n", session_data->caret_pos);
#endif
    
    lp = s->If->m->iml_make_preedit_caret_inst(s, session_data->caret_pos);
    s->If->m->iml_execute(s, &lp);
}

/*
 * test for iml_make_preedit_caret_inst()
 */

void
caret_move_end(
    iml_session_t * s
)
{
    int len;
    iml_inst *lp;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    len = UTFCHARLen(session_data->preedit_buf);
    session_data->caret_pos = len;
    
#ifdef	notdef
    printf("iml_make_preedit_caret_inst()\n");
    printf("	caret_pos=%d\n", session_data->caret_pos);
#endif
    
    lp = s->If->m->iml_make_preedit_caret_inst(s, session_data->caret_pos);
    s->If->m->iml_execute(s, &lp);
}

void
expand_preedit(
    iml_session_t * s
)
{
    int i, len;
    int first_underline = -1;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    len = UTFCHARLen(session_data->preedit_buf);
    
    memset(session_data->preedit_string, 0, sizeof(UTFCHAR) * BUFSIZE);
    memset(session_data->conversion_string, 0, sizeof(UTFCHAR) * BUFSIZE);
    
    for (i = 0; i < len; i++) {
        if (get_feedback(&session_data->preedit_feedback[i]) == IMUnderline) {
            first_underline = i;
            break;
        }
    }
    
    if (first_underline != -1) {
        set_feedback(&session_data->preedit_feedback[first_underline], IMReverse);
        preedit_draw(s);
    }
}


void
shrink_preedit(
    iml_session_t * s
)
{
    int i, len;
    int last_reverse = -1;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    len = UTFCHARLen(session_data->preedit_buf);
    
    memset(session_data->preedit_string, 0, sizeof(UTFCHAR) * BUFSIZE);
    memset(session_data->conversion_string, 0, sizeof(UTFCHAR) * BUFSIZE);
    
    for (i = 0; i < len; i++) {
        if (get_feedback(&session_data->preedit_feedback[i]) == IMReverse) {
            last_reverse = i;
        }
    }
    
    if (last_reverse != -1) {
        set_feedback(&session_data->preedit_feedback[last_reverse], IMUnderline);
        preedit_draw(s);
    }
}

void
preedit_draw_reverse(
    iml_session_t * s
)
{
    int i, len;
    int last_reverse = -1;
    int buf[BUFSIZE];
    int fbs[BUFSIZE];
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    len = UTFCHARLen(session_data->preedit_buf);
    
    /*
    * when reversed once, next is convert
    */
    
    for (i = 0; i < len; i++) {
        if (get_feedback(&session_data->preedit_feedback[i]) == IMReverse) {
            last_reverse = i;
        }
    }
    
    if (last_reverse != -1) {
        if (session_data->conversion_string[0] != 0) {
            lookup_test(s);
            return;
        }
        for (i = 0; i <= last_reverse; i++) {
            buf[i] = session_data->preedit_buf[i];
#ifdef	notdef
            printf("buf[%d]=%x\n", i, buf[i]);
#endif
            fbs[i] = IMReverse;
            session_data->conversion_string[i] = buf[i];
        }
        
        buf[i] = '0';
#ifdef	notdef
        printf("buf[%d]=%x\n", i, buf[i]);
#endif
        fbs[i] = IMReverse;
        session_data->conversion_string[i] = 0;
        
        if (last_reverse <= UTFCHARLen(session_data->preedit_buf)) {
            for (i = last_reverse + 1; i < len; i++) {
                buf[i + 1] = session_data->preedit_buf[i];
                fbs[i + 1] = IMUnderline;
                session_data->preedit_string[i - last_reverse - 1] = session_data->preedit_buf[i];
            }
            buf[i + 1] = 0;
            session_data->preedit_string[i - last_reverse - 1] = 0;
            
            for (i = 0; i < len + 1; i++) {
                session_data->preedit_buf[i] = buf[i];
                set_feedback(&session_data->preedit_feedback[i], fbs[i]);
            }
            
            session_data->preedit_buf[i] = 0;
            preedit_buf_print(s);
        }
        preedit_draw(s);
        return;
    }
    for (i = 0; i < len; i++) {
        set_feedback(&session_data->preedit_feedback[i], IMReverse);
    }
    preedit_draw(s);
}

void
preedit_buf_print(iml_session_t * s)
{
    int i;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    int len = UTFCHARLen(session_data->preedit_buf);
    for (i = 0; i <= len; i++) {
        printf("Preedit[%d]=%x	%x\n",
            i,
            session_data->preedit_buf[i],
            get_feedback(&session_data->preedit_feedback[i]));
    }
}

IMText *
make_imtext(iml_session_t * s, UTFCHAR * u)
{
    int len;
    IMText *p = (IMText *) s->If->m->iml_new(s, sizeof(IMText));
    memset(p, 0, sizeof(IMText));
    p->encoding = UTF16_CODESET;
    len = UTFCHARLen(u);
    p->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR) * (len + 1));
    UTFCHARCpy(p->text.utf_chars, u);
    p->char_length = len;
    p->feedback = create_feedback(s, p->char_length);
    return p;
}

IMText *
make_preedit_imtext(iml_session_t * s)
{
    int len;
    int i;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    IMText *p = (IMText *) s->If->m->iml_new(s, sizeof(IMText));
    memset(p, 0, sizeof(IMText));

    p->encoding = UTF16_CODESET;
    len = UTFCHARLen(session_data->preedit_buf);
    p->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR) * (len + 1));
    UTFCHARCpy(p->text.utf_chars, session_data->preedit_buf);
    p->char_length = len;
    p->feedback = create_feedback(s, p->char_length);
    for (i = 0; i < p->char_length; i++) {
        set_feedback(&p->feedback[i], get_feedback(&session_data->preedit_feedback[i]));
        printf("0x%x[%d %d]", p->text.utf_chars[i], get_feedback(&p->feedback[i]), get_feedback(&session_data->preedit_feedback[i]));
    }
    printf("\n");
    return p;
}

void
preedit_draw(
    iml_session_t * s
)
{
    iml_inst *lp;
    iml_inst *rrv = NULL;
    
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    IMText *p = make_preedit_imtext(s);
    
    if (session_data->preedit_start == False) {
        lp = s->If->m->iml_make_preedit_start_inst(s);
        s->If->m->iml_link_inst_tail(&rrv, lp);
        session_data->preedit_start = True;
    }
#ifdef	IML_API_TEST
    /*
    * text replacement text
    */
    lp = s->If->m->iml_make_preedit_draw_with_chgpos_inst(s,
        p,
        0,
        s->PreEditTextInfo.text->char_length,
        UTFCHARLen(p->text.utf_chars));
#else
    lp = s->If->m->iml_make_preedit_draw_inst(s, p);
#endif
    
    s->If->m->iml_link_inst_tail(&rrv, lp);
    s->If->m->iml_execute(s, &rrv);
}

void
iml_make_preedit_draw_with_chgpos_inst_test(iml_session_t * s)
{
    iml_inst *lp;
    iml_inst *rrv = NULL;
    int i;
    UTFCHAR test_string[] = {0x30aa, 0x30f3, 0x0};
    
    /*
    * replacement chg_pos=1 chg_len=3 to text (len=2)
    */
    
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    IMText *p = (IMText *) s->If->m->iml_new(s, sizeof(IMText));
    int len = 2;

    memset(p, 0, sizeof(IMText));
    p->encoding = UTF16_CODESET;
    p->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR) * (len + 1));
    UTFCHARCpy(p->text.utf_chars, test_string);
    p->char_length = len;
    p->feedback = create_feedback(s, p->char_length);
    for (i = 0; i < p->char_length; i++) {
        set_feedback(&p->feedback[i], IMUnderline);
    }
    lp = s->If->m->iml_make_preedit_draw_with_chgpos_inst(s,
        p,
        1,
        4,
        0);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    s->If->m->iml_execute(s, &rrv);
    
    /*
    * sync preedit
    */
    for (i = 0; i < s->PreEditTextInfo.text->char_length; i++) {
        session_data->preedit_buf[i] = s->PreEditTextInfo.text->text.utf_chars[i];
        session_data->preedit_feedback[i] = s->PreEditTextInfo.text->feedback[i];
    }
    session_data->preedit_buf[i] = 0;
}

void
lookup_commit(iml_session_t * s, int index)
{
    int i;
    iml_inst *lp;
    iml_inst *rrv = NULL;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    IMText **candidates = session_data->luc_candidates;
    index += session_data->luc_top;
    
    lp = s->If->m->iml_make_lookup_done_inst(s);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    session_data->luc_current_candidate = 0;
    
    /* erase first */
    lp = s->If->m->iml_make_preedit_erase_inst(s);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    
    lp = s->If->m->iml_make_commit_inst(s, candidates[index]);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    
    s->If->m->iml_execute(s, &rrv);
    
    for (i = 0; i < BUFSIZE; i++) {
        set_feedback(&session_data->preedit_feedback[i], IMUnderline);
    }
    
    if (session_data->preedit_string[0]) {
        UTFCHARCpy(session_data->preedit_buf, session_data->preedit_string);
        session_data->preedit_buf[UTFCHARLen(session_data->preedit_string)] = 0;
        preedit_draw(s);
    } else {
        memset(session_data->preedit_buf, 0, sizeof(UTFCHAR) * BUFSIZE);
    }
    
    memset(session_data->preedit_string, 0, sizeof(UTFCHAR) * BUFSIZE);
    memset(session_data->conversion_string, 0, sizeof(UTFCHAR) * BUFSIZE);
    
    session_data->caret_pos = -1;
    
    session_data->luc_start = False;
    s->If->m->iml_delete2(s);
}

void
lookup_prev(iml_session_t * s)
{
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    session_data->luc_top -= session_data->luc_nchoices;
    session_data->luc_current_candidate = 0;
    if (session_data->luc_top < 0) {
        int p = session_data->max_candidates % session_data->luc_nchoices;
        session_data->luc_top = session_data->max_candidates - p;
    }
}

void
lookup_next(iml_session_t * s)
{
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    session_data->luc_top += session_data->luc_nchoices;
    session_data->luc_current_candidate = 0;
    if (session_data->luc_top > session_data->max_candidates) {
        session_data->luc_top = 0;
    }
}

void
lookup_test(iml_session_t * s)
{
    int i;
    int j = 0;
    int k = 0;
    iml_inst *lp;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    IMLookupDrawCallbackStruct *draw;
    IMLookupStartCallbackStruct *start;
    int max_len = 0;
    IMText **candidates;
    IMText *current_text;
    IMText **labels;
    int len;
    UTFCHAR buf[BUFSIZE];
    
    /* duplicate */
    s->If->m->iml_delete2(s);
    
    session_data->luc_candidates = (IMText **) s->If->m->iml_new2(s, MAXCANDIDATES * sizeof(IMText));
    memset(session_data->luc_candidates, 0, MAXCANDIDATES * sizeof(IMText));
    
    candidates = session_data->luc_candidates;
    
    if (session_data->conversion_string[0]) {
        UTFCHARCpy(buf, session_data->conversion_string);
    } else {
        return;
    }
    
    for (i = 0; i < MAXCANDIDATES; i++) {
        char tmp[3];
        sprintf(tmp, "%d", i);
        candidates[i] = (IMText *) s->If->m->iml_new2(s, sizeof(IMText));
        memset(candidates[i], 0, sizeof(IMText));
        candidates[i]->encoding = UTF16_CODESET;
        candidates[i]->char_length = UTFCHARLen(buf) + strlen(tmp);
        candidates[i]->text.utf_chars = (UTFCHAR *) s->If->m->iml_new2(s,
            sizeof(UTFCHAR) * (candidates[i]->char_length + 1));
        memset(candidates[i]->text.utf_chars, 0, sizeof(UTFCHAR) * (candidates[i]->char_length + 1));
        UTFCHARCpy(candidates[i]->text.utf_chars, buf);
        if (i > 9) {
            candidates[i]->text.utf_chars[candidates[i]->char_length - 2] = tmp[0];
            candidates[i]->text.utf_chars[candidates[i]->char_length - 1] = tmp[1];
        } else {
            candidates[i]->text.utf_chars[candidates[i]->char_length - 1] = tmp[0];
        }
        candidates[i]->feedback = create_feedback2(s, candidates[i]->char_length);
        if (i == session_data->luc_current_candidate) {
            for (j = 0; j < candidates[i]->char_length; j++) {
                set_feedback(&candidates[i]->feedback[j], IMReverse);
            }
        } else {
            for (j = 0; j < candidates[i]->char_length; j++) {
                if (0) {
                    set_feedback(&candidates[i]->feedback[j], IMNormal);
                }
                set_feedback_private(&candidates[i]->feedback[j],
                    IMNormal,
                    IM_RGB_COLOR(255, 0, 0),
                    IM_RGB_COLOR(255, 192, 203),
                    -1);
            }
        }
    }
    
    current_text = candidates[session_data->luc_current_candidate];
    
    session_data->luc_labels = (IMText **) s->If->m->iml_new2(s, MAXCANDIDATES * sizeof(IMText));
    memset(session_data->luc_labels, 0, MAXCANDIDATES * sizeof(IMText));
    
    j = 0;
    labels = session_data->luc_labels;
    for (i = '1'; i <= '9'; i++, j++) {
        labels[j] = (IMText *) s->If->m->iml_new2(s, sizeof(IMText));
	memset(labels[j], 0, sizeof(IMText));
        labels[j]->encoding = UTF16_CODESET;
        labels[j]->char_length = 1;
        labels[j]->text.utf_chars = (UTFCHAR *) s->If->m->iml_new2(s,
            sizeof(UTFCHAR) * (labels[j]->char_length + 1));
        labels[j]->text.utf_chars[0] = (UTFCHAR) i;
        labels[j]->feedback = create_feedback2(s, labels[j]->char_length);
        
        for (k = 0; k < labels[j]->char_length; k++) {
            set_feedback_private(&labels[j]->feedback[k],
                IMNormal,
                IM_RGB_COLOR(0, 0, 0),
                IM_RGB_COLOR(192, 192, 192),
                -1);
        }
    }
    for (i = 'A'; i <= 'Z'; i++, j++) {
        labels[j] = (IMText *) s->If->m->iml_new2(s, sizeof(IMText));
	memset(labels[j], 0, sizeof(IMText));
        labels[j]->char_length = 1;
        labels[j]->text.utf_chars = (UTFCHAR *) s->If->m->iml_new2(s,
            sizeof(UTFCHAR) * (labels[j]->char_length + 1));
        labels[j]->text.utf_chars[0] = (UTFCHAR) i;
        labels[j]->feedback = create_feedback2(s, labels[j]->char_length);
        for (k = 0; k < labels[j]->char_length; k++) {
            set_feedback_private(&labels[j]->feedback[k],
                IMNormal,
                IM_RGB_COLOR(0, 0, 0),
                IM_RGB_COLOR(192, 192, 192),
                -1);
        }
    }
    for (i = 'a'; i <= 'z'; i++, j++) {
        labels[j] = (IMText *) s->If->m->iml_new2(s, sizeof(IMText));
	memset(labels[j], 0, sizeof(IMText));
        labels[j]->encoding = UTF16_CODESET;
        labels[j]->char_length = 1;
        labels[j]->text.utf_chars = (UTFCHAR *) s->If->m->iml_new2(s,
            sizeof(UTFCHAR) * (labels[j]->char_length + 1));
        labels[j]->text.utf_chars[0] = (UTFCHAR) i;
        labels[j]->feedback = create_feedback2(s, labels[j]->char_length);
        for (k = 0; k < labels[j]->char_length; k++) {
            set_feedback_private(&labels[j]->feedback[k],
                IMNormal,
                IM_RGB_COLOR(0, 0, 0),
                IM_RGB_COLOR(192, 192, 192),
                -1);
        }
    }
    labels = session_data->luc_labels;
    
    if (session_data->luc_start == False) {
        session_data->luc_top = 0;
        start = (IMLookupStartCallbackStruct *) s->If->m->iml_new(s, sizeof(IMLookupStartCallbackStruct));
	memset(start, 0, sizeof(IMLookupStartCallbackStruct));
        start->whoIsMaster = IMIsMaster;
        session_data->luc_type = IMIsMaster;
        start->IMPreference = (LayoutInfo *) s->If->m->iml_new(s, sizeof(LayoutInfo));
	memset(start->IMPreference, 0, sizeof(LayoutInfo));
        start->IMPreference->choice_per_window = 36;
        start->IMPreference->ncolumns = 6;
        start->IMPreference->nrows = 6;
        start->IMPreference->drawUpDirection = DrawUpHorizontally;
        start->IMPreference->whoOwnsLabel = IMOwnsLabel;
        start->CBPreference = NULL;
        lp = s->If->m->iml_make_lookup_start_inst(s, start);
        s->If->m->iml_execute(s, &lp);
        session_data->luc_start = True;
    }
    draw = (IMLookupDrawCallbackStruct *) s->If->m->iml_new(s, sizeof(IMLookupDrawCallbackStruct));
    memset(draw, 0, sizeof(IMLookupDrawCallbackStruct));
    draw->index_of_first_candidate = 0;
    draw->index_of_last_candidate = 35;
    draw->n_choices = draw->index_of_last_candidate - draw->index_of_first_candidate + 1;
    
#ifdef	notdef
    draw->title = (IMText *) NULL;
#else
    draw->title = (IMText *) s->If->m->iml_new(s, sizeof(IMText));
    memset(draw->title, 0, sizeof(IMText));
    draw->title->encoding = UTF16_CODESET;
    draw->title->char_length = UTFCHARLen(title_string);
    draw->title->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(IMText) * (draw->title->char_length + 1));
    UTFCHARCpy(draw->title->text.utf_chars, title_string);
    draw->title->feedback = create_feedback(s, draw->title->char_length);
#endif
    
    draw->choices = (IMChoiceObject *) s->If->m->iml_new(s, draw->n_choices * sizeof(IMChoiceObject));
    memset(draw->choices, 0, draw->n_choices * sizeof(IMChoiceObject));
    
    for (i = 0; i < draw->n_choices; i++) {
        IMText *vt;		/* for value */
        IMText *lt;		/* for label */
        vt = draw->choices[i].value = candidates[i + session_data->luc_top];
        lt = draw->choices[i].label = labels[i];
        
        printf("candidates[%d]=%x\n", i + session_data->luc_top,
            candidates[i + session_data->luc_top]);
        
        if (max_len < vt->char_length)
            max_len = vt->char_length;
        
        if (i + session_data->luc_top == session_data->max_candidates) {
            draw->index_of_first_candidate = 0;
            draw->index_of_last_candidate = i;
            draw->n_choices = i + 1;
            break;
        }
    }
    draw->max_len = max_len;
    draw->max_len = 20;
    draw->index_of_current_candidate = session_data->luc_current_candidate;
    
    printf("session_data->luc_top=%x\n", session_data->luc_top);
    
    printf("draw->index_of_first_candidate=%x\n", draw->index_of_first_candidate);
    printf("draw->index_of_last_candidate=%x\n", draw->index_of_last_candidate);
    printf("draw->n_choices=%x\n", draw->n_choices);
    printf("draw->choices=%x\n", draw->choices);
    printf("draw->choices->label=%x\n", draw->choices->label);
    printf("draw->max_len=%x\n", max_len);
    printf("draw->index_of_current_candidate=%x\n", session_data->luc_current_candidate);
    
    lp = s->If->m->iml_make_lookup_draw_inst(s, draw);
    s->If->m->iml_execute(s, &lp);
    
    {
        int last_reverse = 0;
        UTFCHAR tmp[BUFSIZE];
        UTFCHAR tmp2[BUFSIZE];
        len = UTFCHARLen(session_data->preedit_buf);
        
        j = 0;
        UTFCHARCpy(tmp, candidates[session_data->luc_top + session_data->luc_current_candidate]->text.utf_chars);
        
        printf("##\n");
        preedit_buf_print(s);
        printf("##\n");
        
        for (i = 0; i < len; i++) {
            printf("%d %x\n", get_feedback(&session_data->preedit_feedback[i]));
            if (get_feedback(&session_data->preedit_feedback[i]) == IMUnderline) {
                last_reverse = 1;
            }
            if (last_reverse) {
                tmp2[j] = session_data->preedit_buf[i];
                printf("U %d = %x\n", j, tmp2[j]);
                j++;
            }
        }
        tmp2[j] = 0;
        printf("U %d = %x\n", j, tmp2[j]);
        
        UTFCHARCat(session_data->preedit_buf, tmp, tmp2);
        
        printf("##\n");
        preedit_buf_print(s);
        printf("##\n");
        
        for (i = 0; i < UTFCHARLen(tmp); i++) {
            set_feedback(&session_data->preedit_feedback[i], IMReverse);
        }
        for (i = UTFCHARLen(tmp); i < UTFCHARLen(session_data->preedit_buf); i++) {
            set_feedback(&session_data->preedit_feedback[i], IMUnderline);
        }
        preedit_draw(s);
    }
}

void
receive_aux(
    iml_session_t * s,
    IMAuxDrawCallbackStruct * aux
)
{
    IMText *lts, *lt;
    int i, j;
	iml_inst *lp;

    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;
    printf("Received AUX data\n");
    
    printf("\taux_name=[%s]\n", aux->aux_name);
    printf("\tcount_integer_values=[%d]\n", aux->count_integer_values);
    printf("\tcount_string_values=[%d]\n", aux->count_string_values);
    
    printf("\t** INT[] **\n");
    for (i = 0; i < aux->count_integer_values; i++) {
        printf("\t%3d:0x%08x\n", i, aux->integer_values[i]);
    }
    printf("\t** STR[] **\n");
    lts = aux->string_values;
    for (i = 0, lt = lts; i < aux->count_string_values; i++, lt++) {
        printf("\t%3d:[%d]", i, lt->char_length);
        for (j = 0; j < lt->char_length; j++) {
            printf("[%x]", lt->text.utf_chars[j]);
        }
        printf("\n");
    }
    
    if (!strcmp(aux->aux_name, class_names[SAMPLE_AUX_PANEL])) {
        if (aux->count_string_values == 1 && aux->integer_values[0] == 1 &&
          UTFCHARCmp2(aux->string_values[0].text.utf_chars, "DICT", 4)) {
            if (desktop_data->aux_start[SAMPLE_AUX_DICT] == False) {
                aux_start(desktop_data->auxproxy_session, SAMPLE_AUX_DICT);
            } else {
                aux_draw(desktop_data->auxproxy_session, SAMPLE_AUX_DICT, 0, NULL, 0, NULL);
            }
        }
    } else if (!strcmp(aux->aux_name, class_names[SAMPLE_AUX_DICT])) {
        if (aux->count_string_values == 2) {
            UTFCHAR *from, *to;
            IMText *fromt, *tot;
            fromt = &aux->string_values[0];
            tot = &aux->string_values[1];
            from = s->If->m->iml_new(s, sizeof(UTFCHAR) * (fromt->char_length + 1));
            to = s->If->m->iml_new(s, sizeof(UTFCHAR) * (tot->char_length + 1));
            memset(from, 0, sizeof(UTFCHAR) * (fromt->char_length) + 1);
            memset(to, 0, sizeof(UTFCHAR) * (tot->char_length) + 1);
            
            memcpy(from, fromt->text.utf_chars, sizeof(UTFCHAR) * fromt->char_length);
            memcpy(to, tot->text.utf_chars, sizeof(UTFCHAR) * tot->char_length);
            add_dict(s->desktop->specific_data, from, to);

    	    lp = s->If->m->iml_make_preedit_draw_inst(s, make_imtext(s, add_string));
            s->If->m->iml_execute(s, &lp);
        } else if (aux->count_integer_values == 1) {
            if (aux->integer_values[0] == 0) {
                /*
                * aux_done(s, SAMPLE_AUX_DICT);
                */
            }
        }
    }
#ifdef	notdef
    if (aux->integer_values[SAMPLE_AUX_PANEL] == 1 &&
      aux->count_string_values == 1 &&
      UTFCHARCmp2(aux->string_values[0].text.utf_chars, "DICT", aux->string_values[0].char_length)) {
        aux_start(desktop_data->auxproxy_session, SAMPLE_AUX_DICT);
    } else {
        int aux_int_data[] = {1};
        aux_draw(desktop_data->auxproxy_session, SAMPLE_AUX_DICT, 1, aux_int_data, 0, NULL);
    }
#endif
}

void
aux_start(
    iml_session_t * s,
    int class_name_id
)
{
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;
    if (desktop_data->aux_start[class_name_id] == False) {
        iml_inst *lp;
        IMAuxStartCallbackStruct *aux = (IMAuxStartCallbackStruct *) s->If->m->iml_new(s, sizeof(IMAuxStartCallbackStruct));
	memset(aux, 0, sizeof(IMAuxStartCallbackStruct));
        aux->aux_name = class_names[class_name_id];
        lp = s->If->m->iml_make_aux_start_inst(s, aux);
        s->If->m->iml_execute(s, &lp);
        printf("Starting AUX [%s]\n", class_names[class_name_id]);
        desktop_data->aux_start[class_name_id] = True;
    } else {
        printf("AUX[%s] is already started.\n", class_names[class_name_id]);
    }
}

void
aux_done(
    iml_session_t * s,
    int class_name_id
)
{
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;
    if (desktop_data->aux_start[class_name_id] == True) {
        iml_inst *lp;
        IMAuxDoneCallbackStruct *aux = (IMAuxDoneCallbackStruct *) s->If->m->iml_new(s, sizeof(IMAuxDoneCallbackStruct));
	memset(aux, 0, sizeof(IMAuxDoneCallbackStruct));
        aux->aux_name = class_names[class_name_id];
        lp = s->If->m->iml_make_aux_done_inst(s, aux);
        s->If->m->iml_execute(s, &lp);
        printf("Closing AUX\n");
        desktop_data->aux_start[class_name_id] = False;
    } else {
        printf("AUX is already done.\n");
    }
}

UTFCHAR sample_string[] = {0x53d7, 0x3051, 0x53d6, 0x3063, 0x305f, 0x305e, 0x30fc, 0};

void
aux_draw(
    iml_session_t * s,
    int class_name_id,
    int count_integers,
    int *integers,
    int count_strings,
    UTFCHAR ** strings
)
{
    iml_inst *lp;
    int i, j;
    int len = 7;
    IMText *lts, *lt;
    IMAuxDrawCallbackStruct *aux;
    MyDataPerDesktop *desktop_data;

    if (!s) return;

    desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;
    
    if (desktop_data->aux_start[class_name_id] == False) {
        printf("AUX is not started.\n");
        return;
    }
    aux = (IMAuxDrawCallbackStruct *) s->If->m->iml_new(s, sizeof(IMAuxDrawCallbackStruct));
    memset(aux, 0, sizeof(IMAuxDrawCallbackStruct));
    
    aux->aux_name = class_names[class_name_id];
    
    aux->count_integer_values = count_integers;
    if (aux->count_integer_values) {
        aux->integer_values = (int *) s->If->m->iml_new(s, sizeof(int) * aux->count_integer_values);
        for (i = 0; i < aux->count_integer_values; i++) {
            aux->integer_values[i] = integers[i];
        }
    }
    aux->count_string_values = count_strings;
    if (aux->count_string_values) {
        aux->string_values = lts = (IMText *)
        s->If->m->iml_new(s, sizeof(IMText) * aux->count_string_values);
        memset(aux->string_values, 0, sizeof(IMText) * aux->count_string_values);
        aux->string_values->encoding = UTF16_CODESET;
        
        for (i = 0, lt = lts; i < aux->count_string_values; i++, lt++) {
            len = UTFCHARLen(strings[i]);
            lt->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR) * (len + 1));
            lt->char_length = len + 1;
            UTFCHARCpy(lt->text.utf_chars, strings[i]);
        }
    }
    lp = s->If->m->iml_make_aux_draw_inst(s, aux);
    s->If->m->iml_execute(s, &lp);
}

/* conversion table for predefined dictionary */

UTFCHAR name1_from[] = {0x3044, 0x3057, 0x3080, 0x3089, 0};
UTFCHAR name1_to[] = {0x77f3, 0x6751, 0};
UTFCHAR name2_from[] = {0x304b, 0x305f, 0x304b, 0x3044, 0};
UTFCHAR name2_to[] = {0x7247, 0x8c9d, 0};
UTFCHAR name3_from[] = {0x305f, 0x3058, 0x307e, 0};
UTFCHAR name3_to[] = {0x7530, 0x5cf6, 0};
UTFCHAR name4_from[] = {0x304f, 0x307e, 0x30fc, 0};
UTFCHAR name4_to[] = {0x30af, 0x30de, 0x30fc, 0};
UTFCHAR name5_from[] = {0x307e, 0x3064, 0x305f, 0x304b, 0x3053, 0};
UTFCHAR name5_to[] = {0x677e, 0x305f, 0x304b, 0x5b50, 0};
UTFCHAR name6_from[] = {0x3064, 0x304e, 0x306e, 0x305b, 0x3060, 0x3044, 0};
UTFCHAR name6_to[] = {0x6b21, 0x306e, 0x4e16, 0x4ee3, 0};
UTFCHAR name7_from[] = {0x3072, 0x304d, 0x3064, 0x304e, 0};
UTFCHAR name7_to[] = {0x5f15, 0x304d, 0x7d99, 0x304e, 0};

henkan_table3 htable3[] = {
    {name1_from, name1_to},
    {name2_from, name2_to},
    {name3_from, name3_to},
    {name4_from, name4_to},
    {name5_from, name5_to},
    {name6_from, name6_to},
    {name7_from, name7_to},
    {0, 0},
};

/* add word */

void
add_dict(
    MyDataPerDesktop * desktop_data,
    UTFCHAR * from,
    UTFCHAR * to
)
{
    henkan_table3 *p = (henkan_table3 *) calloc(1, sizeof(henkan_table3));
    int from_len = UTFCHARLen(from);
    int to_len = UTFCHARLen(to);
    p->from = (UTFCHAR *) calloc(1, sizeof(UTFCHAR) * (from_len + 1));
    p->to = (UTFCHAR *) calloc(1, sizeof(UTFCHAR) * (to_len + 1));
    
    UTFCHARCpy(p->from, from);
    UTFCHARCpy(p->to, to);
    
    desktop_data->userdict[desktop_data->wordcount] = p;
    desktop_data->wordcount++;
}

/* do conversion */

Bool
do_convert(
    iml_session_t * s
)
{
    int i, j;
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    MyDataPerDesktop *desktop_data = (MyDataPerDesktop *) s->desktop->specific_data;
    
    for (i = 0; i < desktop_data->wordcount; i++) {
        henkan_table3 *p = desktop_data->userdict[i];
        if (UTFCHARCmp(session_data->preedit_buf, p->from) == True) {
            UTFCHARCpy(session_data->preedit_buf, p->to);
            for (j = 0; j < BUFSIZE; j++) {
                set_feedback(&session_data->preedit_feedback[j], IMReverse);
            }
            preedit_draw(s);
            return True;
        }
    }
    
    for (i = 0; htable3[i].from; i++) {
        if (UTFCHARCmp(session_data->preedit_buf, htable3[i].from) == True) {
            UTFCHARCpy(session_data->preedit_buf, htable3[i].to);
            for (j = 0; j < BUFSIZE; j++) {
                set_feedback(&session_data->preedit_feedback[j], IMReverse);
            }
            preedit_draw(s);
            return True;
        }
    }
    return False;
}

IMFeedbackList *
create_feedback_with_color(
    iml_session_t * s,
    int size,
    int normalfeedback,
    int fg,
    int bg
)
{
    int i;
    IMFeedbackList *feedback, *fbl;
    feedback = (IMFeedbackList *) create_feedback(s, size);
    for (i = 0; i < size; i++) {
        IMFeedbackList *fbl = &feedback[i];
        set_feedback_private(fbl, normalfeedback, fg, bg, -1);
    }
    
    return feedback;
}

IMFeedbackList *
create_feedback2(
    iml_session_t * s,
    int size
)
{
    int i;
    IMFeedbackList *feedback, *fbl;
    IMFeedback *fb;
    
    if (s) {
        feedback = (IMFeedbackList *) s->If->m->iml_new2(s, sizeof(IMFeedbackList) * size);
    } else {
        feedback = (IMFeedbackList *) calloc(1, sizeof(IMFeedbackList) * size);
    }
    for (i = 0; i < size; i++) {
        IMFeedbackList *fbl = &feedback[i];
        fbl->count_feedbacks = 1;
        if (s) {
            fb = fbl->feedbacks = (IMFeedback *) s->If->m->iml_new2(s, sizeof(IMFeedback) * 4);
        } else {
            fb = fbl->feedbacks = (IMFeedback *) calloc(1, sizeof(IMFeedback) * 4);
        }
        memset(fbl->feedbacks, 0, sizeof(IMFeedback) * 4);
    }
    return feedback;
}

IMFeedbackList *
create_feedback(
    iml_session_t * s,
    int size
)
{
    int i;
    IMFeedbackList *feedback, *fbl;
    IMFeedback *fb;
    
    if (s) {
        feedback = (IMFeedbackList *) s->If->m->iml_new(s, sizeof(IMFeedbackList) * size);
    } else {
        feedback = (IMFeedbackList *) calloc(1, sizeof(IMFeedbackList) * size);
    }
    for (i = 0; i < size; i++) {
        IMFeedbackList *fbl = &feedback[i];
        fbl->count_feedbacks = 1;
        if (s) {
            fb = fbl->feedbacks = (IMFeedback *) s->If->m->iml_new(s, sizeof(IMFeedback) * 4);
        } else {
            fb = fbl->feedbacks = (IMFeedback *) calloc(1, sizeof(IMFeedback) * 4);
        }
        memset(fbl->feedbacks, 0, sizeof(IMFeedback) * 4);
    }
    return feedback;
}

int
get_feedback(
    IMFeedbackList * fbl
)
{
    /* returns IM_DECORATION_FEEDBACK */
    IMFeedback *fb = &fbl->feedbacks[0];
    return IM_FEEDBACK_VALUE(fb);
}

void
set_feedback_private(
    IMFeedbackList * fbl,
    int normalfeedback,
    int fg,
    int bg,
    int underline
)
{
    int count = 0;
    IMFeedback *fb;
    
    fb = &fbl->feedbacks[count];
    IM_FEEDBACK_TYPE(fb) = IM_DECORATION_FEEDBACK;
    IM_FEEDBACK_VALUE(fb) = normalfeedback;
    count++;
    
#ifdef	USE_COLOR_FEEDBACK

    if (fg != -1) {
        fb = &fbl->feedbacks[count];
        IM_FEEDBACK_TYPE(fb) = IM_FOREGROUND_RGB_FEEDBACK;
        IM_FEEDBACK_VALUE(fb) = fg;
        count++;
    }
    if (bg != -1) {
        fb = &fbl->feedbacks[count];
        IM_FEEDBACK_TYPE(fb) = IM_BACKGROUND_RGB_FEEDBACK;
        IM_FEEDBACK_VALUE(fb) = bg;
        count++;
    }
    if (underline != -1) {
        fb = &fbl->feedbacks[count];
        IM_FEEDBACK_TYPE(fb) = IM_UNDERLINE_RGB_FEEDBACK;
        IM_FEEDBACK_VALUE(fb) = underline;
        count++;
    }

#endif
    IM_FEEDBACK_COUNT(fbl) = count;
}

void
set_feedback(
    IMFeedbackList * fbl,
    int normalfeedback
)
{
    
    if (normalfeedback == IMUnderline) {
        set_feedback_private(fbl,
            IMUnderline,
            IM_RGB_COLOR(0, 0, 255),		/* FG: blue */
            IM_RGB_COLOR(255, 255, 255),	/* BG: white */
            IM_RGB_COLOR(0, 0, 255));
    } else if (normalfeedback == IMReverse) {
        set_feedback_private(fbl,
            IMReverse,
            IM_RGB_COLOR(255, 255, 255),	/* FG: white */
            IM_RGB_COLOR(0, 0, 255),		/* BG: blue */
            -1);
    } else {
        set_feedback_private(fbl,
            IMNormal,
            -1,
            -1,
            -1);
    }
}

void
SetFeedback(
    iml_session_t * s,
    IMText * text
)
{
    int i;
    IMFeedbackList *fbl;
    IMFeedback *fb;
    int size;
    
    size = text->char_length;
    text->feedback = (IMFeedbackList *) s->If->m->iml_new(s,
				sizeof(IMFeedbackList) * size);
    
    /* set color for each character */
    for (i = 0; i < size; i++) {
        fbl = &text->feedback[i];
        fbl->count_feedbacks = 3;	/* IM_DECORATION_FEEDBACK,
					 * IM_FOREGROUND_RGB_FEEDBACK,
					 * IM_BACKGROUND_RGB_FEEDBACK */

        fbl->feedbacks = (IMFeedback *) s->If->m->iml_new(s,
				sizeof(IMFeedback) * fbl->count_feedbacks);
        
        /*
        * normal decolation, IM_DECORATION_FEEDBACK is required in
        * the first element
        */
        fb = &fbl->feedbacks[0];
        IM_FEEDBACK_TYPE(fb) = IM_DECORATION_FEEDBACK;
        IM_FEEDBACK_VALUE(fb) = IMNormal;
        
        /* foreground is blue */
        fb = &fbl->feedbacks[1];
        IM_FEEDBACK_TYPE(fb) = IM_FOREGROUND_RGB_FEEDBACK;
        IM_FEEDBACK_VALUE(fb) = IM_RGB_COLOR(0, 0, 255);
        
        /* background is blue */
        fb = &fbl->feedbacks[2];
        IM_FEEDBACK_TYPE(fb) = IM_BACKGROUND_RGB_FEEDBACK;
        IM_FEEDBACK_VALUE(fb) = IM_RGB_COLOR(255, 255, 255);
    }
}
