/*
    Copyright (c)
    1987,1988,1989,1990,1991,1992,1993,1994  Electrotechnical Laboratory 

    Permission to use, copy, modify, and distribute this software
    and its documentation for any purpose is hereby granted without fee,
    provided that the above copyright notice and this permission notice
    appear in all versions of this software.

    Author: Yutaka Sato     Electrotechnical Laboratory
                            <ysato@etl.go.jo>
 */

/*######################################################################*
 *									*
 *		Onew for Nihongo text Entry with Wnn			*
 *									*
 *######################################################################*/
#define STATIC static

#include <stdio.h>
#include <ctype.h>
#include "onew.h"

int ONEW_DEBUG;
int ONEW_MSGHOLD;

int ONEW_RK_THRU;
int ONEW_NN_THRU;
int ONEW_THRUSYMS_ON;
int ONEW_2BYTES_ONLY;
int ONEW_IN_ISO2022;

int ONEW_MODE_SWITCHER	= Cntl('\\');
int ONEW_ROMKAN_TOGGLE	= Cntl('@');
int ONEW_KANA_TOGGLE	= Cntl('K');
int ONEW_ZENKAKU_TOGGLE	= Cntl('L');
int ONEW_SELECT_YANK	= Cntl('Y');
int ONEW_RKKSERV_SW	= 'Q';
int ONEW_MODESW_CALL	= Cntl('Z');
int ONEW_THRU_NEXTCH	= Cntl('V');
int ONEW_HENKAN_START	= Cntl('W');
int ONEW_THRUSYMS_SETUP	= Cntl('@');
int THRUSYMS_TOGGLE	= Cntl('^');

/* internally generated commands */
int ONEW_I_ESC		= Cntl(']');
int ONEW_I_KAKUTEI	= Cntl('_');
int ONEW_I_THRU_NEXTCH	= Cntl('C');
int ONEW_I_SYNC_CHAR	= 0xFF;
int ONEW_KK_OPDICT	= 'x';

static definedKanamode();
static romkan_modesw();
static thru_char1();
static Onew_kakuteiInRomkan();

#define MODE_SWITCHER	ONEW_MODE_SWITCHER
#define ZENKAKU_TOGGLE	ONEW_ZENKAKU_TOGGLE
#define KANA_TOGGLE	ONEW_KANA_TOGGLE
#define ROMKAN_TOGGLE	ONEW_ROMKAN_TOGGLE

char *ONEW_HENKANKEYS	= "[ ]";
char  ONEW_HENKANKEYA[256];

#define IS_NOINS_HENKANKEY(ch)	(ch == ONEW_HENKAN_START || ch == STD_HENKAN)
#define IS_INS_HENKANKEY(ch)	(ch && ONEW_HENKANKEYA[ch])
#define IS_HENKANKEY(ch)	(IS_NOINS_HENKANKEY(ch)||IS_INS_HENKANKEY(ch))
#define LET_IT_THRU(ch)		(ONEW_THRUSYMS_ON && Onew_isTHRU(ch))


static romkan_ready(){
	romkan_select();
	return oeiRomkanReady(0);
}
static kanakan_ready(){
	kanakan_select();
	return oeiKanakanReady();
}

/*######################################################################*
 *	Jisyo MODE							*
 *######################################################################*/

extern int OM_JisyoMode;
extern int OM_JisyoGetYomi;
extern int OM_JisyoGetTsuduri;	/* touroku string input mode */
extern int OM_JisyoGetKanjiFlush;
extern int OM_JisyoMassyou;
#define OM_JisyoGetModes	(OM_JisyoGetYomi || OM_JisyoGetTsuduri)

/*######################################################################*
 *	ROMKAN INTERFACE						*
 *######################################################################*/
/* romkan mode mnemonics */
#define RK_HIRA		'h'
#define RK_KATA		'k'
#define RK_LARGE	'l'
#define RK_THRU		'@'
#define RK_OFF		'-'

static Linebuff rawc_inbuff;
clr_keyinQ(){  return strQclr(rawc_inbuff);   }
ins_keyinQ(c){ return strQins(rawc_inbuff,c); }
enq_keyinQ(c){ return strQenq(rawc_inbuff,c); }
deq_keyinQ(){  return strQdeq(rawc_inbuff);   }
ready_keyinQ(){ return rawc_inbuff[0] != 0; }

char *romkan_cmode();
int ONEW_getch_asis; /* never interpret as command keys */

ONEW_getch0(asis){
	int ch;

	if( (ch = deq_keyinQ()) == EOF ){
		if( !asis && !ONEW_getch_asis )
			Onew_putmode(romkan_cmode(),0);
		ch = OnewGetchar();
	}
	return ch;
}
ONEW_getch1(){
   int ch;

   for(;;){
	ch = ONEW_getch0(ONEW_getch_asis);
	if( ONEW_getch_asis )
		break;

	if( ch == ROMKAN_TOGGLE   ){ romkan_toggle(); break;		}else
	if( ch == MODE_SWITCHER   ){ romkan_modesw(); ch = 0; break;	}else
	if( ch == THRUSYMS_TOGGLE ){ sym_thru_toggle();			}else 
	if( ch == ONEW_MODESW_CALL){ ch = ONEW_HENKAN_START; break;	}else
	if( romkan_on() ){
		if( IS_HENKANKEY(ch) && !IS_NOINS_HENKANKEY(ch) )
			enq_keyinQ(ONEW_HENKAN_START);

		if( definedKanamode(ch) ){ continue;                    }else
		if( ch == KANA_TOGGLE   ){ katakana_toggle(); continue; }else
		if( ch == ZENKAKU_TOGGLE){ zenkaku_toggle();  continue; }else
		if( ch == DEL_CH )	 { ch = BS_CH;                  }else
		if( ch == ESC_CH ) { oeiRomkanClear(); ch = ONEW_I_ESC; }else
		if( in_kana_mode() ){
			if( LET_IT_THRU(ch) && !IS_NOINS_HENKANKEY(ch) ){
				thru_char1(ch);
				continue;
			}else
			if( ch == 'Q' ){
				switch_rkserv();
				ch = 0;/* let the current Romkan exit */
			}else
			if( ch == 'q' || ch == ONEW_MODESW_CALL ){
				OM_mode_switches();
				ch = 0;
			}else
			switch( ch ){
				case 'Z':
					ins_zenkaku_char1(0,0);
					continue;
	/*
				default:
					if( 'A' <= ch && ch <= 'Y' )
					if( katakana_toggle() ){
						enq_keyinQ(ch-('A'-'a'));
						continue;
					}
	*/
			}
		}
		break;
	}else
	if( ch == Cntl('G') ){
		/*pushQ(ONEW_HENKAN_START);*/
		ch = ONEW_HENKAN_START;
		break;
	}else	break;
    }
    return ch;
}

static IFUNC KanamodeSw[128];
static int kanamodes[16];
static int kanamodex;

static definedKanamode(ch)
	unsigned char ch;
{	IFUNC func;

	if( 128 <= ch )
		return 0;
	if( func = KanamodeSw[ch] )
		return (*func)(ch);
	return 0;
}
Onew_defineKanamode(mode,ch,func)
	IFUNC func;
{
	kanamodes[kanamodex++] = mode;
	KanamodeSw[ch] = func;
}


static romkan_modesw(){
	int cmode;

	cmode = ONEW_getch1();
	romkan_mode_switch(cmode);
}
static thru_char1(ch){
	ins_keyinQ(ch);
	ins_keyinQ(ONEW_I_THRU_NEXTCH);
}

ins_zenkaku_char1(ch,kakutei)
{	char buf[8],*bp;

	if( ch == 0 )
		OM_zenkaku1(buf);
	else	ONEWromkan_zenkaku(ch,buf);

	for( bp = buf; *bp; bp++ )
		enq_keyinQ(*bp);
	if( kakutei )
		enq_keyinQ(ONEW_I_KAKUTEI);
}

ONEWromkan_zenkaku(ch,dst)
	char *dst;
{	char *tab,*jis;

	if( 0x200 <= ch ){
		dst[0] = ch;
		dst[1] = 0;
	}else{
		jis = &ONEW_ASCII_TO_JIS[ch*2];
		dst[0] = jis[0];
		dst[1] = jis[1];
		dst[2] = 0;
	}
}
ASCII_TO_JIS(asc,jis)
	char *asc,*jis;
{	char *a,*j;
	char *jc;
	int ac;

	j = jis;
	for( a = asc; ac = *a; a++ ){
		if( 0x20 <= ac && ac < 0x7F ){
			jc = &ONEW_ASCII_TO_JIS[ac*2];
			*j++ = jc[0];
			*j++ = jc[1];
		}else	*j++ = ac;
	}
	*j = 0;
}

Onew_HENKANKEYS(syms)
	char *syms;
{
	strMAPset(syms,ONEW_HENKANKEYA,"ONEW_HENKANKEYS",
		ONEW_HENKANKEYS,0);
}

static Linebuff kana_inbuff;
Onew_deqchar(commandmode){
	int ch;

	if( (ch = strQdeq(kana_inbuff)) != EOF )
		return ch;
	if( commandmode || ONEW_RK_THRU )
		if( 0 < Onew_inready(stdin,-1) )
			return OnewGetchar();
	return EOF;
}
Onew_enqchar(ch){
	strQenq(kana_inbuff,ch);
}
Onew_enqstr(str) char *str; {
	char *sp,ch;
	for(sp = str; ch = *sp; sp++)
		Onew_enqchar(ch);
}

Onew_asis_romkan_next(){
	int kc;

	ONEW_getch_asis = 1;
	kc = oeiRomkanNext();
	ONEW_getch_asis = 0;
	return kc;
}

static int ROMKAN_INIT_DONE;
Onew_RK_init(){
	char *env;

	if( ROMKAN_INIT_DONE == 0 ){
		if( env = getenv("ONEW_MSGHOLD") )
			ONEW_MSGHOLD = atoi(env);
		if( env = getenv("ONEW_MAXWORDS") )
			ONEW_MAXWORDS = atoi(env);

		Onew_HENKANKEYS(0);
		Onew_THRUSYMS(0);
		ONEW_NN_THRU    = getenv("ONEW_NN_THRU")    != 0;
		ONEW_IN_ISO2022 = getenv("ONEW_NO_ISO2022") == 0;
		ONEW_DEBUG      = getenv("ONEW_DEBUG")      != 0;

		ROMKAN_INIT_DONE = romkan_ready();
		keisen_init();
	}
	return 0 < ROMKAN_INIT_DONE;
}

kget_char1(){
	unsigned int kc;

	if( !Onew_RK_init() ){
		kc = OnewGetchar();
		ouiTrace("kget_char1.1","(%x)",kc);
		return kc;
	}
start:
	if( (kc = Onew_deqchar(0)) != EOF ){
		ouiTrace("kget_char1.2","(%x)",kc);
		return kc;
	}

	if( ONEW_RK_THRU ){
		kc = OnewGetchar();
		ouiTrace("kget_char1.3","(%x)",kc);
		return kc;
	}

	do{
		if( romkan_on() )
			kc = oeiRomkanGetc();
		else	kc = oeiRomkanNext();

		/*###### KAKUTEI ######*/
		if( kc=='\r' || kc=='\n' || kc==ONEW_I_KAKUTEI )
		if( romkan_on() || OM_JisyoGetModes ){
			if( Onew_kakuteiInRomkan(kc) )
				goto start;
			if( kc==ONEW_I_KAKUTEI )
				goto start;
		}

		/*###### YANK ######*/
		if( kc == ONEW_SELECT_YANK ){
			Onew_getword(kc);
			goto start;
		}else
		/*###### SELECT ######*/
		if( romkan_on() && kc == Cntl('G') ){
			char code[4];
			if( 0 < OM_get_jisspecial(code) )
				Onew_enqstr(code);
			goto start;
		}else
		/*###### HENKAN ######*/
		if( romkan_on() && IS_NOINS_HENKANKEY(kc)
		 || kc == ONEW_HENKAN_START ){
			if( !kanakan_ready() )
				goto start;

			kc = OM_kanakan(kc);
			if( kc == ONEW_HENKAN_START ){
				/* maybe q-a for empty buffer */
				goto start;
			}
			if( kc == STD_HENKAN ){
				if( ONEW_THRUSYMS_ON && Onew_isTHRU(kc) )
					enq_keyinQ(ONEW_I_KAKUTEI);
				else{
					ins_zenkaku_char1(kc,1);
					goto start;
				}
			}
		}else
		if( kc == ONEW_THRU_NEXTCH || kc == ONEW_I_THRU_NEXTCH ){
			int nkc;

			if( kc == ONEW_THRU_NEXTCH ){
				nkc = OM_get_thruchar(1);
				Onew_enqchar(kc);
			}else	nkc = OM_get_thruchar(0);

			Onew_enqchar(nkc);
			goto start;
		}else{
			kc = oeiRomkanGotch(kc);
			if( kc == 0 )
				continue;
			if( kc == ONEW_I_ESC ){
				if( odmAbort_touroku() )
					goto start;
				kc = ESC_CH;
			}
			if( in_kana_mode() )
			if( ONEW_THRUSYMS_ON ){
				/* enqueue kakutei control code if
				   there has been no JIS input */
				/*enq_keyinQ(ONEW_I_KAKUTEI);*/
			}else{
				if( ' ' < kc  && kc < 0x7F && !isalpha(kc) ){
					ins_zenkaku_char1(kc,0);
					kc = 0;
					continue;
				}
			}

			if( kc & 0xFF00 )
			if((kc & 0xFF000000) == 0)/* not a control-code */
			{
				Linebuff buff;
				ouiGOT_2BCHAR(buff,kc>>8,kc&0xFF);
				Onew_enqstr(buff);
				goto start;
			}
		    }
	}while(kc == 0);

	ouiTrace("kget_char1.4","(%x)",kc);
	return kc;
}
Onew_romkan(){
	return kget_char1();
}

/*######################################################################*
 *	Romaji-Kana henkan MODE SWITCH					*
 *######################################################################*/
/*
 *	MODE FLAGS
 */
int ONEW_kanamode;

romkan_on(){
	return ONEW_kanamode;
}
Onew_RK_imode(){
	return romkan_on();
}
Onew_RK_imode_setv(imode)
{
	ONEW_kanamode = imode;
}
romkanmode_ch(){
	switch( ONEW_kanamode ){
		case ZENKAKU:		return RK_HIRA;
		case ZENKAKU|KATAKANA:	return RK_KATA;
		case ZENKAKU| NOTKANA:	return RK_LARGE;
		default:		return RK_THRU;
	}
}
Onew_RK_cmode(){
	return romkanmode_ch();
}

Onew_RK_imode_set(imode)
{
	return oeiRomkanModesw(imode);
}

romkan_mode_switch(mode){
	int new_kana_mode = 0;

	switch( mode ){
		default : new_kana_mode = 0; break;
		case RK_HIRA:  new_kana_mode = ZENKAKU; break;
		case RK_KATA:  new_kana_mode = ZENKAKU | KATAKANA; break;
		case RK_LARGE: new_kana_mode = ZENKAKU | NOTKANA; break;
		case RK_THRU:  new_kana_mode = 0; break;
	}
	if( ONEW_kanamode && new_kana_mode )
		oeiRomkanModesw(0);
	oeiRomkanModesw(new_kana_mode);
}
Onew_RK_cmode_set(mode){
	Onew_RK_init();
	return romkan_mode_switch(mode);
}
romkan_toggle(){
	if( ONEW_kanamode )
		oeiRomkanModesw(0);
	else	oeiRomkanModesw(ZENKAKU);
}
Onew_RK_toggle(){
	return romkan_toggle();
}
zenkaku_toggle(){
	if( ONEW_kanamode & ZENKAKU ){
		oeiRomkanModesw( ONEW_kanamode ^ NOTKANA );
	}
}

in_kana_mode(){
	int Kmode,ki,mode;

	if(	ONEW_kanamode == ZENKAKU
	     || ONEW_kanamode ==(ZENKAKU|KATAKANA) )
		return 1;
	for( ki = 0; ki < kanamodex; ki++ )
		if( ONEW_kanamode == kanamodes[ki] )
			return 1;
	return 0;
}
katakana_toggle(){
	if( in_kana_mode() ){
		ONEW_kanamode &= (ZENKAKU | KATAKANA);
		oeiRomkanModesw(ONEW_kanamode ^ KATAKANA);
		return 1;
	}
	return 0;
}
sym_thru_toggle(){
	ONEW_THRUSYMS_ON = !ONEW_THRUSYMS_ON;
}

char *
ONEWromkan_smode(){
	static char rkmode[8];

	if(ROMKAN_INIT_DONE && ONEW_kanamode)
		sprintf(rkmode,oeiRomkanDispmode(),rkEngineID());
	else	strcpy(rkmode,"[---]");

	if( ONEW_THRUSYMS_ON )
	if( rkmode[4] == ']' )
		strcpy(&rkmode[4],"-]");

	return rkmode;
}
char *Onew_RK_smode(){
	return ONEWromkan_smode();
}
char *romkan_cmode(){
	return Onew_RK_smode();
}

char *romkan_help(){
	if( romkan_on() )
		return ONEW_menu_romkana;
	else	return ONEW_menu_roman;
}

/*######################################################################*
 *	KANA-KAN							*
 *######################################################################*/
Onew_kanakan(com,str,start,leng)
	char *str;
{
	return Onew_kana_to_kanji(com,str,start,leng);
}

char ONEW_CurrentYomi[256];
char ONEW_CurrentKanji[1024];
Uchar ONEW_DicYomi[256];

Onew_kana_to_kanji(startcom,str)
	Uchar *str;
{	Mssgbuff buf;
	Uchar sstr[2048];
	int endcom;

	if( OM_JisyoGetYomi && startcom != STD_HENKAN ){
		if( odmStart_touroku(str) )
			OM_JisyoGetYomi = 0;
		return 0;
	}
	if( OM_JisyoGetKanjiFlush ){
		strcpy(ONEW_CurrentKanji,str);
		OM_JisyoGetKanjiFlush = 0;
		odmJisyo_touroku();
		str = ONEW_DicYomi;
	}
	if( startcom != ONEW_HENKAN_START && Onew_non_ascii(str) == 0 ){
		if( ONEW_THRUSYMS_ON && Onew_isTHRU(startcom) )
			sprintf(buf,"%s%c",str,startcom);
		else	strcpy(buf,str);
		ouiDISP_KANAKANB(0,buf,"","");
		ouiKAKUTEI(ONEW_I_KAKUTEI);
		return 0;
	}

	strcpy(sstr,str);
	strcpy(ONEW_CurrentYomi,sstr);

	for(;;){
		endcom = oeiKanakan(startcom,str);
		if( endcom == ONEW_RKKSERV_SW ){
			switch_kkserv();
			str = sstr;
			continue;
		}
		if( endcom == ONEW_KK_OPDICT || endcom == 'q' ){
			if( odmJisyo_sousa() ){
				endcom = 0;
				break;
			}else{
				str = sstr;
				continue;
			}
		}
		if( endcom != BS_CH && endcom != DEL_CH ){
			if( OM_JisyoGetYomi ){
				if( odmStart_touroku(ONEW_CurrentKanji) ){
					OM_JisyoGetYomi = 0;
					break;
				}
			}
			if( OM_JisyoGetTsuduri ){
				odmJisyo_touroku();
				strcpy(sstr,ONEW_DicYomi);
				str = sstr;
				continue;
			}
		}
		break;
	}
	ONEW_CurrentKanji[0] = 0;
	return endcom;
}

Onew_kakutei(kc) /* invoked in Kana-Kanji translation */
{
	return ouiKAKUTEI(kc);
}

static Onew_kakuteiInRomkan(kc)
{
	if( OM_JisyoGetYomi ){
		enq_keyinQ(ONEW_HENKAN_START);
		return 1;
	}
	if( OM_JisyoGetTsuduri ){
		if( ONEW_CurrentKanji[0] == 0 ){
			OM_JisyoGetKanjiFlush = 1;
			enq_keyinQ(ONEW_HENKAN_START);
			return 1;
		}
		odmJisyo_touroku();
	}
	return ouiKAKUTEI(kc);
}

Onew_dispKanakanBuf(so,left,cur,right)
	char *left,*cur,*right;
{	char xleft[1024],xright[1024];

	sprintf(ONEW_CurrentKanji,"%s%s%s",left,cur,right);
	if( so && OM_JisyoGetTsuduri ){
		sprintf(xleft,"[%s",left);
		left = xleft;
		sprintf(xright,"%s]",right);
		right = xright;
	}
	ouiDISP_KANAKANB(so,left,cur,right);
}

Onew_setupYomistr(com,str,yomibuf)
	char *str,*yomibuf;
{	int len;
	int lastch;

	strcpy(yomibuf,str);
	if( ONEW_THRUSYMS_ON && com != STD_HENKAN )
	if( len = strlen(str) ){
		lastch = str[len-1];
		if( Onew_isTHRU(lastch) )
			strcat(yomibuf," ");
	}
}

Onew_freqsave(){
	oeiKanakanFreqsave();
}
Onew_KK_freqsave(){
	return Onew_freqsave();
}
Onew_RK_thru(mode){
	ONEW_RK_THRU = mode;
}

Onew_inready( fp, wait_usec )
	FILE *fp;
{
	if( *rawc_inbuff || *kana_inbuff )
		return 1;
/*
	if( OnewPeekchar(1) != EOF )
		return 1;
*/
	return Onew_fp_input_ready(fp,wait_usec);
}

/************************************************************************
 */
int ONEW_modedepth;
Onew_modef(modes,xmodes,helps,xhelps)
	char **modes,*xmodes;
	char **helps,*xhelps;
{	int modef;

	modef = ONEW_kanamode
	     | (ONEW_INCHAR_WIDTH==2 ? KF_2BINPUT    : 0)
	     | (ONEW_THRUSYMS_ON     ? KF_THRUSYMS   : 0)
	     | (ONEW_NN_THRU         ? KF_NN_THRU    : 0)
	     | (ONEW_getch_asis      ? KF_NEXTCHAR   : 0)
	     | (ONEW_select_mode     ? KF_SELECT     : 0)
	     | (ONEW_kanakan_mode    ? KF_KANAKAN    : 0)
	     | (OM_JisyoMode         ? KF_JISYO      : 0)
	     | (OM_JisyoGetYomi      ? KF_GETYOMI    : 0)
	     | (OM_JisyoGetTsuduri   ? KF_GETTSUDURI : 0)
	     | (OM_JisyoMassyou      ? KF_MASSYOU    : 0)
	     | ONEW_modedepth << 24;

	if( *modes == 0 ) *modes = Onew_RK_smode();
	if( *helps == 0 ) *helps = romkan_help();

	if( OM_JisyoGetYomi ){
		sprintf(xmodes,"%s%s",ONEW_mode_touroku_yomi,*modes);
		*modes = xmodes;
	}
	if( OM_JisyoGetTsuduri ){
		sprintf(xmodes,"%s%s",ONEW_mode_touroku_kanji,*modes);
		*modes = xmodes;
		sprintf(xhelps,"(%s) %s",ONEW_DicYomi,*helps);
		*helps = xhelps;
	}

	return modef;
}

/************************************************************************
 *	OBSOLETE
 */
kana_init(){
	return Onew_RK_init();
}
kana_to_kanji(str,start,leng)
{
	return Onew_kana_to_kanji(0,str,start,leng);
}



syntax highlighted by Code2HTML, v. 0.9.1