#include <config.h>
#include <stdio.h>
#include <vector>
#include <SunIM.h>
#include "IMBasicObject.hh"
#include "IMKeyUtils.hh"
#include "IMHotkeyPrimitive.hh"
#include "IIIMP_hotkey_profile.hh"
#include "IIIMP_IMState.hh"

IMHotkey::IMHotkey(
    int a_id, 
    const IMHotkeyStruct& a_hk,
    const u16string& a_label
): label(a_label){
    state_flag = a_hk.state_flag;
    action_flag = a_hk.action_flag;
    hotkey_id = a_id;

    for (int i = 0; i < a_hk.nkeys; i++)
	keys.push_back(IMKeySpec(a_hk.keys[i].keyCode, a_hk.keys[i].keyChar,
				 a_hk.keys[i].modifier, a_hk.keys[i].time_stamp));
}

// Passing the latest hk_id in constructor so that hotkey_id's
// can be unique across all the hotkey profiles

IMHotkeyProfile::IMHotkeyProfile(
    int a_id,
    int hk_id,
    const IMHotkeyProfileStruct *hkps
)
{
    if (a_id == 0) {
	// Clear the hklist when adding the first hotkey profile
	hklist.clear();
    }

    hotkey_profile_struct = hkps;
    for (int i = 0; i < hkps->num_hotkeys; i++) {
        u16string label = "Default Hotkey Label";
	// what shall we do with hkps->scope?
	if ((hkps->hks[i].label) && (strlen(hkps->hks[i].label))) {
	  label = u16string(hkps->hks[i].label); 
        }
	hklist.push_back(IMHotkey(hk_id + i, hkps->hks[i], label));
    }
    profile_id = a_id;
}

IIIMP_hotkey_profile::IIIMP_hotkey_profile(
)
{
    default_hotkey_profile_id = 0;
    default_hotkey_trigger_notify_id = 0;
    default_hotkey_lang_switch_id = 0;
    default_hotkey_cycle_lang_switch_id = 0;
    default_hotkey_reverse_cycle_lang_switch_id = 0;
    default_hotkey_super_help_id = 0;
}

IMHotkeyStruct *
IIIMP_hotkey_profile::get_super_hotkeys(const IMKeySpecList &triggerkeys,
					const char          *language,
					int                 *count_hotkeys)
{
    IMHotkeyStruct *hks = NULL;
    HotKeyList *hlist = NULL;
    IMKeyEventStruct *kev;
    int n_keys = 0, n_hotkeys = 0;
    IMKeySpecList::const_iterator it;

    hks = new IMHotkeyStruct[4];

    // lang switch
    kev = new IMKeyEventStruct[2];
    n_keys = 0;
    kev[n_keys].keyCode = IM_VK_SPACE;
    kev[n_keys].keyChar = 0;
    kev[n_keys].modifier = IM_CTRL_MASK|IM_ALT_MASK;
    kev[n_keys].time_stamp = 0;
    n_keys++;
    kev[n_keys].keyCode = IM_VK_SPACE;
    kev[n_keys].keyChar = 0;
    kev[n_keys].modifier = IM_CTRL_MASK|IM_SHIFT_MASK;
    kev[n_keys].time_stamp = 0;
    n_keys++;

    hks[n_hotkeys].label = strdup("LE SWITCH");
    hks[n_hotkeys].state_flag = 0;
    hks[n_hotkeys].action_flag = 1;
    hks[n_hotkeys].nkeys = n_keys;
    hks[n_hotkeys].keys = kev;
    n_hotkeys++;

    // trigger keys
    kev = new IMKeyEventStruct[triggerkeys.size()];

    for (it = triggerkeys.begin(), n_keys = 0; it != triggerkeys.end(); it++, n_keys++) {
	kev[n_keys].keyCode = it->get_keycode();
	kev[n_keys].keyChar = it->get_keychar();
	kev[n_keys].modifier = it->get_modifier();
	kev[n_keys].time_stamp = it->get_timestamp();
    }

    hks[n_hotkeys].label = strdup("TRIGGER KEYS");
    hks[n_hotkeys].state_flag = 0;
    hks[n_hotkeys].action_flag = 1;
    hks[n_hotkeys].nkeys = n_keys;
    hks[n_hotkeys].keys = kev;
    n_hotkeys++;

    // cycle lang switch
    kev = new IMKeyEventStruct[1];
    n_keys = 0;
    kev[n_keys].keyCode = IM_VK_GREATER;
    kev[n_keys].keyChar = 0;
    kev[n_keys].modifier = IM_SHIFT_MASK|IM_CTRL_MASK;
    kev[n_keys].time_stamp = 0;
    n_keys++;

    hks[n_hotkeys].label = strdup("CYCLE LE SWITCH");
    hks[n_hotkeys].state_flag = 0;
    hks[n_hotkeys].action_flag = 1;
    hks[n_hotkeys].nkeys = n_keys;
    hks[n_hotkeys].keys = kev;
    n_hotkeys++;

    // cycle lang switch (reverse)
    kev = new IMKeyEventStruct[1];
    n_keys = 0;
    kev[n_keys].keyCode = IM_VK_LESS;
    kev[n_keys].keyChar = 0;
    kev[n_keys].modifier = IM_SHIFT_MASK|IM_CTRL_MASK;
    kev[n_keys].time_stamp = 0;
    n_keys++;

    hks[n_hotkeys].label = strdup("CYCLE LE SWITCH(reverse)");
    hks[n_hotkeys].state_flag = 0;
    hks[n_hotkeys].action_flag = 1;
    hks[n_hotkeys].nkeys = n_keys;
    hks[n_hotkeys].keys = kev;
    n_hotkeys++;

    *count_hotkeys = n_hotkeys;

    return hks;
}

bool
IIIMP_hotkey_profile::add_super_hotkey_profiles(
    const u16string &curr_input_lang,
    const IMHotkeyStruct *hotkeys,
    int n_hotkeys
)
{
    IMHotkeyList hklist;
    int curr_hotkey_id, i, j;
    const char *function_ids[] = {
	"LE SWITCH",
	"TRIGGER KEYS",
	"CYCLE LE SWITCH",
	"CYCLE LE SWITCH(reverse)",
	NULL,
    };

    // Hack to get the latest hotkey_id which we can use for
    // setting the unique default_hotkey_lang_switch_id and
    // default_hotkey_trigger_notify_id 

    IMHotkeyProfileList::const_iterator it1 = profile_list.begin();
    for (curr_hotkey_id = 0 ; it1 != profile_list.end(); ++it1) {
        curr_hotkey_id += (it1->get_hotkey_list())->size();
    }

    for (i = 0; i < n_hotkeys; i++) {
	for (j = 0; function_ids[j] != NULL; j++) {
	    if (!strcmp(hotkeys[i].label, function_ids[j])) {
		hklist.push_back(IMHotkey(curr_hotkey_id, hotkeys[i], u16string(hotkeys[i].label)));
		switch (j) {
		case 0: /* LE SWITCH */
		    default_hotkey_lang_switch_id = curr_hotkey_id;
		    j = (sizeof (function_ids) / sizeof (char *)) - 2;
		    break;
		case 1: /* TRIGGER KEYS */
		    default_hotkey_trigger_notify_id = curr_hotkey_id;
		    j = (sizeof (function_ids) / sizeof (char *)) - 2;
		    break;
		case 2: /* CYCLE LE SWITCH */
		    default_hotkey_cycle_lang_switch_id = curr_hotkey_id;
		    j = (sizeof (function_ids) / sizeof (char *)) - 2;
		    break;
		case 3: /* CYCLE LE SWITCH(reverse) */
		    default_hotkey_reverse_cycle_lang_switch_id = curr_hotkey_id;
		    j = (sizeof (function_ids) / sizeof (char *)) - 2;
		    break;
		default:
		    LOG_DEBUG("Unknown function id: %s", hotkeys[i].label);
		    curr_hotkey_id--;
		    break;
		}
		curr_hotkey_id++;
	    }
	}
    }
    default_hotkey_profile_id = profile_list.size();
    profile_list.push_back(IMHotkeyProfile(profile_list.size(), hklist));

    // crack
    merge_default_hotkeys (hklist);

    return True;
}

IIIMP_hotkey_profile::~IIIMP_hotkey_profile()
{
    LOG_DEBUG("IIIMP_hotkey_profile destructor \n");
    // profile_list.clear();
}

const int
IIIMP_hotkey_profile::get_unique_profile_id(
    int le_profile_id,
    IMLEName *lename
)
{
    HotkeyProfileMap::iterator it;

    for (it = hotkey_profile_map.begin(); it != hotkey_profile_map.end(); ++it) {
      IMHotkeyProfileStruct *hkps = it->second;
      if ((hkps->name->id == lename->id) && (hkps->profile_id == le_profile_id)) {
        return it->first;
      }
   }
   return -1;
}

void
IIIMP_hotkey_profile::merge_default_hotkeys(IMHotkeyList &phklist)
{
    IMHotkeyProfileList::iterator it1 = profile_list.begin();

    for (; it1 != profile_list.end(); ++it1) {
	if (it1->get_profile_id() == default_hotkey_profile_id)
	    continue;
	IMHotkeyList *hkl = it1->get_hotkey_list();
        IMHotkeyList::iterator it2 = phklist.begin();
	for (; it2 != phklist.end(); ++it2)
	    hkl->push_back(*it2);
    }
}

bool
IIIMP_hotkey_profile::init_hotkey_profile_list(IMHotkeyProfileStruct *hkps,
					       int count_profiles)
{
    IMHotkeyProfileStruct *p;
    int curr_hotkey_id = 0;
    profile_list.clear();

    hotkey_profile_map.clear();
    if (hkps) {
	for (p = hkps; p < &hkps[count_profiles]; p++) {
	    if (p != NULL) {
                hotkey_profile_map.insert(make_pair(profile_list.size(), p));
		profile_list.push_back(IMHotkeyProfile(profile_list.size(), curr_hotkey_id, p));
	    }
	    // 1. Hack to assign unique hotkey_ids for hotkey's under
	    //    hotkey profiles registered by all LEs.
	    // 2. Get the latest hotkey_id from the hotkey profiles added
	    //    so far and pass it IMHotkeyProfile constructor

	    curr_hotkey_id = 0;
            for (IMHotkeyProfileList::iterator it = profile_list.begin();
                 it != profile_list.end();
                 ++it)
            {
                curr_hotkey_id += it->get_hotkey_list()->size();
	    }
	}
    }

    return True;
}

int
IIIMP_hotkey_profile::register_hotkeys(
    void* register_id,
    IMHotkeyList *hklist  
)
{
    // TODO ...
    // return profile_id
    return -1;
}

const IMKeySpecList *
IIIMP_hotkey_profile::retrieve_trigger_keys(int profile_id)
{
    int i, j;

    for (IMHotkeyProfileList::iterator it1 = profile_list.begin();
	 it1 != profile_list.end(); it1++) {
	if (it1->get_profile_id() == default_hotkey_profile_id) {
	    IMHotkeyList *phklist = it1->get_hotkey_list();
	    IMHotkeyList::iterator it2;

	    for (i = 0, it2 = phklist->begin(); it2 != phklist->end(), i < phklist->size(); it2++, i++) {
		if (it2->get_hotkey_id() == default_hotkey_trigger_notify_id) {
		    return it2->get_keylist();
		}
	    }
	}
    }
    return NULL;
}

HOTKEY_LIST* 
IIIMP_hotkey_profile::retrive_hotkeys(
    IIIMP_data_s *pdata_s,
    int count,
    int *profile_id
)
{
    IMHotkeyList::iterator it2; 
    IMKeySpecList::iterator it3;
    HOTKEY *hk;
    HOTKEY_LIST *hklist;
    IIIMP_keyevent *keys;
    size_t n, i, j;
    u16string label;

    IMHotkeyProfileList::iterator it1 = profile_list.begin();
    n = count;
    while (n-- > 0)
	it1++;

    *profile_id = it1->get_profile_id();
    IMHotkeyList *phklist = it1->get_hotkey_list();
    hk = new HOTKEY[phklist->size()];
    for (i = 0, it2 = phklist->begin(); it2 != phklist->end(), i < phklist->size(); it2++, i++) {
	hk[i].hotkeyctrl.hotkey_id = it2->get_hotkey_id();
	hk[i].hotkeyctrl.state_flag = it2->get_state_flag();
	hk[i].hotkeyctrl.action_flag = it2->get_action_flag();

	IMKeySpecList *keylist = it2->get_keylist();
	keys = new IIIMP_keyevent[keylist->size()];

	for (j = 0, it3 = keylist->begin(); it3 != keylist->end(), j < keylist->size(); it3++, j++) {
	    keys[j].keycode = it3->get_keycode();
	    keys[j].keychar = it3->get_keychar();
	    keys[j].modifier = it3->get_modifier();
	    keys[j].time_stamp = it3->get_timestamp();
	}
	hk[i].hotkeylist = iiimp_keyevent_list_new(pdata_s, keylist->size(), keys);
	delete[] keys;
	if (!hk[i].hotkeylist) {
	    if (hk[i].hotkeylist) iiimp_keyevent_list_delete(pdata_s, hk[i].hotkeylist);
	    return NULL;
	}

	label = it2->get_label();
	hk[i].label = iiimp_string_new(pdata_s, label.size(), label.data());
    }
    hklist = iiimp_hotkey_list_new(pdata_s, phklist->size(), hk);
    delete[] hk;
    return hklist;
}

void* 
IIIMP_hotkey_profile::get_registerer_id_by_profile_id(
    int profile_id
)
{
    return NULL;
}

void* 
IIIMP_hotkey_profile::get_profile_id_by_registerer_id(
    void* registerer_id
)
{
    return NULL;
}

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