/*
 * Copyright (c) 1991-1994  Sony Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL SONY CORPORATION BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the name of Sony Corporation
 * shall not be used in advertising or otherwise to promote the sale, use
 * or other dealings in this Software without prior written authorization
 * from Sony Corporation.
 *
 */

/*
 * $SonyRCSfile: mkkouho.c,v $
 * $SonyRevision: 1.1 $
 * $SonyDate: 1994/06/03 08:02:04 $
 */

#include "sj_euc.h"
#include "sj_kcnv.h"
#include "sj_hinsi.h"
#include "sj_suuji.h"
#include "sj_dict.h"

#include "sj_kanakan.h"

static void    getkhtbl(SJ4_CONTEXT CLREC*), cl_kanji(SJ4_CONTEXT JREC*, CLREC*);
static int     diffknj(SJ4_CONTEXT JREC*, u_char*, int);
static void    cl_numcmn(SJ4_CONTEXT JREC*, CLREC*);
static u_char* makekan(SJ4_CONTEXT u_char*, u_char*, int);

void mkkouho(SJ4_CONTEXT2) {
	CLREC* clrec;
	int    keeplen;

	khcount = nkhcount = 0;

	keeplen = clt1st->cllen;

	clrec = clt1st;

	do {
		getkhtbl(SJ4_CONTEXT_PASS clrec);
		clrec = clrec->clsort;
	} while(clrec && (keeplen == clrec->cllen));
}

static void
getkhtbl(SJ4_CONTEXT CLREC* clrec) {
	JREC* jrec;

	jrec = clrec->jnode;

	switch(jrec->jclass) {
	case C_DICT:
		cl_kanji(SJ4_CONTEXT_PASS jrec, clrec);
		break;
	case C_N_ARABIA:
	case C_N_ARACMA:
	case C_N_KAZU:
	case C_N_SUUJI:
	case C_N_NANSUU:
	case C_N_KANKURA:
	case C_N_ARAKURA:
	case C_N_KAZULONG:
	case C_N_KAZULCMA:
	case C_N_SUUJILONG:
		cl_numcmn(SJ4_CONTEXT_PASS jrec, clrec);
		break;
	case C_BUNSETU:
		break;
	case C_MINASI:
	case C_WAKACHI:
		setkouho(SJ4_CONTEXT_PASS clrec, (TypeDicOfs)0, 0);
		break;
	}
}

static void
cl_kanji(SJ4_CONTEXT JREC* jrec, CLREC* clrec) {
	u_char* ptr;
	int	kcount = khcount;

	if(seldict(SJ4_CONTEXT_PASS jrec->dicid)) {
		(*curdict->getdic)(SJ4_CONTEXT_PASS curdict, jrec->jseg);
		ptr = dicbuf + jrec->jofsst + 1;

		get_askknj(SJ4_CONTEXT_PASS2);

		while(*ptr != HINSIBLKTERM) {
			if(diffknj(SJ4_CONTEXT_PASS jrec, ptr, kcount)) {
				setkouho(SJ4_CONTEXT_PASS clrec, (TypeDicOfs)(ptr - dicbuf), 0);
			}
			ptr = skipkstr(ptr);
		}
	} else {
		setkouho(SJ4_CONTEXT_PASS clrec, (TypeDicOfs)1, 0);
	}
}

u_char*
makekan_none(SJ4_CONTEXT u_char* s, u_char* d, int flg) {
	return d;
}

u_char*
makekan_1byte(SJ4_CONTEXT u_char* s, u_char* d, int flg) {
	if((*s & KANJIMODEMASK) == ZENHIRAASSYUKU)
		*d++ = 0x10 | (*s & KNJASSYUKUMASK);
	else
		*d++ = 0x90 | (*s & KNJASSYUKUMASK);

	if(flg) *d++ = KANJISTREND;
	return d;
}

u_char*
makekan_knj(SJ4_CONTEXT u_char* s, u_char* d, int flg) {
	return makekan(SJ4_CONTEXT_PASS askknj[*s & KNJASSYUKUMASK], d, flg);
}

u_char* makekan_ofs(SJ4_CONTEXT u_char* s, u_char* d, int flg) {
	return makekan(SJ4_CONTEXT_PASS dicbuf + ((*s & KANJICODEMASK) << 8) + *(s + 1),
		       d, flg);
}

u_char*
makekan_norm(SJ4_CONTEXT u_char* s, u_char* d, int flg) {
	u_char c;

	if(*s != 0) {
		c = s[1];
		if(c & 0x80)
			*d++ = SS3;
		*d++ = *s | 0x80;
		*d++ = c | 0x80;
	} else {
		*d++ = *s;
	}
	if(flg) *d++ = KANJISTREND;
	return d;
}

u_char*
makekan_ascii(SJ4_CONTEXT u_char* s, u_char* d, int flg) {
	u_char c;

	c = s[1];
	if(c & 0x80)
		*d++ = SS2;
	*d++ = c;

	if(flg) *d++ = KANJISTREND;

	return d;
}

static u_char*
makekan(SJ4_CONTEXT u_char* s, u_char* d, int flg) {
	int csize;

	for(;;) {
		csize = codesize(*s);
		if(s[csize] == KANJISTREND) {
			switch(*s & KANJIMODEMASK) {
			case ZENHIRAASSYUKU:
				d = makekan_1byte(SJ4_CONTEXT_PASS s, d, flg);
				break;

			case ZENKATAASSYUKU:
				d = makekan_1byte(SJ4_CONTEXT_PASS s, d, flg);
				break;

			case OFFSETASSYUKU:
				d = makekan_ofs(SJ4_CONTEXT_PASS s, d, flg);
				break;

			case AIATTRIBUTE:
			case KANAKANCOST:
				d = makekan_none(SJ4_CONTEXT_PASS s, d, flg);
				break;

			case LEADINGHANKAKU:
				d = makekan_ascii(SJ4_CONTEXT_PASS s, d, flg);
				break;

			case KANJIASSYUKU:
				d = makekan_knj(SJ4_CONTEXT_PASS s, d, flg);
				break;

			default:
				d = makekan_norm(SJ4_CONTEXT_PASS s, d, flg);
			}
			break;
		} else
			switch(*s & KANJIMODEMASK) {
			case ZENHIRAASSYUKU:
				d = makekan_1byte(SJ4_CONTEXT_PASS s, d, FALSE);
				break;

			case ZENKATAASSYUKU:
				d = makekan_1byte(SJ4_CONTEXT_PASS s, d, FALSE);
				break;

			case OFFSETASSYUKU:
				d = makekan_ofs(SJ4_CONTEXT_PASS s, d, FALSE);
				break;

			case AIATTRIBUTE:
			case KANAKANCOST:
				d = makekan_none(SJ4_CONTEXT_PASS s, d, FALSE);
				break;

			case LEADINGHANKAKU:
				d = makekan_ascii(SJ4_CONTEXT_PASS s, d, FALSE);
				break;

			case KANJIASSYUKU:
				d = makekan_knj(SJ4_CONTEXT_PASS s, d, FALSE);
				break;

			default:
				d = makekan_norm(SJ4_CONTEXT_PASS s, d, FALSE);
			}
		s += codesize(*s);
	}

	return d;
}

#define PEND 2
#define QEND 1
static int
sameknj(u_char* p, u_char plen, u_char* q, u_char qlen) {
	int i;
	int j;
	int endf = 0;
	int brkf;

	do {
		if((i = euc_codesize(*p)) != euc_codesize(*q)) return FALSE;

		brkf = 0;
		for(j = 0; j < i; j++) {
			if(p[j] != q[j]) {
				brkf = 1;
				break;
			}
		}
		if(brkf) break;

		if(p[i] == KANJISTREND) endf += PEND;
		if(q[i] == KANJISTREND) endf += QEND;

		p += i;
		q += i;
	} while(!endf);

	switch(endf) {
	case(PEND | QEND):
		if(plen == qlen) return TRUE;
		break;

	case PEND:
		i    = plen;
		plen = qlen;
		qlen = i;
		p    = q;

	case QEND:
		if(p[euc_codesize(*p)] != KANJISTREND) break;
		if((*p & KANJIMODEMASK) != 0x10) break;
		if(qlen != plen - (*p & KANJICODEMASK) - 1) break;
		return TRUE;

	default:
		if(q[euc_codesize(*q)] != KANJISTREND) break;
		if(p[euc_codesize(*p)] != KANJISTREND) break;
		if((*q & KANJIMODEMASK) != 0x10) break;
		if((*p & KANJIMODEMASK) != 0x10) break;
		if(plen - (*p & KANJICODEMASK) != qlen - (*q & KANJICODEMASK))
			break;
		return TRUE;
	}

	return FALSE;
}
#undef PEND
#undef QEND

static int
diffknj(SJ4_CONTEXT JREC* jrec, u_char* ptr, int num) {
	KHREC* kptr;
	JREC*  jptr;
	int    i;
	u_char kbuf1[MAXWDKANJILEN];
	u_char kbuf2[MAXWDKANJILEN];

	if(jrec->hinsi == TANKANJI) return TRUE;

	makekan(SJ4_CONTEXT_PASS ptr, kbuf1, TRUE);

	for(i = 0, kptr = kouhotbl; i < num; i++, kptr++) {
		if((jptr = kptr->clrec->jnode) == jrec)
			return FALSE;

		if(jptr->hinsi == TANKANJI) continue;

		if(jptr->jclass != jrec->jclass) continue;

		if(jptr->dicid != jrec->dicid) continue;

		if(jptr->jseg != jrec->jseg) continue;

		if(jptr->sttofs != jrec->sttofs) continue;

		if(jptr->stbofs != jrec->stbofs) continue;

		makekan(SJ4_CONTEXT_PASS dicbuf + kptr->offs, kbuf2, TRUE);

		if(sameknj(kbuf1, jrec->jlen, kbuf2, jptr->jlen))
			return FALSE;
	}

	return TRUE;
}

static int
chrck_numtbl(u_short flg, u_short cond) {
	u_short must;

	if((cond = SelNumCond(cond))) {
		if((must = (cond & SELNUMMUST))) {
			if((flg & must) != must) return FALSE;
			cond &= ~must;
		}
		if(cond && !(cond & flg)) return FALSE;
	}

	return TRUE;
}

int sel_sjmode(JREC* jrec) {
	u_short	 i;
	u_short* p;
	u_short* q;

	switch(jrec->jclass) {
	case C_N_ARABIA:
	case C_N_ARACMA:
	case C_N_KAZU:
	case C_N_SUUJI:
	case C_N_NANSUU:
	case C_N_KANKURA:
	case C_N_ARAKURA:
	case C_N_KAZULONG:
	case C_N_KAZULCMA:
	case C_N_SUUJILONG:
		p = q = Selsjadrs(jrec->jclass - C_N_ARABIA);
		break;

	default:
		return SELARB;
	}

	while((i = *p++) != SELNUMTERM) {
		if(chrck_numtbl(jrec->flags, i)) break;
	}

	if(i == SELNUMTERM) i = *q;

	return SelNumFunc(i);
}

static void
cl_numcmn(SJ4_CONTEXT JREC* jrec, CLREC* clrec) {
	u_char*	 p;
	int	 i;
	u_short	 j;
	u_short* tbl;

	p = cnvstart;
	if((i = jrec->sttofs) == SETTOU_DAI)
		p += SttYomiLen(Settou_ptr(i));
	else if(i == SETTOU_KIGOU)
		p++;

	if(jrec->jofsst) {
		i = sel_sjmode(jrec);

		if(seldict(SJ4_CONTEXT_PASS jrec->dicid)) {
			(*curdict->getdic)(SJ4_CONTEXT_PASS curdict, jrec->jseg);

			p = dicbuf + jrec->jofsst + 1;

			while(*p != HINSIBLKTERM) {
				setkouho(SJ4_CONTEXT_PASS clrec, (TypeDicOfs)(p - dicbuf), i);
				p = skipkstr(p);
			}
		} else {
			setkouho(SJ4_CONTEXT_PASS clrec, (TypeDicOfs)1, i);
		}
	} else {
		tbl = Selsjadrs(jrec->jclass - C_N_ARABIA);
		while((j = *tbl++) != SELNUMTERM) {
			if(!chrck_numtbl(jrec->flags, j)) continue;

			setkouho(SJ4_CONTEXT_PASS clrec, (TypeDicOfs)0, (int)SelNumFunc(j));
		}
	}
}
