#include	"list.h"

#define		MAX_TOKEN		10
#define		MAX_FEPLINE		128

#define		MODE_NORMAL		(0)
#define		MODE_ZENHIRA	(1)
#define		MODE_ZENKATA	(2)
#define		MODE_HANKATA	(3)
#define		MODE_ZENROMA	(4)
#define		MODE_HANROMA	(5)

extern	void	hira2kata( LPCSTR src, LPSTR dst ) ;
extern	void	zen2han( LPCSTR src, LPSTR dst ) ;
extern	void	han2zen( LPCSTR src, LPSTR dst ) ;

class Token : public Link {
	CHAR	roma[ MAX_TOKEN ] ;	/* ローマ字 */
	CHAR	kana[ MAX_TOKEN ] ;	/* かな文字 */

public:
	LPSTR	get_roma() {
		return roma ;
	}
	LPSTR	get_kana() {
		return kana ;
	}

	Token( LPCSTR r, LPCSTR k ) {
		strcpy( roma, r ) ;
		strcpy( kana, k ) ;
	}
	Token( CHAR c, LPCSTR k ) {
		roma[0] = c ;
		roma[1] = 0 ;
		strcpy( kana, k ) ;
	}
} ;
typedef	Token	*PToken ;

class DictItem : public Link {
	LPSTR	str ;

public:
	LPCSTR	get_str() const {
		return str ;
	}

	DictItem( LPSTR nm ) {
		str = new CHAR[ strlen( nm ) + 1 ] ;
		strcpy( str, nm ) ;
	}
	~DictItem() {
		delete[] str ;
	}
} ;
typedef	DictItem	*PDictItem ;

class DictLine : public Link {
	LPSTR	key ;
	List	items ;
	DWORD	offset ;

public:
	void	append( LPSTR item ) {
		items.append( new DictItem( item ) ) ;
	}
	LPCSTR	get_key() const {
		return key ;
	}
	PList	get_items() {
		return &items ;
	}
	DWORD	get_offset() const {
		return offset ;
	}
	BOOL	write( HANDLE hFile ) ;
	PDictItem	find( LPCSTR i ) ;

	DictLine( LPSTR k, DWORD ofs ) {
		key = new CHAR[ strlen( k ) + 1 ] ;
		strcpy( key, k ) ;
		offset = ofs ;
	}
	~DictLine() {
		delete[] key ;
	}
} ;
typedef	DictLine	*PDictLine ;

#define		KEY_START	0x9F
#define		KEY_END		0xF1
#define		KEY_SIZE	(KEY_END-KEY_START+1)

class FepDict {
	TCHAR		filename[ MAX_PATH ] ;	/* 辞書ファイル名 */
	DWORD		offset[ KEY_SIZE ] ;	/* 先頭文字の辞書ファイル内位置 */
	HANDLE		hFile ;					/* 辞書ファイルハンドル */
	List		dict ;					/* 辞書行リスト */
	PDictLine	*index ;				/* 辞書行へのポインタの配列 */
	DWORD		num_index ;				/* 辞書行ポインタ配列の要素数 */
	DWORD		topkey ;				/* 現在読み込み中のトップキー */
	DWORD		next_offset ;			/* 現在読み込み中の辞書行の直後オフセット */

	BOOL		open() ;
	void		clear_offset() ;
	void		clear_index() ;
	PDictLine	find( LPCSTR k, LPDWORD ofs ) ;

public:
	void		close() ;
	void		set( LPCTSTR fn ) ;
	BOOL		read_offset() ;
	BOOL		read( LPCSTR str ) ;
	void		make_index() ;
	PDictLine	get_line( DWORD i ) ;
	LPCSTR		get_key( DWORD i ) ;
	BOOL		write( PDictLine dl ) ;
	BOOL		add_item( LPCSTR k, LPCSTR i ) ;

	FepDict() {
		filename[0] = 0 ;
		hFile = INVALID_HANDLE_VALUE ;
		/* オフセット情報のクリア */
		clear_offset() ;
		/* インデックス配列の初期化 */
		index = 0 ;
		num_index = 0 ;
		topkey = IDX_NONE ;
	}
	~FepDict() {
		/* 辞書ファイルを閉じる */
		close() ;
		/* インデックス配列をクリアする */
		clear_index() ;
	}
} ;
typedef	FepDict	*PFepDict ;

class FepCtrl ;

class PropLink : public Link {
	LPSTR		str ;
	DWORD		num_token ;

public:
	LPSTR		get_str() const {
		return str ;
	}
	DWORD		get_num_token() const {
		return num_token ;
	}

	PropLink( LPCSTR v, int nt ) {
		str = new CHAR[ strlen( v ) + 1 ] ;
		strcpy( str, v ) ;
		num_token = nt ;
	}
	~PropLink() {
		delete[] str ;
	}
} ;
typedef	PropLink		*PPropLink ;

class FepProposed : public List {
	DWORD	pos ;

public:
	void	make( FepCtrl& fc ) ;
	DWORD	get_pos() const {
		return pos ;
	}
	void	inc_pos() {
		pos ++ ;
	}
	void	clear_pos() {
		pos = 0 ;
	}
	void	set_pos( DWORD p ) {
		pos = p ;
	}

	FepProposed() {
		clear_pos() ;
	}
} ;

class FepCtrl : public List {
private:
	CHAR		input[ MAX_FEPLINE ] ;	/* 入力中文字列 */
	PFepDict	dict ;
	FepProposed	proposed ;				/* 変換対象リスト */
	DWORD		num_token ;				/* 変換対象中のトークン数 */
	DWORD		line_idx ;				/* 辞書行番号 */
	PDictLine	dict_line ;				/* 辞書行 */
	DWORD		item_idx ;				/* 辞書項目番号 */
	PDictItem	dict_item ;				/* 現在辞書項目 */
	DWORD		muhenkan ;				/* 無変換モード(0=変換) */

	BOOL		conv_first() ;
	BOOL		conv_next() ;
	void		get_top( LPSTR buf ) ;
	void		get_conv( LPSTR buf ) ;
	void		get_all( LPSTR buf ) ;
	BOOL		get_muhenkan_str( LPSTR buf ) ;

public:
	void		addchar( CHAR c ) ;
	void		get_zenhira( DWORD n_token, LPSTR buf ) ;
	DWORD		len_zenhira() ;
	void		get_roma( LPSTR buf ) ;
	LPSTR		get_input() {
		return input ;
	}
	BOOL		chop() ;
	void		clear_proposed() ;
	BOOL		read_dict() ;
	DWORD		find( DWORD start ) ;
	PDictItem	get_dict_item() {
		return dict_item ;
	}
	void		drop_top( LPSTR buf ) ;
	void		drop_conv( LPSTR buf ) ;
	void		drop_all( LPSTR buf ) ;
	void		clear() ;
	void		shrink() ;
	void		grow() ;
	void		set_dict( PFepDict d ) ;
	BOOL		space() ;
	BOOL		is_converting() const ;
	BOOL		is_input() const ;
	void		confirm() ;
	BOOL		add_item( LPCSTR i ) ;
	void		get_fep_line( LPSTR buf, DWORD size ) ;
	BOOL		conv_prev() ;
	void		set_muhenkan( CHAR c ) ;
	BOOL		is_muhenkan() { return muhenkan ; }
	void		drop_muhenkan( LPSTR buf ) ;

	FepCtrl() {
		input[0] = 0 ;
		dict = 0 ;
		num_token = 0 ;
		dict_line = 0 ;
		dict_item = 0 ;
		muhenkan = MODE_NORMAL ;
	}
} ;
