/*
    KCTRL - Dynamic Link Library of Japanization Toolkit for Windows CE
    Copyright (C) 1997-2001  ITO, Eiichiro

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library 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.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#ifndef	STRICT
#define	STRICT
#endif	/* STRICT */
#ifndef	UNICODE
#define	UNICODE
#endif	/* UNICODE */
#ifndef	_UNICODE
#define	_UNICODE
#endif	/* _UNICODE */
#include	<windows.h>
#include	<windowsx.h>
#include	<winuser.h>
#include	<string.h>
#include	<commctrl.h>
#include	<commdlg.h>
#include	<tchar.h>
#include	"kctrl.h"

#ifdef	KCTRL_20
extern	DWORD	FontZenVW ;
extern	DWORD	FontHanVW ;
extern	DWORD	FontVH ;
extern	DWORD	TabWidth ;
extern	DWORD	F_convmode ;

#define		MAX_FONT		2
#define		iskanji(x)		(((x)>=0x81 && (x)<=0x9F)||((x)>=0xE0 && (x)<=0xFC))
#define		BaseKey			TEXT("Software\\Gawaro\\Kctrl")
#define		VAR_TTFONT		TEXT("TTFont")
#define		VAR_FONTWIDTH	TEXT("FontWidth")
#define		VAR_FONTHEIGHT	TEXT("FontHeight")

static	BOOL	get_reg( void ) ;
static	void	enum_fonts( void ) ;

HFONT		hFont[ MAX_FONT ] ;
LOGFONT		LF_MSG[ MAX_FONT ] = {
	{ 14, 7, 0, 0, 0x190, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x02,
		TEXT("CEFONT") },
	{ 12, 6, 0, 0, 0x190, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x02,
		TEXT("CEFONT") },
} ;

DWORD		g_dwCurFont = 0 ;

BOOL
InitLocal( void )
{
	int		i ;
	TCHAR	buf[ 128 ] ;

	get_reg() ;
	enum_fonts() ;
	for ( i = 0 ; i < MAX_FONT ; i ++ ) {
		hFont[i] = CreateFontIndirect( &LF_MSG[i] ) ;
		if ( !hFont[i] ) {
			wsprintf( buf, TEXT("Error: %d\r\n Font:[%s]"),
					  GetLastError(), LF_MSG[i].lfFaceName ) ;
			MessageBox( NULL, buf, TEXT("InitLocal"), MB_OK|MB_ICONASTERISK ) ;
		}
	}
	g_dwCurFont = 0 ;
	FontHanVW = LF_MSG[g_dwCurFont].lfWidth ;
	FontZenVW = LF_MSG[g_dwCurFont].lfWidth * 2 ;
	FontVH    = LF_MSG[g_dwCurFont].lfHeight + 1 ;
	SetLastError( 0 ) ;
	return TRUE ;
}

void
ReleaseLocal( void )
{
	int		i ;

	for ( i = 0 ; i < MAX_FONT ; i ++ ) {
		if ( hFont[i] ) {
			DeleteObject( hFont[i] ) ;
		}
	}
}

void
KDrawText( HDC hDC, LPCTSTR str, int len, LPRECT pos, UINT format )
{
	RECT	rect ;
	DWORD	col = 0, cw = 0, num = 0, max  ;
	TCHAR	c, outbuf[ 256 ], *dst = outbuf ;
	HFONT	oldfont = SelectObject( hDC, hFont[g_dwCurFont] ) ;

	max = (sizeof outbuf / sizeof *outbuf) - TabWidth - 8 ;
	while ( (c = *str++) && (num < max) ) {
		if ( c == 9 ) {
			cw = TabWidth - (col % TabWidth) ;
			col += cw ;
			do {
				*dst++ = TEXT(' ') ;
				num ++ ;
			} while ( -- cw ) ;
			continue ;
		} else if ( c & 0xFF00 ) {
			col ++ ;
		}
		col ++ ;
		*dst++ = c ;		num ++ ;
	}
	*dst = 0 ;
	memcpy( &rect, pos, sizeof (RECT) ) ;
	if ( !(rect.top > rect.bottom && rect.right == 640 && rect.bottom == 16) ) {
		rect.bottom = rect.top + FontVH - 1 ;
	}
	FillRect( hDC, &rect, GetStockObject( WHITE_BRUSH ) ) ;
	DrawText( hDC, outbuf, len, &rect, format|DT_NOPREFIX ) ;
	SelectObject( hDC, oldfont ) ;
}

void
KDrawTextW( HDC hDC, LPCTSTR str, int len, LPRECT pos, UINT format )
{
	KDrawText( hDC, str, len, pos, format ) ;
}

void
KDrawTextI( HDC hDC, LPCTSTR str, int len, LPRECT pos, UINT format )
{
	RECT	rect ;
	DWORD	col = 0, cw = 0, num = 0, max  ;
	TCHAR	c, outbuf[ 256 ], *dst = outbuf ;
	HFONT	oldfont = SelectObject( hDC, hFont[g_dwCurFont] ) ;
	HBRUSH	hOldBrush = SelectObject( hDC, WHITE_BRUSH ) ;

	max = (sizeof outbuf / sizeof *outbuf) - TabWidth - 8 ;
	while ( (c = *str++) && (num < max) ) {
		if ( c == 9 ) {
			cw = TabWidth - (col % TabWidth) ;
			col += cw ;
			do {
				*dst++ = TEXT(' ') ;
				num ++ ;
			} while ( -- cw ) ;
			continue ;
		} else if ( c & 0xFF00 ) {
			col ++ ;
		}
		col ++ ;
		*dst++ = c ;		num ++ ;
	}
	*dst = 0 ;
	memcpy( &rect, pos, sizeof (RECT) ) ;
	DrawText( hDC, outbuf, len, &rect, DT_CALCRECT|DT_NOPREFIX ) ;
	FillRect( hDC, pos, GetStockObject( WHITE_BRUSH ) ) ;
	DrawText( hDC, outbuf, len, pos, format|DT_NOPREFIX ) ;
	PatBlt( hDC,
			rect.left, rect.top, rect.right - rect.left + 1, rect.bottom - rect.top + 1,
			PATINVERT ) ;
	SelectObject( hDC, hOldBrush ) ;
	SelectObject( hDC, oldfont ) ;
}

/* SJIS <-> Unicode変換テーブル */
typedef struct {
	WORD	startCode, endCode ;
} SEGTABLE ;

const	SEGTABLE	UniSegTable[] = {
#include	"uniseg.h"
} ;
#define		Num_UniSegTable		(sizeof (UniSegTable)/sizeof (*UniSegTable))

const	SEGTABLE	SjisSegTable[] = {
#include	"sjisseg.h"
} ;
#define		Num_SjisSegTable	(sizeof (SjisSegTable)/sizeof (*SjisSegTable))

const	WORD		Uni2Sjis[] = {
#include	"uni2sjis.h"
} ;

const	WORD		Sjis2Uni[] = {
#include	"sjis2uni.h"
} ;

/*
 * 　名称：Unicode→SJISコード変換
 * 　略称：unicode2sjis
 * 　概要：Unicode文字列をSJIS文字列に変換する
 * 引き数：src = Unicode文字列
 * 　　　：dst = SJIS文字列を格納する領域へのポインタ
 * 　　　：max = SJIS文字列を格納する領域の最大バイト数
 * 戻り値：DWORD = 変換結果のバイト数(dst=0の時は必要バイト数)\0も含む
 */
DWORD
unicode2sjis( LPCTSTR src, BYTE *dst, DWORD max )
{
	WORD		sjis ;
	DWORD		count ;
	TCHAR		unicode ;

	count = 0 ;
	if ( dst ) {
		if ( max <= 1 ) {
			return count ;
		}
		max -- ;
	}
	while ( unicode = *src++ ) {
		sjis = unicode2sjis_char( unicode ) ;
		if ( sjis == 0xFFFF ) {
			continue ;
		}
		if ( sjis >= 0x0100 ) {
			count ++ ;
			if ( dst ) {
				*dst++ = (BYTE) (sjis / 0x0100) ;
				if ( !(-- max) ) {
					break ;
				}
			}
		}
		count ++ ;
		if ( dst ) {
			*dst++ = (BYTE) (sjis % 0x0100) ;
			if ( !(-- max) ) {
				break ;
			}
		}
	}
	count ++ ;
	if ( dst ) {
		*dst = 0 ;
	}
	return count ;
}

/*
 * 　名称：SJIS→Unicodeコード変換
 * 　略称：sjis2unicode
 * 　概要：SJIS文字列をUnicode文字列に変換する
 * 引き数：src = SJIS文字列
 * 　　　：dst = Unicode文字列を格納する領域へのポインタ
 * 　　　：max = Unicode文字列を格納する領域の最大バイト数
 * 戻り値：DWORD = 変換結果のバイト数(dst=0の時は必要バイト数)\0も含む
 */
DWORD
sjis2unicode( const BYTE *src, LPTSTR dst, DWORD max )
{
	BYTE		c1 ;
	WORD		sjis ;
	DWORD		count ;

	count = 0 ;
	if ( dst ) {
		max /= sizeof (TCHAR) ;
		if ( max <= 1 ) {
			return count * sizeof (TCHAR) ;
		}
		max -- ;
	}
	while ( ( sjis = (WORD) *src++ ) != 0 ) {
		if ( iskanji( sjis ) ) {
			c1 = *src++ ;
			if ( !c1 ) {
				break ;
			}
			sjis <<= 8 ;
			sjis |= (WORD) c1 ;
		}
		count ++ ;
		if ( dst ) {
			*dst++ = sjis2unicode_char( sjis ) ;
			if ( !(-- max) ) {
				break ;
			}
		}
	}
	count ++ ;
	if ( dst ) {
		*dst = 0 ;
	}
	return count * sizeof (TCHAR) ;
}

static	WORD
find_code( const SEGTABLE *seg, int count, const WORD *codes, WORD code )
{
	int			total ;

	if ( code < 0x20 ) {
		return code ;
	}
	total = 0 ;
	do {
		WORD	startCode = seg->startCode, endCode = seg->endCode ;

		if ( code <= endCode ) {
			if ( code < startCode ) {
				break ;
			}
			return codes[ total + code - startCode ] ;
		}
		total += endCode - startCode + 1 ;
		seg ++ ;
	} while ( -- count ) ;
	return 0xFFFF ;
}

/*
 * 　名称：シフトＪＩＳコード→UNICODE変換
 * 　略称：sjis2unicode_char
 * 　概要：シフトＪＩＳコード文字をUNICODEに変換する
 * 引き数：sjis(WORD) = シフトＪＩＳコード
 * 戻り値：TCHAR = UNICODE
 */
TCHAR
sjis2unicode_char( WORD code )
{
	return (TCHAR) find_code( SjisSegTable, Num_SjisSegTable, Sjis2Uni, code );
}

/*
 * 　名称：UNICODE→シフトＪＩＳコード変換
 * 　略称：unicode2sjis_char
 * 　概要：UNICODE文字をシフトＪＩＳコードに変換する
 * 引き数：unicode(TCHAR) = UNICODE
 * 戻り値：WORD = シフトＪＩＳコード
 */
WORD
unicode2sjis_char( TCHAR code )
{
	return find_code( UniSegTable, Num_UniSegTable, Uni2Sjis, (WORD) code ) ;
}

/*
 * 　名称：半角文字チェック
 * 　略称：is_hankaku
 * 　概要：Unicode文字が半角かどうか調べる
 * 引き数：c = Unicode文字
 * 戻り値：BOOL = TRUE:半角, FALSE:全角
 */
BOOL
is_hankaku( TCHAR c )
{
	return (c >= 0xFF60 && c <= 0xFF9F) || (c < 0x0080) ;
}

/*
 * 　名称：KCTRLロケール取得
 * 　略称：GetKLocale
 * 　概要：KCTRL(US)やKCTRL(JP)などの区別を返す
 * 引き数：なし
 * 戻り値：DWORD = 0:US, 1:JP, ...
 */
DWORD
GetKLocale( void )
{
	return LOCALE_US20 ;
}

/*
 * 　名称：フォント数取得
 * 　略称：GetNumFont
 * 　概要：表示に使用できるフォント数を調べる
 * 引き数：なし
 * 戻り値：DWORD = フォント数
 */
DWORD
GetNumFont( void )
{
	return MAX_FONT ;
}

/*
 * 　名称：利用フォント設定
 * 　略称：SetCurFont
 * 　概要：表示に使用するフォントを決める
 * 引き数：index(DWORD) = 番号(0..1)
 * 戻り値：なし
 */
void
SetCurFont( DWORD index )
{
	g_dwCurFont = index ;
	FontHanVW = LF_MSG[g_dwCurFont].lfWidth ;
	FontZenVW = LF_MSG[g_dwCurFont].lfWidth * 2 ;
	FontVH    = LF_MSG[g_dwCurFont].lfHeight + 1 ;
}

/*
 * 　名称：現在フォント取得
 * 　略称：GetCurFont
 * 　概要：表示に使用しているフォントを調べる
 * 引き数：なし
 * 戻り値：DWORD = 0..1
 */
DWORD
GetCurFont( void )
{
	return g_dwCurFont ;
}

static	BOOL
get_reg( void )
{
	HKEY	hk ;
	LONG	lret ;
	LPBYTE	lpData ;
	DWORD	dwType, cbData, dValue, i ;
	TCHAR	name[ 64 ], sValue[ 256 ] ;

	/* レジストリキーをオープンする */
	lret = RegOpenKeyEx( HKEY_CURRENT_USER, BaseKey, 0,
						 KEY_QUERY_VALUE, &hk ) ;
	if ( lret != ERROR_SUCCESS ) {
		return FALSE ;
	}
	for ( i = 0 ; i < MAX_FONT ; i ++ ) {
		/* TrueTypeフォント名 */
		wsprintf( name, TEXT("%s%d"), VAR_TTFONT, i ) ;
		dwType = REG_SZ ;
		lpData = (LPBYTE) sValue ;
		cbData = sizeof sValue ;
		if ( RegQueryValueEx( hk, name, NULL, &dwType, lpData, &cbData ) == ERROR_SUCCESS ) {
			_tcscpy( LF_MSG[i].lfFaceName, sValue ) ;
		}
		/* フォント幅 */
		wsprintf( name, TEXT("%s%d"), VAR_FONTWIDTH, i ) ;
		dwType = REG_DWORD ;
		lpData = (LPBYTE) &dValue ;
		cbData = sizeof dValue ;
		if ( RegQueryValueEx( hk, name, NULL, &dwType, lpData, &cbData ) == ERROR_SUCCESS ) {
			LF_MSG[i].lfWidth = dValue ;
		}
		/* フォント高 */
		wsprintf( name, TEXT("%s%d"), VAR_FONTHEIGHT, i ) ;
		dwType = REG_DWORD ;
		lpData = (LPBYTE) &dValue ;
		cbData = sizeof dValue ;
		if ( RegQueryValueEx( hk, name, NULL, &dwType, lpData, &cbData ) == ERROR_SUCCESS ) {
			LF_MSG[i].lfHeight = dValue ;
		}
	}
	/* レジストリクローズ */
	RegCloseKey( hk ) ;
	return TRUE ;
}

int CALLBACK
enum_fonts_sub( const LOGFONT *lplf, const TEXTMETRIC *lptm, DWORD dwType, LPARAM lpData )
{
	int		i ;
	LONG	lfWidth, lfHeight ;

	for ( i = 0 ; i < MAX_FONT ; i ++ ) {
		if ( _tcsicmp( lplf->lfFaceName, LF_MSG[ i ].lfFaceName ) ) {
			continue ;
		}
		lfWidth  = LF_MSG[i].lfWidth ;
		lfHeight = LF_MSG[i].lfHeight ;
		memcpy( &LF_MSG[ i ], lplf, sizeof (LOGFONT) ) ;
		LF_MSG[i].lfWidth = lfWidth ;
		LF_MSG[i].lfHeight = lfHeight ;
	}
	return TRUE ;
}

void
enum_fonts( void )
{
	HDC		hDC ;

	hDC = GetDC( NULL ) ;
	EnumFonts( hDC, NULL, enum_fonts_sub, 0 ) ;
	ReleaseDC( NULL, hDC ) ;
}
#endif	/* KCTRL_20 */
