#include <config.h>
#include <stdio.h>
#include <vector>
#include "IIIMP_ICState.hh"
#include "IIIMPTrans.hh"
#include "IIIMPUtil.hh"
#include "IIIMP_hotkey.hh"

IIIMP_hotkey::IIIMP_hotkey(
    IIIMP_ICState *hics
) 
{
    hotkey_mode = false;
    lang_selection = false;
    forward_event = false;
    first_candidate = -1;
    last_candidate = -1;
    current = -1;
    curr_hotkeyid = -1;
}

IIIMP_hotkey::~IIIMP_hotkey()
{   
}

bool
IIIMP_hotkey::process_hotkey(
    IIIMP_ICState *hics,
    int hotkey_id,
    int index
)
{
    bool result = false;
    bool flag;
    IIIMP_message *p;

    curr_hotkeyid = hotkey_id;

    if (hotkey_id == HOTKEY_ID_LANG_SWITCH) {
	if (get_lang_selection()) {
	    set_lang_selection(false);
	    result = stop_lang_selection_window(hics);
	} else {
	    set_lang_selection(true);
	    result = start_lang_selection_window(hics);
	}
    } else if (hotkey_id == HOTKEY_ID_TRIGGER_NOTIFY) {
	if (hics->pshared->conversion_mode)
	    flag = false;
	else 
	    flag = true;
	result = hics->get_ichandler()->toggle_conversion(hics->get_imlexec(), flag);
        hics->pshared->conversion_mode = flag;
        if ((hics->start_request()->dealing()) && result) {
	    if (!hics->pshared->conversion_mode) {
		p = iiimp_hotkey_state_notify_new(hics->get_iiimptrans()->get_data_s(), hics->get_im_id(), hics->get_ic_id(), hotkey_id, EVENT_FORWARDING_OFF);
		if (!hics->send(p, true)) return false;
		return true;
	    } 
	    return result;
        }
    }else
	result = send_hotkey_reply(hics);
    return result;
}

bool
IIIMP_hotkey::send_hotkey_reply(
    IIIMP_ICState *hics
)
{
    IIIMP_message *p;
    p = iiimp_hotkey_notify_reply_new(hics->get_iiimptrans()->get_data_s(), hics->get_im_id(), hics->get_ic_id());   
    set_hotkey_mode(false);
    if (!hics->send(p, true)) return false;
    return true;
}

bool
IIIMP_hotkey::start_lang_selection_window(
    IIIMP_ICState *hics
)
{
    IMLangList *planglist = hics->get_langlist();
    IIIMP_message *p;

    p = iiimp_lookup_choice_start_new(hics->get_iiimptrans()->get_data_s(),
				      hics->get_im_id(),
				      hics->get_ic_id(),
				      IM_LOOKUP_CHOICE_START_SERVER_IS_MASTER,
				      planglist->size(),
				      planglist->size(),
				      1,
				      IM_LOOKUP_CHOICE_START_DRAWING_UP_HORIZONTALLY,
				      IM_LOOKUP_CHOICE_START_SERVER_OWNS_LABEL);
    if (!hics->send(p, true)) return false;
   
    hics->create_langimlist();

    return true;
}

void
IIIMP_hotkey::print_LangIMList(
    IIIMP_ICState *hics
)
{
    LangIMList::iterator it;
    LangIMList *plangimlist = hics->get_langimlist();

    for (it = plangimlist->begin (); it != plangimlist->end (); it++){
	u16string imname = it->get_hrn();
        if (imname.get_charstr() == NULL) {
	    imname  = it->get_imname();
        }
	LOG_DEBUG("Index [%d], Lang_ID [%s], IMName [%s]\n",it->get_index(), it->get_id(), imname.get_charstr());
    }
}

bool
IIIMP_hotkey::stop_lang_selection_window(
    IIIMP_ICState *hics
)
{
    IIIMP_message *p;
    p = iiimp_lookup_choice_done_new(hics->get_iiimptrans()->get_data_s(),
				     hics->get_im_id(),
				     hics->get_ic_id());
    if (!hics->send(p, true)) return false;
    return true;
}

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

int
IIIMP_hotkey::UTFCHARLen(
    const char *p
)
{
    int i;
    for (i = 0; *p; i++)
	p++;
    return i;
}

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

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

int 
IIIMP_hotkey::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
IIIMP_hotkey::UTFCHARCat(
    UTFCHAR *dest, 
    const char *str1, 
    const char *str2,
    const char *str3,
    const char *str4
)
{
    int i;
    for (i = 0; *str1; i++) { 
	*dest++ = *str1++;
    }
    for (i = 0; *str2; i++) {
	*dest++ = *str2++;
    }
    for (i = 0; *str3; i++) {
	*dest++ = *str3++;
    }
    for (i = 0; *str4; i++) {
	*dest++ = *str4++;
    }
    *dest = 0;
    return i;
} 

IMFeedbackList *
IIIMP_hotkey::create_feedback(
    int size
)
{
    int i;
    IMFeedbackList *feedback, *fbl;

    feedback = (IMFeedbackList *) calloc(size, sizeof(IMFeedbackList));
    for (i = 0; i < size; i++) {
	fbl = &feedback[i];
	fbl->count_feedbacks = 1;
	fbl->feedbacks = (IMFeedback *) calloc(4, sizeof(IMFeedback));
	memset(fbl->feedbacks, 0, sizeof(IMFeedback) * 4);
    }
    return feedback;
}

void
IIIMP_hotkey::free_feedback(
    IMFeedbackList *feedback,
    int size
)
{
    int i;
    IMFeedbackList *fbl;

    if (feedback == NULL) return;

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

bool
IIIMP_hotkey::process_lang_selection_window(
    IIIMP_ICState *hics,
    IIIMP_message *pmes
)
{
    IIIMP_contents *pc = pmes->v.forward_event.contents;
    IIIMP_keyevent *piiimpkey = pc->value.keyevent_list->keyevent;
    int keycode = piiimpkey->keycode;
    int index = 0;
    IIIMP_message *p;
    int hotkey_id = 0;

    hotkey_id = check_for_hotkey(hics, piiimpkey);

    if (hotkey_id) process_hotkey(hics, hotkey_id, 0);

    // print_LangIMList(hics);

    switch(keycode) {
      case IM_VK_PAGE_UP:
      case IM_VK_PAGE_DOWN:
      case IM_VK_SPACE:
      case IM_VK_DOWN:
      case IM_VK_UP:
      case IM_VK_LEFT:
      case IM_VK_RIGHT:
       draw_lang_selection_window(hics, keycode);
       break;

      case IM_VK_ENTER:
       index = current + 1;
       if (switch_language(hics, index, curr_hotkeyid)) return true;
       break;
      
      case IM_VK_1:
      case IM_VK_2:
      case IM_VK_3:
      case IM_VK_4:
      case IM_VK_5:
      case IM_VK_6:
      case IM_VK_7:
      case IM_VK_8:
      case IM_VK_9:
       index = first_candidate + ((piiimpkey->keychar - '0') % 10);
       if (switch_language(hics, index, curr_hotkeyid)) return true;
       break;
    }
    p = iiimp_forward_event_reply_new(hics->get_iiimptrans()->get_data_s(),
				      hics->get_im_id(),
				      hics->get_ic_id());
    if (!hics->send(p, true)) return false;
    set_forward_event(false);
    return true;
}

int
IIIMP_hotkey::check_for_hotkey(
    IIIMP_ICState *hics,
    IIIMP_keyevent *kev
)
{
    HotkeyProfileList::iterator it1;
    HotkeyProfileList *hkplist = const_cast<HotkeyProfileList *>(hics->get_hotkey_profile()->get_profile_list());
    HotkeyList::iterator it2;
    IMKeySpecList::iterator it3;
    int hotkey_id = 0;
    int i,j;

    for (it1 = hkplist->begin(); it1 != hkplist->end(); it1++) {
	HotkeyList *phklist = const_cast<HotkeyList *>(it1->get_hotkey_list());
	for (i = 0, it2 = phklist->begin(); it2 != phklist->end(), i < phklist->size(); it2++, i++) {
	    IMKeySpecList *keylist = const_cast<IMKeySpecList *>(it2->get_keylist());
	    for (j = 0, it3 = keylist->begin(); it3 != keylist->end(), j < keylist->size(); it3++, j++) {
		if ((kev->keycode == it3->get_keycode()) && (kev->modifier == it3->get_modifier())) {
		    return it2->get_hotkey_id();
		}
	    }
	}
    } 
    return hotkey_id;
}

bool
IIIMP_hotkey::switch_language(
    IIIMP_ICState *hics,
    int index,
    int hotkey_id
)
{
    IIIMP_message *p;
    LangIMList::iterator it;
    LangIMList *plangimlist = hics->get_langimlist();
    ICAttribute attr;
    bool result = false;

    for (it = plangimlist->begin (); it != plangimlist->end (); it++){
	if (index == it->get_index()) {
	    u16string imname = it->get_imname();
	    attr.set_inputlanguage(it->get_id());
	    attr.set_inputmethod(imname);
	    hics->get_ichandler()->set_icattr(attr);
	    if (get_lang_selection()) {
		set_lang_selection(false);
		result = hics->get_ichandler()->toggle_conversion(hics->get_imlexec(), true);
		hics->pshared->conversion_mode = true;
		if ((hics->start_request()->dealing()) && result) {
		    stop_lang_selection_window(hics);
		    p = iiimp_hotkey_state_notify_new(hics->get_iiimptrans()->get_data_s(), hics->get_im_id(), hics->get_ic_id(), hotkey_id, EVENT_FORWARDING_ON);
		    if (!hics->send(p, true)) return false;
		    return true;
		}
	    } 
	}
    }
    return false;
}

bool
IIIMP_hotkey::draw_lang_selection_window(
    IIIMP_ICState *hics,
    int kc
)
{
    IIIMP_message *p;
    IIIMP_text *pchoiceh, *pchoice;
    IIIMP_text *plabelh, *plabel;
    IIIMP_text *ptitle;
    IIIMP_text *pcur;
    IMText *title;
    IMText **vt;             /* for value */
    IMText **lt;             /* for label */
    LangIMList::iterator it;
    LangIMList *plangimlist;
    UTFCHAR title_string[] = {'S','W','I','T','C','H',' ','L','A','N','G',' ',' ',0};
    UTFCHAR *tmp_str;
    char label[16];
    char pos[16];
    int idx_first, idx_last, size;
    int i, j, k, l;
    bool flag = false;

    idx_first = idx_last = size = 0;
    pchoiceh = plabelh = ptitle = NULL;

    plangimlist = hics->get_langimlist();
    size = plangimlist->size();

    if (kc == 0) {
        first_candidate = 0;
        last_candidate = 8;
        current = 0;
        k = current;
    } 

    switch(kc) {
      case IM_VK_UP:
       if (last_candidate > size)
         last_candidate = size;
       if (current == first_candidate) {
	   current = last_candidate;
	   flag = true;
       } else
	   current -= 1;
       break;
      case IM_VK_DOWN:
      case IM_VK_SPACE:
       if (current == last_candidate)
	   current = first_candidate;
       else
	   current += 1;
       break;
      case IM_VK_PAGE_UP:
      case IM_VK_LEFT:
       idx_first = first_candidate - 9;
       if (idx_first >= 0) {
	   last_candidate = first_candidate -1;
	   first_candidate = idx_first;
	   current = first_candidate;
       }
       break;
      case IM_VK_PAGE_DOWN:
      case IM_VK_RIGHT:
       idx_first = first_candidate + 9;
       idx_last = last_candidate + 9;
       if (idx_first < size) {
	  first_candidate = idx_first;
          current = first_candidate;
       }
       if (idx_last <= size)
	   last_candidate = idx_last;
       else if (idx_last > size) 
	   last_candidate = size;
       break;
    }

    title = (IMText *)calloc(1, sizeof(IMText));
    (void)memset(pos, 0, 32);

    if (current < size) 
	k = current + 1;
    else if (current >= size) {
	if (!flag)
	    current = first_candidate;
	else 
	    current -= 1;
	k = current + 1;
    }
    l = size;
    snprintf((char *)pos,sizeof(pos),"%c%d%c%d%c",'[', k, '/', l, ']');
    title->char_length = UTFCHARLen(title_string) + strlen(pos);
    title->text.utf_chars = (UTFCHAR *) calloc((title->char_length + 1), sizeof(UTFCHAR));
    tmp_str = (UTFCHAR *) calloc ((strlen(pos) + 1), sizeof(UTFCHAR));
    UTFCHARCpy(tmp_str, pos);
    UTFCHARCat(title->text.utf_chars, title_string, tmp_str);
    title->feedback = create_feedback(title->char_length);
    ptitle = convert_IMText_to_iiimp_text(hics->get_iiimptrans()->get_data_s(), title);
  
    if (title) free(title);
    if (tmp_str) free(tmp_str);

    vt = (IMText **)calloc(size, sizeof(IMText *));
    lt = (IMText **)calloc(size, sizeof(IMText *));

    for (i = 0, it = plangimlist->begin(); i < plangimlist->size(); it++,i++) {
        int tmpstr_len = 0;
        u16string imname  = it->get_hrn();

        if (imname.get_charstr() == NULL) {
	    imname  = it->get_imname();
        }

        vt[i] = (IMText *)calloc(1, sizeof(IMText));
        vt[i]->char_length = UTFCHARLen(imname.get_charstr()) + 3 + UTFCHARLen(it->get_id());
        vt[i]->text.utf_chars = (UTFCHAR *) calloc((vt[i]->char_length + 1), sizeof(UTFCHAR));

        UTFCHARCat(vt[i]->text.utf_chars, it->get_id(), " (", imname.get_charstr(), ")");
        vt[i]->feedback = create_feedback(vt[i]->char_length);

        // Value
        pcur = convert_IMText_to_iiimp_text(hics->get_iiimptrans()->get_data_s(), vt[i]);
        if (!pchoiceh) {
	    pchoiceh = pcur;
        }else{
	    pchoice->next = pcur;
        }
        pchoice = pcur;

        lt[i] = (IMText *)calloc(1, sizeof(IMText));
        (void)memset(label, 0, 32);
        lt[i]->char_length = 3;
        lt[i]->text.utf_chars = (UTFCHAR *) calloc((lt[i]->char_length + 1), sizeof(UTFCHAR));
        if (i > 8) {
	    j = i % 9;
	    snprintf((char *)label,sizeof(label),"%d%c%c",j+1,'.',' ');
        } else {
	    snprintf((char *)label,sizeof(label),"%d%c%c",i+1,'.',' ');
        }
        UTFCHARCpy(lt[i]->text.utf_chars, label);
        lt[i]->feedback = create_feedback(lt[i]->char_length);

        // Label
        pcur = convert_IMText_to_iiimp_text(hics->get_iiimptrans()->get_data_s(), lt[i]);
        if (!plabelh) {
            plabelh = pcur;
        } else {
            plabel->next = pcur;
        }
        plabel = pcur;
    }
 
    p = iiimp_lookup_choice_draw_new(hics->get_iiimptrans()->get_data_s(),
				     hics->get_im_id(),
				     hics->get_ic_id(),
				     first_candidate,
				     last_candidate,
				     current,
				     pchoiceh,
				     plabelh,
				     ptitle);
    if (!hics->send(p, true)) return false;
    return true;
}

/* Local Variables: */
/* c-file-style: "iiim-project" */
/* End: */
