/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program 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.

**********************************************************************/


#include	"memory_debug.h"
#include	"long_char.h"


CODE_TABLE_HEADER *	ct_root;

CODE_TABLE_HEADER *
get_code_table_by_lcz(L_CHAR lcz)
{
CODE_TABLE_HEADER * ct;
int i;
CODE_ENTRY * e;
	for ( ct = ct_root ; ct ; ct = ct->next )
		if ( ct->lcz == lcz )
			return ct;
	ct = d_alloc(sizeof(*ct));
	ct->lcz = lcz;
	ct->mask = get_lc_mask(lcz);
	ct->len = - ct->mask;
	ct->tbl = d_alloc(ct->len * sizeof(CODE_ENTRY));
	for ( i = 0 ;  i < ct->len ; i ++ ) {
		e = &ct->tbl[i];
		e->code = ct->lcz|i;
		e->co = e;
	}
	ct->next = ct_root;
	ct_root = ct;
	return ct;
}

CODE_TABLE_HEADER *
get_code_table_by_char(L_CHAR a)
{
CODE_TABLE_HEADER * ct;
	for ( ct = ct_root ; ct ; ct = ct->next )
		if ( (ct->lcz & ct->mask) == (a & ct->mask) )
			return ct;
	return 0;
}

int
col_code_entry(CODE_ENTRY * ce1,CODE_ENTRY * ce2)
{
CODE_ENTRY * _ce1, * _ce2;
L_CHAR m1,m2;
	for ( _ce1 = ce1 ; ; _ce1 = _ce1->co ) {
		for ( _ce2 = ce2 ; ; _ce2 = _ce2->co ) {
			m1 = get_lc_mask(_ce1->code);
			m2 = get_lc_mask(_ce2->code);
			if ( m1 != m2 )
				goto next;
			if ( (m1 & _ce1->code) == (m1 & _ce2->code) )
				return 1;
		next:
			if ( _ce2 == ce2 )
				break;
		}
		if ( _ce1 == ce1 )
			break;
	}
	return 0;
}

void
marge_code_entry(CODE_ENTRY * e1,CODE_ENTRY * e2)
{
CODE_ENTRY * e1_next, * e2_next;
	e1_next = e1->co;
	e2_next = e2->co;
	e1->co = e2_next;
	e2->co = e1_next;
}

void
set_correspond(L_CHAR a,L_CHAR b)
{
CODE_TABLE_HEADER * ct_a,* ct_b;
CODE_ENTRY * a_e,* b_e, * e;

	ct_a = get_code_table_by_char(a);
	ct_b = get_code_table_by_char(b);
	if ( ct_a == 0 || ct_b == 0 )
		er_panic("set_correspond");

	a_e = &ct_a->tbl[(~ct_a->mask) & a];
	b_e = &ct_b->tbl[(~ct_b->mask) & b];
	if ( col_code_entry(a_e,b_e) == 1 )
		return;
	marge_code_entry(a_e,b_e);
}


L_CHAR
code_convert(L_CHAR from,L_CHAR lcz)
{
CODE_ENTRY * e, * ep;
CODE_TABLE_HEADER * ct;
L_CHAR mask;
	switch ( lcz ) {
	case 0:
	case LCZ_2BC_UNICODE_v3_0_UN:
	case LCZ_2BC_UNICODE_v3_0_JP:
	case LCZ_2BC_UNICODE_v3_0_TW:
	case LCZ_2BC_UNICODE_v3_0_KR:
	case LCZ_2BC_UNICODE_v3_0_CN:
		ct = get_code_table_by_char(LCZ_2BC_UNICODE_v3_0_UN);
		if ( ct ) {
			lcz = LCZ_2BC_UNICODE_v3_0_UN;
			break;
		}
	case LCZ_2BC_UNICODE_v2_0_UN:
	case LCZ_2BC_UNICODE_v2_0_JP:
	case LCZ_2BC_UNICODE_v2_0_TW:
	case LCZ_2BC_UNICODE_v2_0_KR:
	case LCZ_2BC_UNICODE_v2_0_CN:
		ct = get_code_table_by_char(LCZ_2BC_UNICODE_v2_0_UN);
		if ( ct ) {
			lcz = LCZ_2BC_UNICODE_v2_0_UN;
			break;
		}
	case LCZ_2BC_UNICODE_v1_1_UN:
	case LCZ_2BC_UNICODE_v1_1_JP:
	case LCZ_2BC_UNICODE_v1_1_TW:
	case LCZ_2BC_UNICODE_v1_1_KR:
	case LCZ_2BC_UNICODE_v1_1_CN:
		ct = get_code_table_by_char(LCZ_2BC_UNICODE_v1_1_UN);
		if ( ct ) {
			lcz = LCZ_2BC_UNICODE_v1_1_UN;
			break;
		}
		er_panic("code_convert");
	}
	ct = get_code_table_by_char(from);
	if ( ct == 0 )
		return LCC_ERROR;
	e = &ct->tbl[ct->mask & from];
	mask = get_lc_mask(lcz);
	for ( ep = e ; ; ep = ep->co ) {
		if ( (ep->code & mask) == (lcz & mask) )
			return ep->code;
		if ( ep == e )
			break;
	}
	return LCC_ERROR;
}

