/*
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.

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

#include "SunIM.h"

#include "sampleja3_xaux.h"

/*
 * define If method prototype
 */
Bool if_sampleja3_OpenIF(iml_if_t *);
Bool if_sampleja3_CloseIF(iml_if_t *);
Bool if_sampleja3_GetIFValues(iml_if_t *, IMArgList, int);
Bool if_sampleja3_SetIFValues(iml_if_t *, IMArgList, int);
Bool if_sampleja3_OpenDesktop(iml_desktop_t *, IMArgList, int);
Bool if_sampleja3_CloseDesktop(iml_desktop_t *);
Bool if_sampleja3_CreateSC(iml_session_t *, IMArgList, int);
Bool if_sampleja3_DestroySC(iml_session_t *);
Bool if_sampleja3_GetSCValues(iml_session_t *, IMArgList, int);
Bool if_sampleja3_SetSCValues(iml_session_t *, IMArgList, int);
IMText *if_sampleja3_ResetSC(iml_session_t *);
void if_sampleja3_SetSCFocus(iml_session_t *);
void if_sampleja3_UnsetSCFocus(iml_session_t *);
void if_sampleja3_SendEvent(iml_session_t *, IMInputEvent * ev);

/*
 * define if_methods_t
 */
static if_methods_t if_methods = {
    if_sampleja3_OpenIF,
    if_sampleja3_CloseIF,
    if_sampleja3_GetIFValues,
    if_sampleja3_SetIFValues,
    if_sampleja3_OpenDesktop,
    if_sampleja3_CloseDesktop,
    if_sampleja3_CreateSC,
    if_sampleja3_DestroySC,
    if_sampleja3_GetSCValues,
    if_sampleja3_SetSCValues,
    if_sampleja3_ResetSC,
    if_sampleja3_SetSCFocus,
    if_sampleja3_UnsetSCFocus,
    if_sampleja3_SendEvent
};

UTFCHAR lename_string[] = {'s', 'a', 'm', 'p', 'l', 'e', 'j', 'a', '3', 0};
UTFCHAR jahrn_string[] = {0x65e5, 0x672c, 0x8a9e, 0};
static IMLEName lename = {"sampleja3", lename_string};
static IMLocale locales[] = {{"ja", jahrn_string}, NULL};

static UTFCHAR AuxName[] = {'s', 'a', 'm', 'p', 'l', 'e', 'j', 'a', '3'};

void sampleja3_conversion_on(iml_session_t *);
void sampleja3_conversion_off(iml_session_t *);
void sampleja3_commit_string(iml_session_t *, UTFCHAR *);

IMInputEvent *modify_event(iml_session_t * s, IMInputEvent * ev);
void aux_start(iml_session_t * s, char *class_name);
void aux_done(iml_session_t * s, char *class_name);
void aux_draw(iml_session_t * s, char *class_name, int count_integers, int *integers, int count_strings, UTFCHAR ** strings);
void aux_draw2(iml_session_t * s, char *class_name, int count_integers, int *integers, int count_strings, IMText * texts);
void sampleja3_receive_aux(iml_session_t * s, IMAuxDrawCallbackStruct * aux);
IMText *make_imtext(iml_session_t * s, UTFCHAR * p);
IMFeedbackList *create_feedback(iml_session_t * s, int size);

static IMObjectDescriptorStruct *objects = 0;

typedef struct Sampleja3SessionPrivate_ {
    int lookup_current_candidate;
}   Sampleja3SessionPrivate;

typedef struct Sampleja3DesktopPrivate_ {
    iml_session_t *root_session;
    iml_session_t *luc_session;
}   Sampleja3DesktopPrivate;

static char *class_names[] = {
    "com.sun.sampleja3.PaletteAux",
    "com.sun.sampleja3.LookupAux"
};

void
if_GetIfInfo(
	     IMArgList args,
	     int num_args
)
{
    int i;
    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) & if_methods;
	    break;
	case IF_LE_NAME:
	    args->value = (IMArgVal) & lename;
	    break;
	case IF_SUPPORTED_LOCALES:
	    args->value = (IMArgVal) & locales;
	    break;
	case IF_SUPPORTED_OBJECTS:
	    if (!objects) {
	        int obj_id = 0;
		objects = (IMObjectDescriptorStruct *)
		    calloc(3, sizeof(IMObjectDescriptorStruct));

		objects[obj_id].leid = "sampleja3";
		objects[obj_id].type = IM_DOWNLOADINGOBJECT_BINGUI_TYPE;
		objects[obj_id].name = AuxName;
		objects[obj_id].name_length = 9;
		objects[obj_id].domain = "com.sun";
		objects[obj_id].scope = "sampleja3";
		if (getenv("USE_GTK")) {
		  objects[obj_id].path = "./locale/ja/sampleja3/xaux/gtk/xaux.so";
	        } else {
		  objects[obj_id].path = "./locale/ja/sampleja3/xaux/motif/xaux.so";
   	        }
		objects[obj_id].signature = "";

		obj_id++;

#ifdef	IF_SUPPORT_JAVA
		objects[obj_id].leid = "sampleja3";
		objects[obj_id].type = IM_DOWNLOADINGOBJECT_JARGUI_TYPE;
		objects[obj_id].name = AuxName;
		objects[obj_id].name_length = 9;
		objects[obj_id].domain = "com.sun";
		objects[obj_id].scope = "sampleja3";
		objects[obj_id].path = "/usr/lib/im/locale/ja/sampleja3/aux.jar";
		objects[obj_id].signature = "";
		objects[obj_id].class_names = class_names;
		objects[obj_id].count_names = 1;
#endif /* IF_SUPPORT_JAVA */
	    }
	    args->value = (IMArgVal) objects;
	    break;
	case IF_NEED_THREAD_LOCK:
	    args->value = (IMArgVal) True;
	    break;
	default:
	    break;
	}
    }
}

Bool
if_sampleja3_OpenIF(
	       iml_if_t * If
)
{
    return True;
}

Bool
if_sampleja3_CloseIF(
		iml_if_t * If
)
{
    return True;
}

Bool
if_sampleja3_GetIFValues(
		    iml_if_t * If,
		    IMArgList args,
		    int num_args
)
{
    int i;
    return True;
}

Bool
if_sampleja3_SetIFValues(
		    iml_if_t * If,
		    IMArgList args,
		    int num_args
)
{
    return True;
}

Bool
if_sampleja3_OpenDesktop(
		    iml_desktop_t * desktop,
		    IMArgList args,
		    int num_args
)
{
    Sampleja3DesktopPrivate *dp = (Sampleja3DesktopPrivate *) calloc(1, sizeof(Sampleja3DesktopPrivate));
    desktop->specific_data = (Sampleja3DesktopPrivate *) dp;
    return True;
}

Bool
if_sampleja3_CloseDesktop(
		     iml_desktop_t * desktop
)
{
    Sampleja3DesktopPrivate *dp = (Sampleja3DesktopPrivate *) desktop->specific_data;
    free(dp);
    return True;
}

Bool
if_sampleja3_CreateSC(
		 iml_session_t * s,
		 IMArgList args,
		 int num_args
)
{
    Sampleja3SessionPrivate *p = (Sampleja3SessionPrivate *) calloc(1, sizeof(Sampleja3SessionPrivate));
    s->specific_data = (void *) p;
    return True;
}

Bool
if_sampleja3_DestroySC(
		  iml_session_t * s
)
{
    Sampleja3SessionPrivate *sp = (Sampleja3SessionPrivate *) s->specific_data;
    free(sp);
    return True;
}

Bool
if_sampleja3_GetSCValues(
		    iml_session_t * s,
		    IMArgList args,
		    int num_args
)
{
    return True;
}

Bool
if_sampleja3_SetSCValues(
		    iml_session_t * s,
		    IMArgList args,
		    int num_args
)
{
    int i;
    IMArg *p = args;
    Sampleja3SessionPrivate *sp = (Sampleja3SessionPrivate *) s->specific_data;

    for (i = 0; i < num_args; i++, p++) {
	switch (p->id) {
	case SC_TRIGGER_ON_NOTIFY:
	    sampleja3_conversion_on(s);
	    break;
	case SC_TRIGGER_OFF_NOTIFY:
	    sampleja3_conversion_off(s);
	    break;
	case SC_REALIZE:
	    if (s->desktop->session_count == 1) {
		Sampleja3DesktopPrivate *dp = (Sampleja3DesktopPrivate *) s->desktop->specific_data;
		dp->root_session = s;

		aux_start(s, AUX_PALETTE_CLASS_NAME);
		aux_start(s, AUX_LUC_CLASS_NAME);
	    }
	    sampleja3_conversion_off(s);
	    break;

	case SC_CLIENT_LOCALE:
	  if (p->value) printf("SC_CLIENT_LOCALE: %s\n", p->value);
	  break;
	case SC_CLIENT_INPUT_METHOD_NAME:
	  if (p->value) printf("SC_CLIENT_INPUT_METHOD_NAME: %s\n", p->value);
	  break;
	case SC_CLIENT_CHARACTER_SUBSETS:
	  if (p->value) {
	      int *pi = (int*) p->value;
	      printf("SC_CLIENT_CHARACTER_SUBSETS:");
	      for (; *pi; pi++) {
		  printf("%d ", *pi);
	      }
	      printf("\n");
	  }
	  break;
			
	default:
	    break;
	}
    }
    return True;
}

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

void
if_sampleja3_SetSCFocus(
		   iml_session_t * s
)
{
}

void
if_sampleja3_UnsetSCFocus(
		     iml_session_t * s
)
{
}

void
if_sampleja3_SendEvent(
		  iml_session_t * s,
		  IMInputEvent * ev_
)
{
    Sampleja3DesktopPrivate *dp = (Sampleja3DesktopPrivate *) s->desktop->specific_data;

    IMInputEvent *ev = modify_event(s, ev_);
    if (ev->type == IM_EventKeyList) {
	IMKeyEventStruct *key = (IMKeyEventStruct *) ((IMKeyListEvent *) ev)->keylist;
	sampleja3_receive_keyevent(s, key);
    } else if (ev->type == IM_EventAux) {
	IMAuxDrawCallbackStruct *aux_data = ((IMAuxEvent *) ev)->aux;
	sampleja3_receive_aux(s, aux_data);
        {
          int int_values[1];
          int_values[0] = SAMPLEJA3_AUXPALETTE_HELPSTART;
          printf("Help Start\n");
          aux_draw(s,
		 AUX_PALETTE_CLASS_NAME,
		 1, int_values,
		 0, 0);
        }
    }
}

static UTFCHAR luc_string1[] = {0x304b, 0x3093, 0x3058, 0};
static UTFCHAR luc_string2[] = {0x611f, 0x3058, 0};
static UTFCHAR luc_string3[] = {0x6f22, 0x5b57, 0};
static UTFCHAR luc_string4[] = {0x76e3, 0x4e8b, 0};
static UTFCHAR luc_string5[] = {0x5b8c, 0x6cbb, 0};

static UTFCHAR *LUC_CANDIDATES[] = {
    luc_string1,
    luc_string2,
    luc_string3,
    luc_string4,
luc_string5};

#define	NUM_CANDIDATES	5

/* Handle KeyEvent */

sampleja3_receive_keyevent(
		      iml_session_t * s,
		      IMKeyEventStruct * key
)
{
    Sampleja3DesktopPrivate *dp = (Sampleja3DesktopPrivate *) s->desktop->specific_data;
    Sampleja3SessionPrivate *sp = (Sampleja3SessionPrivate *) s->specific_data;
    IMText *p;
    iml_inst *lp;
    int lookup_aux_integers[3];

    iml_session_t *ls = dp->luc_session;

    printf("sampleja3_receive_keyevent keycode=%x keychar=%x modifier=%x\n",
	   key->keyCode, key->keyChar, key->modifier);

    if (ls) {
	sp = (Sampleja3SessionPrivate *) ls->specific_data;
	if (key->keyCode == IM_VK_SPACE) {
	    sp->lookup_current_candidate++;
	    if (sp->lookup_current_candidate >= NUM_CANDIDATES) {
		sp->lookup_current_candidate = 0;
	    }
	    p = make_imtext(ls, LUC_CANDIDATES[sp->lookup_current_candidate]);
	    lp = ls->If->m->iml_make_preedit_draw_inst(ls, p);
	    ls->If->m->iml_execute(ls, &lp);

	    luc_draw(ls, sp->lookup_current_candidate);

	    return;
	} else if (key->keyCode == IM_VK_UP) {
	    if (sp->lookup_current_candidate == 0) {
		sp->lookup_current_candidate = NUM_CANDIDATES - 1;
	    } else {
		sp->lookup_current_candidate--;
	    }

	    p = make_imtext(ls, LUC_CANDIDATES[sp->lookup_current_candidate]);
	    lp = ls->If->m->iml_make_preedit_draw_inst(ls, p);
	    ls->If->m->iml_execute(ls, &lp);

	    luc_draw(ls, sp->lookup_current_candidate);
	    return;
	} else if (key->keyCode >= IM_VK_1 && key->keyCode <= IM_VK_9) {
	    int index = key->keyCode - IM_VK_1;

	    sampleja3_commit_string(ls, LUC_CANDIDATES[index]);

	    aux_luc_done(ls);

	    dp->luc_session = 0;
	    sp->lookup_current_candidate = 0;
	    return;
	} else if (key->keyCode == IM_VK_ENTER || key->keyCode == IM_VK_DOWN) {

	    sampleja3_commit_string(ls, LUC_CANDIDATES[sp->lookup_current_candidate]);

	    aux_luc_done(ls);

	    dp->luc_session = 0;
	    sp->lookup_current_candidate = 0;
	    return;
	} else {
	    sampleja3_commit_string(ls, LUC_CANDIDATES[sp->lookup_current_candidate]);

	    aux_luc_done(ls);

	    dp->luc_session = 0;
	    sp->lookup_current_candidate = 0;
	}
    } else {
	if (key->modifier & IM_CTRL_MASK) {
	    if (key->keyCode == IM_VK_SPACE) {
		sampleja3_conversion_off(s);
		return;
	    }
	} else {
	    if (key->keyCode == IM_VK_B) {
		p = make_imtext(s, LUC_CANDIDATES[sp->lookup_current_candidate]);
		lp = s->If->m->iml_make_preedit_draw_inst(s, p);
		s->If->m->iml_execute(s, &lp);
		return;

	    } else if (key->keyCode == IM_VK_SPACE) {
		ls = dp->luc_session = s;
		sp->lookup_current_candidate++;

		p = make_imtext(ls, LUC_CANDIDATES[sp->lookup_current_candidate]);
		lp = ls->If->m->iml_make_preedit_draw_inst(ls, p);
		ls->If->m->iml_execute(ls, &lp);

		luc_draw(ls, sp->lookup_current_candidate);

		return;
	    }
	}
    }

    lp = s->If->m->iml_make_keypress_inst(s, (IMKeyEventStruct *) key);
    s->If->m->iml_execute(s, &lp);
}

UTFCHAR title_string[] = {'L', 'O', 'O', 'K', 'U', 'P'};

luc_draw(iml_session_t * s, int index)
{
    int i;
    int j = 0;
    int k = 0;
    iml_inst *lp;
    int max_len = 0;
    IMText *current_text;
    int len;
    int luc_top = 0;
    UTFCHAR buf[BUFSIZE];

    Sampleja3SessionPrivate *sp = (Sampleja3SessionPrivate *) s->specific_data;
    Sampleja3DesktopPrivate *dp = (Sampleja3DesktopPrivate *) s->desktop->specific_data;

    IMText **candidates;
    IMText **labels;
    IMLookupDrawCallbackStruct *draw;
    IMLookupStartCallbackStruct *start;

    candidates = (IMText **) s->If->m->iml_new(s, NUM_CANDIDATES * sizeof(IMText *));
    memset(candidates, 0, NUM_CANDIDATES * sizeof(IMText *));

    for (i = 0; i < NUM_CANDIDATES; i++) {
	candidates[i] = (IMText *) s->If->m->iml_new(s, sizeof(IMText));
	memset(candidates[i], 0, sizeof(IMText));
	candidates[i]->encoding = UTF16_CODESET;
	candidates[i]->count_annotations = 0;
	candidates[i]->annotations = NULL;
	candidates[i]->char_length = UTFCHARLen(LUC_CANDIDATES[i]);
	candidates[i]->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR) * candidates[i]->char_length);
	memcpy(candidates[i]->text.utf_chars, LUC_CANDIDATES[i], sizeof(UTFCHAR) * candidates[i]->char_length);
	candidates[i]->feedback = create_feedback(s, candidates[i]->char_length);
    }

    labels = (IMText **) s->If->m->iml_new(s, NUM_CANDIDATES * sizeof(IMText *));
    memset(labels, 0, NUM_CANDIDATES * sizeof(IMText *));
    for (i = '1'; i <= '9'; i++, j++) {
	labels[j] = (IMText *) s->If->m->iml_new(s, sizeof(IMText));
	labels[j]->encoding = UTF16_CODESET;
	labels[j]->count_annotations = 0;
	labels[j]->annotations = NULL;
	labels[j]->char_length = 1;
	labels[j]->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR));
	labels[j]->text.utf_chars[0] = (UTFCHAR) i;
	labels[j]->feedback = create_feedback(s, labels[j]->char_length);
    }

    start = (IMLookupStartCallbackStruct *) s->If->m->iml_new(s, sizeof(IMLookupStartCallbackStruct));
    start->whoIsMaster = IMIsMaster;
    start->IMPreference = (LayoutInfo *) s->If->m->iml_new(s, sizeof(LayoutInfo));
    start->IMPreference->choice_per_window = NUM_CANDIDATES;
    start->IMPreference->ncolumns = 1;
    start->IMPreference->nrows = NUM_CANDIDATES;
    start->IMPreference->drawUpDirection = DrawUpHorizontally;
    start->IMPreference->whoOwnsLabel = IMOwnsLabel;
    start->CBPreference = NULL;

    aux_luc_start(s, start);

    draw = (IMLookupDrawCallbackStruct *) s->If->m->iml_new(s, sizeof(IMLookupDrawCallbackStruct));
    draw->index_of_first_candidate = 0;
    draw->index_of_last_candidate = NUM_CANDIDATES - 1;
    draw->n_choices = draw->index_of_last_candidate - draw->index_of_first_candidate + 1;

    draw->title = (IMText *) s->If->m->iml_new(s, sizeof(IMText));
    draw->title->encoding = UTF16_CODESET;
    draw->title->count_annotations = 0;
    draw->title->annotations = NULL;
    draw->title->char_length = 6;
    draw->title->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR) * draw->title->char_length);
    memcpy(draw->title->text.utf_chars, title_string, sizeof(UTFCHAR) * draw->title->char_length);
    draw->title->feedback = create_feedback(s, draw->title->char_length);

    draw->choices = (IMChoiceObject *) s->If->m->iml_new(s, 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 + luc_top];
	lt = draw->choices[i].label = labels[i];

	if (max_len < vt->char_length) {
	    max_len = vt->char_length;
	}
    }
    draw->max_len = 20;
    draw->index_of_current_candidate = index;

    aux_luc_draw(s, draw);
}

IMText *make_imtext(iml_session_t * s, UTFCHAR * p);

void
sampleja3_conversion_on(
		   iml_session_t * s
)
{
    int int_values[1];
    UTFCHAR on_status_string[] = {'O', 'N', 0x0};

    /* drawing status string */
    iml_inst *lp;
    lp = s->If->m->iml_make_preedit_start_inst(s);
    s->If->m->iml_execute(s, &lp);
    lp = s->If->m->iml_make_status_draw_inst(s, make_imtext(s, on_status_string));
    s->If->m->iml_execute(s, &lp);

    int_values[0] = SAMPLEJA3_AUXPALETTE_CONVON;

    /* sending to AUX */
    aux_draw(s,
		 AUX_PALETTE_CLASS_NAME,
		 1, int_values,
		 0, 0);
}

void
sampleja3_conversion_off(
		    iml_session_t * s
)
{
    int int_values[1];
    UTFCHAR off_status_string[] = {'O', 'F', 'F', 0x0};
    iml_inst *lp;
    lp = s->If->m->iml_make_end_conversion_inst(s);
    s->If->m->iml_execute(s, &lp);
    lp = s->If->m->iml_make_status_draw_inst(s, make_imtext(s, off_status_string));
    s->If->m->iml_execute(s, &lp);

    int_values[0] = SAMPLEJA3_AUXPALETTE_CONVOFF;

    /* sending to AUX */
    aux_draw(s,
		 AUX_PALETTE_CLASS_NAME,
		 1, int_values,
		 0, 0);
}

void
sampleja3_commit_string(
		   iml_session_t * s,
		   UTFCHAR * string
)
{
    iml_inst *lp;
    IMText *p;

    /* erase first */
    lp = s->If->m->iml_make_preedit_erase_inst(s);
    s->If->m->iml_execute(s, &lp);

    /* commit */
    p = make_imtext(s, string);
    lp = s->If->m->iml_make_commit_inst(s, p);
    s->If->m->iml_execute(s, &lp);
}

void
aux_start(
	  iml_session_t * s,
	  char *class_name
)
{
    iml_inst *lp;
    IMAuxStartCallbackStruct *aux = (IMAuxStartCallbackStruct *) s->If->m->iml_new(s, sizeof(IMAuxStartCallbackStruct));
    aux->aux_name = class_name;
    lp = s->If->m->iml_make_aux_start_inst(s, aux);
printf("aux_start\n");
    s->If->m->iml_execute(s, &lp);
}

void
aux_done(
	 iml_session_t * s,
	 char *class_name
)
{
    iml_inst *lp;
    IMAuxDoneCallbackStruct *aux = (IMAuxDoneCallbackStruct *) s->If->m->iml_new(s, sizeof(IMAuxDoneCallbackStruct));
    aux->aux_name = class_name;
    lp = s->If->m->iml_make_aux_done_inst(s, aux);
    s->If->m->iml_execute(s, &lp);
}

void
aux_draw2(
	  iml_session_t * s,
	  char *class_name,
	  int count_integers,
	  int *integers,
	  int count_strings,
	  IMText * texts
)
{
    iml_inst *lp;
    int i, len, pp;
    IMText *lts, *lt, *ltp = texts;
    IMAuxDrawCallbackStruct *aux;

    aux = (IMAuxDrawCallbackStruct *) s->If->m->iml_new(s, sizeof(IMAuxDrawCallbackStruct));
    memset(aux, 0, sizeof(IMAuxDrawCallbackStruct));
    aux->aux_name = class_name;

    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);
	memset(aux->integer_values, 0, 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);
	for (i = 0, lt = lts; i < aux->count_string_values; i++, lt++, ltp++) {
	    len = ltp->char_length;
	    lt->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR) * len);
	    lt->char_length = len;
	    memcpy(lt->text.utf_chars, ltp->text.utf_chars, sizeof(UTFCHAR) * len);
	}
    }
    lp = s->If->m->iml_make_aux_draw_inst(s, aux);
    s->If->m->iml_execute(s, &lp);
}

void
aux_draw(
	 iml_session_t * s,
	 char *class_name,
	 int count_integers,
	 int *integers,
	 int count_strings,
	 UTFCHAR ** strings
)
{
    iml_inst *lp;
    int i, len;
    IMText *lts, *lt;
    IMAuxDrawCallbackStruct *aux;

    aux = (IMAuxDrawCallbackStruct *) s->If->m->iml_new(s, sizeof(IMAuxDrawCallbackStruct));
    memset(aux, 0, sizeof(IMAuxDrawCallbackStruct));
    aux->aux_name = class_name;

    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);
	memset(aux->integer_values, 0, 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);
	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);
	    lt->char_length = len;
	    memcpy(lt->text.utf_chars, strings[i], sizeof(UTFCHAR) * len);
	}
    }
    lp = s->If->m->iml_make_aux_draw_inst(s, aux);
    s->If->m->iml_execute(s, &lp);
}

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

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

    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");
    }
}


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;
}

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++;

    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++;
    }
    IM_FEEDBACK_COUNT(fbl) = count;
}

IMText *
make_imtext(iml_session_t * s, UTFCHAR * p)
{
    int len;
    int i;
    IMText *text = (IMText *) s->If->m->iml_new(s, sizeof(IMText));
    memset(text, 0, sizeof(IMText));

    len = UTFCHARLen(p);
    text->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR) * len);
    memcpy(text->text.utf_chars, p, sizeof(UTFCHAR) * len);
    text->char_length = len;
    text->feedback = create_feedback(s, text->char_length);
    for (i = 0; i < text->char_length; i++) {
	set_feedback_private(&text->feedback[i], IMReverse, -1, -1, -1);
    }
    return text;
}

aux_luc_start(
	      iml_session_t * s,
	      IMLookupStartCallbackStruct * start
)
{
    if (!getenv("DONOTUSE_AUXLUC")) {
	int int_values[6];

	int_values[0] = SAMPLEJA3_AUXLUC_START;
	int_values[1] = start->IMPreference->choice_per_window;
	int_values[2] = start->IMPreference->ncolumns;
	int_values[3] = start->IMPreference->nrows;
	int_values[4] = start->IMPreference->drawUpDirection;

	aux_draw(s,
		 AUX_LUC_CLASS_NAME,
		 5, int_values,
		 0, 0);
    } else {
	iml_inst *lp = s->If->m->iml_make_lookup_start_inst(s, start);
	s->If->m->iml_execute(s, &lp);
    }
}

aux_luc_done(
	     iml_session_t * s
)
{
    if (!getenv("DONOTUSE_AUXLUC")) {
	int int_values[1];
	int_values[0] = SAMPLEJA3_AUXLUC_DONE;
	aux_draw(s,
		 AUX_LUC_CLASS_NAME,
		 1, int_values,
		 0, 0);
    } else {
	iml_inst *lp = s->If->m->iml_make_lookup_done_inst(s);
	s->If->m->iml_execute(s, &lp);
    }
}

aux_luc_draw(
	     iml_session_t * s,
	     IMLookupDrawCallbackStruct * draw
)
{
    if (!getenv("DONOTUSE_AUXLUC")) {
	int i, n = 0;

	int int_values[6];
	IMText *texts, *lt, *lts;

	int_values[0] = SAMPLEJA3_AUXLUC_DRAW;
	int_values[1] = draw->index_of_current_candidate;
	int_values[2] = draw->n_choices;
	int_values[3] = draw->index_of_first_candidate;
	int_values[4] = draw->index_of_last_candidate;

	texts = (IMText *) s->If->m->iml_new(s, draw->n_choices * sizeof(IMText));
	memset(texts, 0, draw->n_choices * sizeof(IMText));
	for (i = 0, lt = texts; i < draw->n_choices; i++, lt++) {
	    lts = draw->choices[i].value;
	    lt->char_length = lts->char_length;
	    lt->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR) * lt->char_length);
	    memcpy(lt->text.utf_chars, lts->text.utf_chars, sizeof(UTFCHAR) * lt->char_length);
	}

	aux_draw2(s,
		  AUX_LUC_CLASS_NAME,
		  5, int_values,
		  draw->n_choices, texts);

    } else {
	iml_inst *lp = s->If->m->iml_make_lookup_draw_inst(s, draw);
	s->If->m->iml_execute(s, &lp);
    }
}

/* Modify AUX event to KeyEvent */

IMInputEvent *
modify_event(
	     iml_session_t * s,
	     IMInputEvent * ev
)
{
    static IMKeyEventStruct akey;
    static IMKeyListEvent keyev;

    if (ev->type == IM_EventAux) {
	IMAuxDrawCallbackStruct *aux_data = ((IMAuxEvent *) ev)->aux;
	if (aux_data->count_integer_values == 4 &&
	    aux_data->integer_values[0] == SAMPLEJA3_AUXSETVAL_KEYPRESS) {
	    akey.keyCode = aux_data->integer_values[1];
	    akey.keyChar = aux_data->integer_values[2];
	    akey.modifier = aux_data->integer_values[3];
	    keyev.type = IM_EventKeyList;
	    keyev.keylist = (IMKeyList) & akey;
	    return (IMInputEvent *) & keyev;
	}
    }
    return ev;
}
