/*
 * Copyright (C) 1994,1995	Edward Der-Hua Liu, Hsin-Chu, Taiwan
 */
/*
 * modified for Big5Con by Hung-Chi Chu <hcchu@r350.ee.ntu.edu.tw>
 */

#include "big5con.h"

int             cursor_x = 0;
static u_char   cur_att = NormalColor;

extern u_char  *cin_textBuff, *cin_attrBuff, *cin_flagBuff;
extern struct dispInfo dInfo;

void 
p_err(char *fmt,...)
{
    va_list         args;

    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    fprintf(stderr, "\n");
    exit(-1);
}

void 
bell()
{
    fputc(007, stderr);
}

static void 
ostr(int x, char *str, int len, u_char attr)
{
    memcpy(cin_textBuff + x, str, len);
    memset(cin_attrBuff + x, attr, len);
    memset(cin_flagBuff + x, 0, len);
}

static void 
costr(int x, char *str, int len, u_char attr)
{
    u_char         *dst, *end;
    memcpy(cin_textBuff + x, str, len);
    memset(cin_attrBuff + x, attr, len);
    for (dst = cin_flagBuff + x, end = dst + len; dst < end; dst += 2) {
	*dst = DF_BIG5_1 | LATCH_1;
	*(dst + 1) = DF_BIG5_1 | LATCH_2;
    }
}

static 
xputs(int x, u_char * s)
{
    u_char          ch;
    int             len = strlen(s);
    int             cl = 0;
    u_char         *cp, *endp, *strp;
    char            ctyp;
    u_char          hb, lb;

    strp = cp = s;
    endp = s + len;
    cl = 0;
    ctyp = 0;

    while (cp < endp) {
	hb = *cp;
	if ((hb >= 0x81 && hb <= 0xfe) && cp + 1 < endp) {
	    lb = *(cp + 1);
	    if (lb >= 0x40 && lb <= 0x7e || lb >= 0xa1 && lb <= 0xfe) {
		if (ctyp == 1) {
		    ostr(strp - s + x, strp, cl, cur_att);
		    cl = 0;
		    strp = cp;
		}
		cl += 2;
		cp += 2;
		ctyp = 2;
		continue;
	    }
	}
	if (ctyp == 2) {
	    costr(strp - s + x, strp, cl, cur_att);
	    cl = 0;
	    strp = cp;
	}
	cl++;
	cp++;
	ctyp = 1;
    }

    if (ctyp == 1)
	ostr(strp - s + x, strp, cl, cur_att);
    if (ctyp == 2)
	costr(strp - s + x, strp, cl, cur_att);

}

void 
xprintf(char *fmt,...)
{
    va_list         args;
    char            tmp[100];

    va_start(args, fmt);
    vsprintf(tmp, fmt, args);
    va_end(args);
    xputs(cursor_x, tmp);
    cursor_x += strlen(tmp);
}

void 
gotox(int x)
{
    cursor_x = x;
}

void 
set_att(u_char att)
{
    cur_att = att;
}

u_char          fullchar[] =
"　！”＃＄％＆’（）＊＋，－．／０１２３４５６７８９：；＜＝＞？"
"＠ＡＢＣＤＥＦＧＨＩＪＫＬＭＮＯＰＱＲＳＴＵＶＷＸＹＺ〔＼〕︿ˍ"
"‘ａｂｃｄｅｆｇｈｉｊｋｌｍｎｏｐｑｒｓｔｕｖｗｘｙｚ｛｜｝∼  ";

u_char         *hfstr[] = {"[半形]", "[全形]"};
static u_char   statstr[] = " 【英數】";
static int      targe_inmd_key = 1;
int             show_keys[9] = {10};
int             show_keys_n = 1;
static int      cur_show_keys = 0;
u_char          cur_input_ch[2];
char           *tabfname[14] = {(char *)1, "cj.tab", "simplex.tab", (char *)1, "dayi3.tab", 0, 0, 0, "array30.tab", "liu.tab", 0, 0, 0, 0};
char            TabDir[40] = XCIN_DIR;

void 
show_target(u_char * s)
{
    u_char          kk[200];
    memset(kk, ' ', sizeof(kk));
    switch (targe_inmd_key) {
    case 10:
	{
	    sprintf(kk, "%2X%2X      ", (u_int) s[0], (u_int) s[1]);
	    break;
	}
    case 11:
    case 3:
    case 6:
	kk[0] = 0;
	break;
    default:
	b52key(targe_inmd_key, s, kk);
    }
    kk[29] = 0;
    gotox(70);
    if (kk[0])
	xprintf("%s", kk);
    else
	xprintf("          ");
}

static int      replied = 0;

void 
putkey_b5(u_char * s)
{
    write(masterPty, s, 2);
    replied = 1;
}

void 
sendkey_b5(u_char * s)
{
    cur_input_ch[0] = s[0];
    cur_input_ch[1] = s[1];
    show_target(cur_input_ch);
    putkey_b5(s);
}

void 
putstr(u_char * s)
{
    write(masterPty, s, strlen(s));
    replied = 1;
}

void 
putfchr(char ch)
{
    char            tt[3];
    int             ii = (int)(ch - ' ') << 1;
    tt[0] = fullchar[ii];
    tt[1] = fullchar[ii + 1];
    tt[2] = 0;
    putstr(tt);
}

void 
puthchr(char ch)
{
    char            tt[2];
    tt[0] = ch;
    tt[1] = 0;
    putstr(tt);
}

InmdState       inmdstate =
{0,				/* inp state */
    3				/* current in-method */
};

void 
SwitchCurInMethod(int usenow)
{
    switch (CurInMethod) {
	case 3:
	init_tab_pho(usenow);
	break;
    case 6:
	init_tab_pp(usenow);
	break;
    case 10:
	init_inter_code(usenow);
	break;
    case 11:
	if (tabfname[11])
	    InitVocBox(usenow);
	else {
	    CurInMethod = 3;
	    init_tab_pho(usenow);
	}
	break;
    default:
	if (tabfname[CurInMethod])
	    init_tab(CurInMethod, usenow);
	else {
	    CurInMethod = 3;
	    init_tab_pho(usenow);
	}
    }
}

void 
show_halffull()
{
    gotox(9);
    xprintf("%s", hfstr[HalfFull]);
}

void 
next_inp()
{
    int             i;

    for (i = CurInMethod + 1; i != CurInMethod; i = (i + 1) % 14)
	if (tabfname[i]) {
	    if (i) {
		CurInMethod = i;
		inmdstate.kb_state |= EngChiMask;
		SwitchCurInMethod(1);
	    } else if (EngChi) {
		inmdstate.kb_state &= ~EngChiMask;
		gotox(0);
		xprintf("%s", statstr);
		gotox(16);	/* clear prev inp */
		xprintf("          ");
	    } else
		continue;
	    break;
	}
    if (i == CurInMethod) {
	CurInMethod = i;
	inmdstate.kb_state |= EngChiMask;
	SwitchCurInMethod(1);
    }
}

void 
toggle_halffull()
{
    inmdstate.kb_state ^= HalfFullMask;
    show_halffull();
}

int 
trans_key2(int ch, int state)
{
    int             count;
    int             res = 0;
    replied = 0;
    if ((state & KEY_ALT_MASK) && (state & KEY_SHIFT_MASK)) {
	res = lookup_key(tolower(ch));
    } else if (ch == ' ' && (state & KEY_CTRL_MASK)) {
	inmdstate.kb_state ^= EngChiMask;
	if (!EngChi) {
	    gotox(0);
	    xprintf("%s", statstr);
	    gotox(16);		/* clear prev inp */
	    xprintf("          ");
	    ClrSelArea();
	} else {
	    SwitchCurInMethod(1);
	}
	TextRefresh();
	return (1);
    } else if (ch == ' ' && (state & KEY_SHIFT_MASK)) {
	toggle_halffull();
	TextRefresh();
	return (1);
    } else if ((state & KEY_CTRL_MASK) && (state & KEY_ALT_MASK)) {
	switch (ch) {
	    int             ttt;
	case '1':
	case '2':
	case '4':
	case '5':
	case '7':
	case '8':
	case '9':
	case '=':
	    if (ch == '=')
		ttt = 12;
	    else
		ttt = ch - '0';
	    if (!tabfname[ttt])
		break;
	    inmdstate.kb_state |= EngChiMask;
	    CurInMethod = ttt;
	    init_tab(CurInMethod, 1);
	    TextRefresh();
	    return (1);
	case '3':
	    CurInMethod = 3;
	    inmdstate.kb_state |= EngChiMask;
	    init_tab_pho(1);
	    TextRefresh();
	    return (1);
	case '6':
	    CurInMethod = 6;
	    inmdstate.kb_state |= EngChiMask;
	    init_tab_pp();
	    TextRefresh();
	    return (1);
	case '0':
	    CurInMethod = 10;
	    inmdstate.kb_state |= EngChiMask;
	    init_inter_code();
	    TextRefresh();
	    return (1);
	case '-':
	    if (!tabfname[11])
		break;
	    CurInMethod = 11;
	    inmdstate.kb_state |= EngChiMask;
	    InitVocBox();
	    TextRefresh();
	    return (1);
	case 'i':
	case 'I':
	    cur_show_keys = (cur_show_keys + 1) % show_keys_n;
	    targe_inmd_key = show_keys[cur_show_keys];
	    if (cur_input_ch[0]) {
		show_target(cur_input_ch);
	    }
	    TextRefresh();
	    return (1);
	case 'R':
	case 'r':
	    sendkey_b5(cur_input_ch);
	    TextRefresh();
	    return (1);
	}
    } else if (EngChi && !(state & (KEY_CTRL_MASK | KEY_ALT_MASK))
	       && ch != VK_Control_L) {
	int             shiftm = state & KEY_SHIFT_MASK;
	res = 0;
	if (shiftm && ch != '<' && ch > ' ' && ch < 127 &&
	    CurInMethod != 6 && ch != '*' && ch != '?') {
	    char            tt[2];
	    if (state & KEY_CAPS_MASK && islower(ch))
		ch -= 0x20;
	    else if (!(state & KEY_CAPS_MASK) && isupper(ch))
		ch += 0x20;
	    if (HalfFull)
		putfchr(ch);
	    else
		puthchr(ch);
	    TextRefresh();
	    return (1);
	}
	switch (CurInMethod) {
	case 3:
	    res = feedkey_pho(ch);
	    break;
	case 6:
	    res = feedkey_pp(ch, state);
	    break;
	case 10:
	    if (!shiftm)
		res = feedkey_intcode(ch);
	    break;
	case 11:
	    res = feedkey_vocbox(ch);
	    break;
	default:
	    res = feedkey(ch);
	    break;
	}
    } else if ((ch == VK_Control_L && state & KEY_SHIFT_MASK) ||
	       (ch == VK_Shift_L && state & KEY_CTRL_MASK)) {
	next_inp();
	TextRefresh();
	return (1);
    }
    if ((!EngChi || !res) &&
	!(state & (KEY_CTRL_MASK | KEY_ALT_MASK))) {
	u_char          tt[3];
	if (HalfFull && ch >= ' ' && ch <= 0x7e) {
	    putfchr(ch);
	}
    }
    if (!replied && !res)
	return (0);
    else {
	TextRefresh();
	return (1);
    }
}

typedef struct {
    char           *argv;
    void           *res;
    int             type;	/* 1:char*   4:int */
    char           *help;
}               ARG;

extern char    *phokbm_name;
char            display_name[16];
extern char     tsfname[];
extern char    *phrfname;
extern int      going_key;
extern int      altmeta;

static ARG      arg[] = {
    {"tabdir", TabDir, 21, "table directory name"},
    {"tsfname", tsfname, 21, "TsIn file name"},
    {"inmd", &CurInMethod, 11, "Input method: 1-11"},
    {"phokbm", &phokbm_name, 1, "phonetic kbd  zo:01 et:eten et26:et26 hsu:hsu's"},
    {"in1", &tabfname[1], 1, "in method 1 (eg) cj.tab"},
    {"in2", &tabfname[2], 1, "in method 2"},
    {"in4", &tabfname[4], 1, "in method 4"},
    {"in5", &tabfname[5], 1, "in method 5"},
    {"in6", &tabfname[6], 1, "in method 6"},
    {"in7", &tabfname[7], 1, "in method 7"},
    {"in8", &tabfname[8], 1, "in method 8 (eg) ar30.tab"},
    {"in9", &tabfname[9], 1, "in method 9"},
    {"vocbox", &tabfname[11], 1, "vocabulary box file name"},
    {"in12", &tabfname[12], 1, "in method 12"},
    {"going", &going_key, 14, "going:  0,1"},
    {"phrase", &phrfname, 1, "phrase name"},
    {"altmeta", &altmeta, 14, "altmeta:  0,1"},
};

void 
get_arg(int argc, char **argv)
{
    int             num = sizeof(arg) / sizeof(ARG);
    char           *pp;
    int             i, j;

    for (i = 1; i < argc; i++) {
	if (argv[i][0] == '-') {
	    for (j = 0; j < num; j++)
		if (!strcmp(&argv[i][1], arg[j].argv) && i < argc - 1) {
		    pp = argv[i + 1];
		    switch (arg[j].type) {
		    case 1:
			*(char **)arg[j].res = pp;
			break;
		    case 11:
			*(char *)arg[j].res = atoi(pp);
			break;
		    case 14:
			*(int *)arg[j].res = atoi(pp);
			break;
		    case 21:
			strcpy(arg[j].res, pp);
		    }
		    i++;
		    break;
		}
#if 0
	    if (j == num) {
		char            tt[128];
		error("Unknown arg %s", argv[i]);
		error("Valid args are :");
		error("\t\tSee README for details");
		for (j = 0; j < num; j++)
		    fprintf(stderr, "\t-%s  %s\n", arg[j].argv,
			    arg[j].help);
		exit(-1);
	    }
#endif
	}
    }

}

void
cin_init(int argc, char **argv)
{
    int             i;
    char            str[10];
    char           *pp;

    get_arg(argc, argv);

    if (TabDir[strlen(TabDir) - 1] != '/')
	strcat(TabDir, "/");
    if (CurInMethod <= 0 || CurInMethod > 11 ||
	(!tabfname[CurInMethod] && CurInMethod != 6))
	CurInMethod = 3;
    targe_inmd_key = CurInMethod;

    SwitchCurInMethod(0);
    gotox(0);
    xprintf("%s", statstr);
    show_halffull();
    init_phrase();
}
