#include <../source/TAL/objbase.h>

#include <../source/TAL/utables/latin1.c>

#ifdef	CONFIG_KOI8R_TABLE
#include <../source/TAL/utables/koi8_r.c>
#endif	/* CONFIG_KOI8R_TABLE */

#ifdef	CONFIG_CP866_TABLE
#include <../source/TAL/utables/cp866.c>
#endif	/* CONFIG_CP866_TABLE */

#ifdef	CONFIG_WIN1251_TABLE
#include <../source/TAL/utables/win1251.c>
#endif	/* CONFIG_WIN1251_TABLE */

#include <../source/TAL/utables/uc_alias.c>

V_LOCAL uc_charmap_desc_t known_uc_charmaps[] =
{
	{"latin1",latin1_ccd}, /* should be the first one */

#ifdef	CONFIG_KOI8R_TABLE
	{"koi8-r",koi8_r_ccd},
#endif	/* CONFIG_KOI8R_TABLE */

#ifdef	CONFIG_CP866_TABLE
	{"cp866",cp866_ccd},
#endif	/* CONFIG_CP866_TABLE */

#ifdef	CONFIG_WIN1251_TABLE
	{"win1251",win1251_ccd},
#endif	/* CONFIG_WIN1251_TABLE */

	{NULL,NULL}
};

uc_charmap_desc_p V_GLOBAL
ucGetCharmap(int cmap_num)
{
	int i;
	/*
	 * Not very optimal...
	 */
	for(i = 0;known_uc_charmaps[i].name;i++)
		if(i == cmap_num)
			return &known_uc_charmaps[i];
	return NULL;
}

uc_char_desc_p V_GLOBAL
ucFindAscii(uc_charmap_desc_p cmap,u32_t acode)
{
	CALLER_NAME(ucFindAscii)
	uc_char_desc_p head;
	if(!cmap)
	{
		ERROR_GENERIC(error_incorrect_parameters);
		return NULL;
	}
	head = cmap->desc;
	for(;head->name;head++)
		if(head->acode == acode)
			return head;
	return NULL;
}

uc_char_desc_p V_GLOBAL
ucFindUnicode(uc_charmap_desc_p cmap,u32_t ucode)
{
	CALLER_NAME(ucFindUnicode)
	uc_char_desc_p head;
	if(!cmap)
	{
		ERROR_GENERIC(error_incorrect_parameters);
		return NULL;
	}
	head = cmap->desc;
	for(;head->name;head++)
		if(head->ucode == ucode)
			return head;
	return NULL;
}

char_p	V_GLOBAL
ucCharName(u32_t ucode)
{
	int i;
	uc_char_desc_p cd;
	STATIC_STRING(noname,"UNKNOWN")
	if(ucode < 0x80)
	{
		cd = ucFindAscii(known_uc_charmaps,ucode);
		if(!cd)
			return noname;
		return cd->name;
	}
	for(i = 1;known_uc_charmaps[i].name;i++)
	{
		cd = ucFindUnicode(known_uc_charmaps + i,ucode);
		if(cd)
			return cd->name;
	}
	return noname;
}

uc_char_desc_p V_GLOBAL
ucFindUnicodeOrAlias(uc_charmap_desc_p target_cmap,u32_t uc_orig)
{
	CALLER_NAME(ucFindUnicodeOrAlias)
	u32_t i;
	uc_alias_list_p alist;
	uc_char_desc_p dest;
	if(!target_cmap)
	{
		ERROR_GENERIC(error_incorrect_parameters);
		return NULL;
	}
	dest = ucFindUnicode(target_cmap,uc_orig);
	if(dest)
		return dest;
	alist = uni_aliases;
	for(;alist->num_alias;alist++)
	{
		if(alist->ucode != uc_orig)
			continue;
		/* found alias for uc_orig */
		for(i = 0;i < alist->num_alias;i++)
		{
			if(alist->alias[i] < 0x80) /* can be replaced by ASCII */
				dest = ucFindAscii(known_uc_charmaps,alist->alias[i]);
			if(dest)
				return dest;
			dest = ucFindUnicode(target_cmap,alist->alias[i]);
			if(dest)
				return dest;
		}
	}
	return NULL;
}

#define	CHAR_UNKNOWN	'?'

vboolean V_GLOBAL
ucAscii2AsciiTable(char_p src_cmap_name,char_p dst_cmap_name,
	u8_t transtab_ret[])
{
	CALLER_NAME(ucAscii2AsciiTable)
	u32_t i;
	uc_charmap_desc_p src_map = NULL, dst_map = NULL;
	uc_char_desc_p cd;
	if(!src_cmap_name || !dst_cmap_name || !transtab_ret)
	{
		ERROR_GENERIC(error_incorrect_parameters);
		return false;
	}
	for(i = 0;known_uc_charmaps[i].name;i++)
	{
		if(!strcmp(known_uc_charmaps[i].name,src_cmap_name))
			src_map = &known_uc_charmaps[i];
		if(!strcmp(known_uc_charmaps[i].name,dst_cmap_name))
			dst_map = &known_uc_charmaps[i];
	}
	if(!src_map)
	{
		ERROR_GENERIC("unknown source map");
		return false;
	}
	if(!dst_map)
	{
		ERROR_GENERIC("unknown destination map");
		return false;
	}
	/* lower part: one-to-one correspondence */
	for(i = 0;i < 0x80;i++)
		transtab_ret[i] = (u8_t)i;
	if(src_map == dst_map)
	{
		for(i = 0x80;i < 0xFF;i++)
			transtab_ret[i] = (u8_t)i;
		return true;
	}
	for(i = 0x80;i < 0xFF;i++)
	{
		cd = ucFindAscii(src_map,i);
		if(!cd)
		{
			transtab_ret[i] = CHAR_UNKNOWN;
			continue;
		}
		cd = ucFindUnicodeOrAlias(dst_map,cd->ucode);
		if(!cd)
			transtab_ret[i] = CHAR_UNKNOWN;
		else
			transtab_ret[i] = (u8_t)cd->acode;
	}
	return true;
}

/*
 * UI - helper routine: converts LibV-specific scan code
 * to (human-readable) LibV-specific scan name.
 */
char_p	V_GLOBAL
uiKeyscan2Name(unsigned scan)
{
	char *name;

#define	MATCH_SCAN(scan_name) \
	case sc_##scan_name: name = #scan_name; break;

	switch(scan)
	{
		MATCH_SCAN(escape)
		MATCH_SCAN(f1)
		MATCH_SCAN(f2)
		MATCH_SCAN(f3)
		MATCH_SCAN(f4)
		MATCH_SCAN(f5)
		MATCH_SCAN(f6)
		MATCH_SCAN(f7)
		MATCH_SCAN(f8)
		MATCH_SCAN(f9)
		MATCH_SCAN(f10)
		MATCH_SCAN(f11)
		MATCH_SCAN(f12)
		MATCH_SCAN(print)
		MATCH_SCAN(scroll_lock)
		MATCH_SCAN(pause)

		MATCH_SCAN(grave)
		MATCH_SCAN(1)
		MATCH_SCAN(2)
		MATCH_SCAN(3)
		MATCH_SCAN(4)
		MATCH_SCAN(5)
		MATCH_SCAN(6)
		MATCH_SCAN(7)
		MATCH_SCAN(8)
		MATCH_SCAN(9)
		MATCH_SCAN(0)
		MATCH_SCAN(minus)
		MATCH_SCAN(equal)
		MATCH_SCAN(backslash)
		MATCH_SCAN(backspace)

		MATCH_SCAN(tab)
		MATCH_SCAN(q)
		MATCH_SCAN(w)
		MATCH_SCAN(e)
		MATCH_SCAN(r)
		MATCH_SCAN(t)
		MATCH_SCAN(y)
		MATCH_SCAN(u)
		MATCH_SCAN(i)
		MATCH_SCAN(o)
		MATCH_SCAN(p)
		MATCH_SCAN(lbracket)
		MATCH_SCAN(rbracket)
		MATCH_SCAN(enter)

		MATCH_SCAN(caps_lock)
		MATCH_SCAN(a)
		MATCH_SCAN(s)
		MATCH_SCAN(d)
		MATCH_SCAN(f)
		MATCH_SCAN(g)
		MATCH_SCAN(h)
		MATCH_SCAN(j)
		MATCH_SCAN(k)
		MATCH_SCAN(l)
		MATCH_SCAN(semicolon)
		MATCH_SCAN(apostrophe)

		MATCH_SCAN(lshift)
		MATCH_SCAN(z)
		MATCH_SCAN(x)
		MATCH_SCAN(c)
		MATCH_SCAN(v)
		MATCH_SCAN(b)
		MATCH_SCAN(n)
		MATCH_SCAN(m)
		MATCH_SCAN(comma)
		MATCH_SCAN(period)
		MATCH_SCAN(slash)
		MATCH_SCAN(rshift)

		MATCH_SCAN(lcontrol)
		MATCH_SCAN(lsuper)
		MATCH_SCAN(lalt)
		MATCH_SCAN(space)
		MATCH_SCAN(ralt)
		MATCH_SCAN(rsuper)
		MATCH_SCAN(menu)
		MATCH_SCAN(rcontrol)

		MATCH_SCAN(insert)
		MATCH_SCAN(home)
		MATCH_SCAN(prior)
		MATCH_SCAN(delete)
		MATCH_SCAN(end)
		MATCH_SCAN(next)

		MATCH_SCAN(up)
		MATCH_SCAN(down)
		MATCH_SCAN(left)
		MATCH_SCAN(right)

		MATCH_SCAN(num_lock)
		MATCH_SCAN(kp_slash)
		MATCH_SCAN(kp_multiply)
		MATCH_SCAN(kp_subtract)
		MATCH_SCAN(kp_home)
		MATCH_SCAN(kp_up)
		MATCH_SCAN(kp_prior)
		MATCH_SCAN(kp_add)
		MATCH_SCAN(kp_left)
		MATCH_SCAN(kp_begin)
		MATCH_SCAN(kp_right)
		MATCH_SCAN(kp_end)
		MATCH_SCAN(kp_down)
		MATCH_SCAN(kp_next)
		MATCH_SCAN(kp_enter)
		MATCH_SCAN(kp_insert)
		MATCH_SCAN(kp_delete)

		MATCH_SCAN(lbutton)
		MATCH_SCAN(mbutton)
		MATCH_SCAN(rbutton)

		MATCH_SCAN(wheelup)
		MATCH_SCAN(wheeldown)

		default: name = "unknown";
	}
	return name;

#undef	MATCH_SCAN
}

/*
 * UI - helper routine: converts LibV-specific scan name
 * to LibV-specific scan code.
 */
unsigned V_GLOBAL
uiName2Keyscan(char *name)
{
	unsigned code;
	if(!name || !*name)
		return sc_unknown;
	for(code = 0;code < sc_maxcode;code++)
		if(!strcasecmp(name,uiKeyscan2Name(code)))
			return code;
	return sc_unknown;
}
