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

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <string.h>

#include "SunIM.h"
#include "koinput.h"
#include "le.h"
#include "kolelog.h"

extern int          g_number_of_engines;
extern int          default_engine_id;
extern IMEEngineRec *g_engines[MAX_ENGINE_NUM];

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

void free_feedback(iml_session_t *s, IMFeedbackList *feedback, int size)
{
    int i;
    IMFeedbackList *fbl;

    if ((s!= NULL) || (feedback == NULL)) return;

    for (i = 0; i < size; i++) {
	fbl = &feedback[i];
	if (fbl->feedbacks != NULL)
	    free(fbl->feedbacks);
    }
    free(feedback);
}

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

void
set_feedback (IMFeedbackList * fbl, int value)
{
    IMFeedback *fb = &fbl->feedbacks[0];
    IM_FEEDBACK_TYPE(fb)=IM_DECORATION_FEEDBACK;
    IM_FEEDBACK_VALUE(fb)=value;
}

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

/* UTF16 string handle functions */
int
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;
}

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;
    if (!p)
	return 0;
    for (i = 0; *p; i++)
	p++;
    return i;
}

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

    memset(text, 0, sizeof(IMText));

    len = UTFCHARLen(p);

    text->encoding = UTF16_CODESET;

    text->text.utf_chars =
	(UTFCHAR *) s->If->m->iml_new(s, sizeof(UTFCHAR) * (len + 1));
    UTFCHARCpy(text->text.utf_chars, p);

    text->char_length = len;

    text->feedback = create_feedback(s, len);
#if 0
    for (i = 0; i < len; i++) {
	set_feedback_private(&text->feedback[i], IMReverse, -1, -1, -1);
    }
#endif

    return text;
}

/* Send a Korean string to system */
void
iml_commit (iml_session_t * s, UTFCHAR *commit_buf)
{
    int len;
    iml_inst *lp;
    IMText *im_text;
    
    len = UTFCHARLen(commit_buf);
    if (len == 0) return;

    im_text = make_imtext(s, commit_buf);
    lp = (iml_inst *)s->If->m->iml_make_commit_inst(s, im_text);
    s->If->m->iml_execute(s, &lp);
}

/* Send a KeyPress Event to system */
void
iml_sendback_key (iml_session_t *s, IMKeyEventStruct *key)
{
    iml_inst *lp;

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

/* Begin catch the system Key Event */
void
iml_conversion_on (iml_session_t * s)
{
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    IMEBufferMethods ime_methods =  session_data->session_core.ime_methods_table;   
    IMEBuffer session_ime_buffer = session_data->session_core.ime_buffer;
#if 0
    (*ime_methods->ime_buffer_conversion_start) (session_ime_buffer);
#endif
    iml_inst *lp;
    lp = (iml_inst *)s->If->m->iml_make_start_conversion_inst(s);
    lp = s->If->m->iml_execute(s, &lp);
}

/* Do not catch the system Key Event */
void
iml_conversion_off (iml_session_t * s)
{
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    IMEBufferMethods ime_methods =  session_data->session_core.ime_methods_table;
    IMEBuffer session_ime_buffer = session_data->session_core.ime_buffer;
    iml_inst *lp;
    IMText *text;
    iml_inst *rrv = NULL;
    UTFCHAR status_str[] = { 0 };
#if 0
    (*ime_methods->ime_buffer_conversion_end) (session_ime_buffer);
#endif

    text = make_imtext (s, status_str);
    lp = s->If->m->iml_make_status_draw_inst(s, text);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    lp = s->If->m->iml_make_status_done_inst(s);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    lp = s->If->m->iml_make_preedit_done_inst(s);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    lp = s->If->m->iml_make_lookup_done_inst(s);
    s->If->m->iml_link_inst_tail (&rrv, lp);
    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);
}

/* Start Status Area Information */
void
iml_status_start (iml_session_t * s)
{
    iml_inst *lp;
    iml_inst *rrv = NULL;
    
    lp = (iml_inst *)s->If->m->iml_make_status_start_inst(s);
    s->If->m->iml_link_inst_tail(&rrv, lp);
}

/* Destroy Status Area Information */
void
iml_status_enddraw (iml_session_t * s)
{
    iml_inst *lp;
    
    lp = (iml_inst *)s->If->m->iml_make_status_done_inst(s);
    s->If->m->iml_execute(s, &lp);
}

/* Draw Status line information */
void
iml_status_draw (iml_session_t * s)
{
    MyDataPerSession *session_data = (MyDataPerSession *) s->specific_data;
    IMEBufferMethods ime_methods =  session_data->session_core.ime_methods_table;
    IMEBuffer session_ime_buffer = session_data->session_core.ime_buffer;
    UTFCHAR *le_status_string = NULL;
    Bool result_is_success;
                                                                                                  
    iml_inst *lp;
    iml_inst *rrv = NULL;
    IMText  *im_text;

    if (!ime_methods)
	return;
  
    result_is_success = 
	(*ime_methods->ime_buffer_get_status) (session_ime_buffer, &le_status_string);

    if (!result_is_success)
	return;

    iml_status_start(s);

    im_text = make_imtext(s, le_status_string);
    lp = (iml_inst *)s->If->m->iml_make_status_draw_inst(s, im_text);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    s->If->m->iml_execute(s, &rrv);
}

void
iml_preedit_start (iml_session_t * s)
{
    iml_inst *lp;
    iml_inst *rrv = NULL;
    
    lp = (iml_inst *)s->If->m->iml_make_preedit_start_inst(s);
    s->If->m->iml_link_inst_tail(&rrv, lp);
}

/* Destroy Pre_edit Area Information */
void
iml_preedit_enddraw (iml_session_t * s)
{
    iml_inst *lp;
    iml_inst *rrv = NULL;
    
    lp = (iml_inst *)s->If->m->iml_make_preedit_erase_inst(s);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    lp = (iml_inst *)s->If->m->iml_make_preedit_done_inst(s);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    
    s->If->m->iml_execute(s, &rrv);
}

/* Draw Pre_edit Area Information */
void
iml_preedit_draw (iml_session_t * s, UTFCHAR *preedit_buf, int caret_pos)
{
    int i, len;
    iml_inst *lp;
    iml_inst *rrv = NULL;
    IMText *im_text;
    
    iml_preedit_start(s);

    if (preedit_buf == NULL || (len = UTFCHARLen(preedit_buf)) == 0){
	lp = (iml_inst *)s->If->m->iml_make_preedit_erase_inst(s);
	s->If->m->iml_link_inst_tail(&rrv, lp);
	s->If->m->iml_execute(s, &rrv);
	return;
    }

    im_text = make_imtext(s, preedit_buf);

    if (caret_pos < 0 || caret_pos > len)
	caret_pos = len;


    for(i = 0; i < caret_pos; i ++) {
	set_feedback(&(im_text->feedback[i]), IMReverse);
    }
    for(i = caret_pos; i < len; i ++) {
	set_feedback(&(im_text->feedback[i]), IMReverse);
    }

#if 0
    set_feedback(&(im_text->feedback[caret_pos - 1]), IMNormal);
#endif

    lp = (iml_inst *)s->If->m->iml_make_preedit_draw_inst(s, im_text);
    s->If->m->iml_link_inst_tail(&rrv, lp);
    
    if(caret_pos != -1) {
	lp = (iml_inst *)s->If->m->iml_make_preedit_caret_inst(s, caret_pos); 
	s->If->m->iml_link_inst_tail(&rrv, lp);
    }
    s->If->m->iml_execute(s, &rrv);
}

void
iml_lookup_start (iml_session_t * s)
{
    /*
      IMLookupStartCallbackStruct *start;
      iml_inst *lp;
	
      start = (IMLookupStartCallbackStruct *)s->If->m->iml_new (s,
      sizeof(IMLookupStartCallbackStruct) );
      start->whoIsMaster = IMIsMaster;
      start->CBPreference = NULL;

      start->IMPreference = (LayoutInfo *)s->If->m->iml_new (s, sizeof (LayoutInfo));
      start->IMPreference->choice_per_window = 10;
      start->IMPreference->ncolumns = 1;
      start->IMPreference->nrows = 10;
      start->IMPreference->drawUpDirection = DrawUpHorizontally;
      start->IMPreference->whoOwnsLabel = IMOwnsLabel;

      lp = s->If->m->iml_make_lookup_start_inst (s, start);

    */	
    iml_inst *lp;
    IMLookupStartCallbackStruct *start;
    
    start = (IMLookupStartCallbackStruct *) s->If->m->iml_new(s, sizeof(IMLookupStartCallbackStruct));
    memset(start, 0, sizeof(IMLookupStartCallbackStruct));

    start->IMPreference = (LayoutInfo *) s->If->m->iml_new(s, sizeof(LayoutInfo));
    memset(start->IMPreference, 0, sizeof(LayoutInfo));

    start->IMPreference->choice_per_window = 10;
    start->IMPreference->ncolumns = 1;
    start->IMPreference->nrows = 10;
    start->IMPreference->drawUpDirection = DrawUpHorizontally;
    start->IMPreference->whoOwnsLabel = IMOwnsLabel;

    start->CBPreference = NULL;
    start->whoIsMaster = IMIsMaster;

    lp = (iml_inst *)s->If->m->iml_make_lookup_start_inst(s, start);
    s->If->m->iml_execute(s, &lp);
}

/* Destroy Candidate Selection Area */
void
iml_lookup_enddraw (iml_session_t *s)
{
    iml_inst *lp;

    lp = (iml_inst*)s->If->m->iml_make_lookup_done_inst(s);
    s->If->m->iml_execute(s, &lp);
}

void
iml_lookup_draw (iml_session_t * s, UTFCHAR ** luc_tmp,
		 int luc_num, int i_current_candidate,int label_type)
{
    int i, char_len;
    char begin_char;
    int max_len = 0;
    int lookup_pos_return;
    iml_inst *lp;
    IMText **candidates, **labels;
    IMLookupDrawCallbackStruct *draw;
    IMEBufferMethods methods_table = 
	((MyDataPerSession *)s->specific_data)->session_core.ime_methods_table;
    IMEBuffer ime_buffer = ((MyDataPerSession *)s->specific_data)->session_core.ime_buffer;
    Bool method_return;
    UTFCHAR u16titlestr[] = { 0xD6C4, 0xBCF4, 0x0000};
    UTFCHAR *u16ptr = u16titlestr;
    
    if (luc_num <= 0) return;

    iml_lookup_start(s);

    if (luc_num > MAX_CANDIDATES_NUM) 
	luc_num = MAX_CANDIDATES_NUM;

    /* Set candidate data */
    candidates = (IMText **) s->If->m->iml_new(s, luc_num * sizeof(IMText *));
    memset(candidates, 0, luc_num * sizeof(IMText *));
    for (i = 0; i < luc_num; 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;
	char_len = UTFCHARLen(luc_tmp[i]);
	candidates[i]->char_length = char_len;
	candidates[i]->text.utf_chars = 
	    (UTFCHAR *)s->If->m->iml_new(s, sizeof(UTFCHAR) * char_len);
	UTFCHARCpy(candidates[i]->text.utf_chars, luc_tmp[i]);
	candidates[i]->feedback = create_feedback(s, char_len);
    }

    /* Set Label data */
    switch(label_type) {
	case NUMERIC_LABEL:
	    begin_char = '0';
	    break;
	case LOWER_LABEL:
	    begin_char = 'a';
	    break;
	case UPPER_LABEL:
	    begin_char = 'A';
	    break;
	default:
	    begin_char = '0';
    }

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

    draw = (IMLookupDrawCallbackStruct *) s->If->m->iml_new(s, sizeof(IMLookupDrawCallbackStruct));
    memset (draw, 0, sizeof(IMLookupDrawCallbackStruct));
	
    method_return =
	(*methods_table->ime_buffer_get_current_lookup_pos)(ime_buffer, &lookup_pos_return);
    if (method_return == False)
	lookup_pos_return = 0;

    draw->title = make_imtext (s, u16ptr);
    /*
      draw->title = NULL;
    */
    draw->n_choices = luc_num ;
#if 0
    if (i_current_candidate <0 || i_current_candidate > luc_num)
	draw->index_of_first_candidate = 0;
    else
	draw->index_of_first_candidate = i_current_candidate;
#endif
    draw->index_of_first_candidate = 0;
	
    draw->index_of_last_candidate = luc_num - 1;
    draw->index_of_current_candidate = lookup_pos_return;
    
    /* Set choices data */
    draw->choices = (IMChoiceObject *) s->If->m->iml_new(s, luc_num * sizeof(IMChoiceObject));
    memset(draw->choices, 0, luc_num * sizeof(IMChoiceObject));
    
    for (i = 0; i < luc_num; i++) {
	IMText *vt;		/* for value */
	IMText *lt;		/* for label */

	vt = draw->choices[i].value = candidates[i];
	lt = draw->choices[i].label = labels[i];
        
	if (max_len < vt->char_length)
	    max_len = vt->char_length;
    }

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

/* Start An Auxiliary Window */
void
iml_aux_start (iml_session_t * s, char *classname)
{
  iml_inst *lp;
  IMAuxStartCallbackStruct *aux;

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

  lp = (iml_inst *)s->If->m->iml_make_aux_start_inst(s, aux);
  s->If->m->iml_execute(s, &lp);

  KOLE_LOG (LOGDEST_STDOUT, "iml_aux_start ----- auxwin name :%s \n", classname);
}

/* Close the Auxiliary Window */
void
iml_aux_done (iml_session_t * s, char *classname)
{
    iml_inst *lp;
    IMAuxDoneCallbackStruct *aux;

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

    lp = (iml_inst *)s->If->m->iml_make_aux_done_inst(s, aux);
    s->If->m->iml_execute(s, &lp);

    KOLE_LOG (LOGDEST_STDOUT, "iml_aux_done -------------------------------- end \n");
}

/* Draw the Auxiliary Window Items */
void iml_aux_draw (iml_session_t *s, char *classname, int count_integers,
		   int *integers, int count_strings,   int *len_strings,
		   unsigned char **strings)
{
    iml_inst *lp;
    IMText *lt;
    IMAuxDrawCallbackStruct *aux;
    int i, len;

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

    aux->count_integer_values = count_integers;
    if (count_integers) {
	aux->integer_values = (int *) s->If->m->iml_new(s, sizeof(int) * count_integers);
	memset(aux->integer_values, 0, sizeof(int) * count_integers);

	for (i = 0; i < count_integers; i++) {
	    aux->integer_values[i] = integers[i];
	}
    }

    aux->count_string_values = count_strings;
    if (count_strings) {
	aux->string_values = (IMText *) s->If->m->iml_new(s, sizeof(IMText) * count_strings);
	memset(aux->string_values, 0, sizeof(IMText) * count_strings);

	aux->string_values->encoding = UTF16_CODESET;
	for (i = 0, lt = aux->string_values; i < count_strings; i++, lt++) {
	    len = len_strings[i];
	    lt->text.utf_chars = (UTFCHAR *) s->If->m->iml_new(s, len+1);
	    lt->char_length = len;
	    memcpy(lt->text.utf_chars, strings[i], len);
	}
    }

    lp = (iml_inst *)s->If->m->iml_make_aux_draw_inst(s, aux);
    s->If->m->iml_execute(s, &lp);

    KOLE_LOG (LOGDEST_STDOUT, "iml_aux_draw -------------------------------- end \n");
}


