/**********************************************************************
 
	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	<stdlib.h>
#include	"memory_debug.h"
#include	"long_char.h"

#define ESC	0x1b
#define M_AS		0
#define M_AS_ES		1
#define M_AS_ES_DR	2
#define M_AS_ES_DR_B	3
#define M_KN		4
#define M_KN_ES		5
#define M_KN_ES_PN	6
#define M_KN_ES_PN_J	7
#define M_MAX		8

typedef struct jis_work {
	int		in_mode;
	int		out_mode;
	unsigned char	in_buf;
} JIS_WORK;

void * open_jis();
int close_jis(unsigned char *,void *);
int jis2int(L_CHAR *,void*,unsigned char);
int int2jis(unsigned char *,void*,L_CHAR);

static L_CHAR main_code[] = {
	LCZ_2BC_JISX0208_1990,
	LCC_ERROR
};

CODE_METHOD jis_cm = {
	"JIS",
	LCC_JISX0208_1997,
	main_code,
	5,
	3,
	{0,0},
	open_jis,
	close_jis,
	jis2int,
	int2jis,
	0
};

int am_stanby;
int am[M_MAX][256];

void *
open_jis()
{
JIS_WORK * ret;
int i;

	if ( am_stanby == 0 ) {
		for ( i = 0 ; i < 256 ; i ++ ) {
			am[M_AS][i] = M_AS;
			am[M_AS_ES][i] = M_AS;
			am[M_AS_ES_DR][i] = M_AS;
			am[M_AS_ES_DR_B][i] = M_KN;
			am[M_KN][i] = M_KN;
			am[M_KN_ES][i] = M_KN;
			am[M_KN_ES_PN][i] = M_KN;
			am[M_KN_ES_PN_J][i] = M_AS;
		}
		am[M_AS][ESC] = M_AS_ES;
		am[M_AS_ES]['$'] = M_AS_ES_DR;
		am[M_AS_ES_DR]['B'] = M_AS_ES_DR_B;
		am[M_KN][ESC] = M_KN_ES;
		am[M_KN_ES]['('] = M_KN_ES_PN;
		am[M_KN_ES_PN]['J'] = M_KN_ES_PN_J;
		am[M_KN_ES_PN]['B'] = M_KN_ES_PN_J;
	}
	ret = d_alloc(sizeof(*ret),100);
	ret->in_mode = M_AS;
	ret->in_buf = 0;
	ret->out_mode = M_AS;
	return ret;
}

int
close_jis(unsigned char * ret,void * _work)
{
JIS_WORK * work;
	work = (JIS_WORK *)_work;
	if ( work->out_mode == M_KN && ret ) {
		ret[0] = ESC;
		ret[1] = '(';
		ret[2] = 'J';
		d_f_ree(work);
		return 3;
	}
	d_f_ree(work);
	return 0;
}

int
jis2int(L_CHAR * ret,void * _work,unsigned char ch)
{
JIS_WORK * work;
unsigned int h;

	work = (JIS_WORK*)_work;
	work->in_mode = am[work->in_mode][ch];
	switch ( work->in_mode ) {
	case M_AS:
		work->in_buf = 0;
		*ret = ((int)ch)&0x0ff;
		return 1;
	case M_KN:
		if ( work->in_buf ) {
			*ret = (work->in_buf<<8)|ch|LCZ_2BC_JISX0208_1990;
			work->in_buf = 0;
			return 1;
		}
		else {
			if ( ch <= 0x20 ) {
				*ret = ((int)ch)&0x0ff;
				return 1;
			}
			work->in_buf = ch;
			return 0;
		}
	}
	return 0;
}

int
int2jis(unsigned char * ret,void * _work,L_CHAR ch)
{
JIS_WORK *work;
	work = (JIS_WORK*)_work;
	if ( (ch&LCZM_1B_TYPE) == LCZ_1BC_ASCII ) {
		if ( ch&0x80 )
			return 0;
		switch ( work->out_mode ) {
		case M_AS:
			ret[0] = ch;
			return 1;
		case M_KN:
			if ( ch <= 0x20 ) {
				if ( ch == '\n' || ch == '\r' ) {
					ret[0] = ESC;
					ret[1] = '(';
					ret[2] = 'J';
					ret[3] = ch;
					work->out_mode = M_AS;
					return 4;
				}
				ret[0] = ch;
				return 1;
			}
			else {
				ret[0] = ESC;
				ret[1] = '(';
				ret[2] = 'J';
				ret[3] = ch;
				work->out_mode = M_AS;
				return 4;
			}
		}
		return 0;
	}
	else if ( (ch&LCZM_2B_TYPE) == LCZ_2BC_JISX0208_1990 ) {
		switch ( work->out_mode ) {
		case M_AS:
			ret[0] = ESC;
			ret[1] = '$';
			ret[2] = 'B';
			ret[3] = (ch>>8)&0xff;
			ret[4] = ch&0xff;
			work->out_mode = M_KN;
			return 5;
		case M_KN:
			ret[0] = (ch>>8)&0xff;
			ret[1] = ch&0xff;
			return 2;
		}
		return 0;
	}
	return 0;
}
