/*
 * NG : NGプログラム：メインルーチン
 *
 * 1998/11/14:Eiichiroh Itoh
 *  (1) 作成開始
 * 修正履歴
 *
 */
#define	STRICT
#include	<windows.h>
#include	<windowsx.h>
#include	<string.h>
#include	<tchar.h>
#include	<excpt.h>
#include	"kctrl.h"
#include	"cectrl.h"
#include	"cefep.h"
#include	"resource.h"
#include	"cemain.h"

#define		VALID_KCTRL_VERSION		(13)
#define		EXCEPTION_QUIT			(1)
#define		IDM_START				(1001)
#define		IDM_EXIT				(1002)
#define		IDC_TTY					(2001)

HINSTANCE	g_hInst ;
HWND		g_hwndMain ;
HWND		g_hwndTty ;
HANDLE		g_hevtGetChar = 0 ;
HANDLE		g_hThread = 0 ;
BOOL		g_bExit = FALSE ;
TCHAR		g_szTitleName[ MAX_PATH ] = TEXT("Ng") ;
TCHAR		g_szClassName[] = TEXT("NG") ;
DWORD		g_dwAppVersion = 12 ;
DWORD		g_dwDllVersion = 0 ;
TCHAR		MessageBuf[ MAX_PATH ] = TEXT("") ;
CHAR		g_szArgBuf[ 256 ] ;
int			g_dwArgc ;
LPSTR		g_szArgv[ 128 ] ;

static	BOOL	init_application( void ) ;
static	BOOL	init_instance( int nCmdShow ) ;
LRESULT CALLBACK	MainWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) ;
static	void	cmdline2args( LPSTR cmdline, int *argc, char **argv ) ;
static	void	ThreadMain( void ) ;

int WINAPI
#ifdef	_WIN32_WCE
WinMain( HINSTANCE hThisInst, HINSTANCE hPrevInst,
		 LPTSTR lpszArgs, int nWinMode )
#else	/* _WIN32_WCE */
WinMain( HINSTANCE hThisInst, HINSTANCE hPrevInst,
		 LPSTR lpszArgs, int nWinMode )
#endif	/* _WIN32_WCE */
{
	MSG			msg ;

	g_hInst = hThisInst ;
	g_dwDllVersion = GetKVersion() ;
	if ( g_dwDllVersion < VALID_KCTRL_VERSION ) {
		wsprintf( MessageBuf,
				  TEXT("Obsolete KCTRL.DLL used\r\nPlease use Ver%d.%02d or later"),
				  VALID_KCTRL_VERSION / 100, VALID_KCTRL_VERSION % 100 ) ;
		MessageBox( NULL, MessageBuf, g_szTitleName, MB_OK|MB_ICONASTERISK ) ;
		return FALSE ;
	}
	if ( !InitFep() ) {
		MessageBox( NULL, TEXT("Can't initialize FEP."), g_szTitleName, MB_OK|MB_ICONASTERISK ) ;
		return FALSE ;
	}
	if ( !InitKanjiControls() ) {
		wsprintf( MessageBuf,
				  TEXT("KCTRL.DLL Initialize error\r\nError=%x"),
				  GetLastError() ) ;
		MessageBox( NULL, MessageBuf, g_szTitleName, MB_OK|MB_ICONASTERISK ) ;
		return FALSE ;
	}
	/* TTYウィンドウを定義する */
	if ( !TtyViewRegisterClass( g_hInst ) ) {
		goto ExitMain ;
	}
	/* キーボード入力通知用イベントを作成する */
	g_hevtGetChar = CreateEvent( NULL, FALSE, FALSE, NULL ) ;
	if ( g_hevtGetChar == NULL ) {
		goto ExitMain ;
	}
	/* ウィンドウクラスを定義する */
	if ( !init_application() ) {
		goto ExitMain ;
	}
	/* ウィンドウを作成する */
	if ( !init_instance( nWinMode ) ) {
		goto ExitMain ;
	}
	/* コマンドライン部を作成する */
#ifdef	_WIN32_WCE
	unicode2sjis( lpszArgs, g_szArgBuf, sizeof g_szArgBuf ) ;
#else	/* _WIN32_WCE */
	strcpy( lpszArgs, g_szArgBuf ) ;
#endif	/* _WIN32_WCE */
	cmdline2args( g_szArgBuf, &g_dwArgc, g_szArgv ) ;
	/* イベントループ */
	while ( GetMessage( &msg, NULL, 0, 0 ) ) {
		TranslateMessage( &msg ) ;
		DispatchMessage( &msg ) ;
	}

ExitMain:
	if ( g_hevtGetChar ) {
		/* キーボード入力通知用イベントをクローズする */
		CloseHandle( g_hevtGetChar ) ;
	}
	ReleaseKanjiControls() ;
	return TRUE ;
}

/*
 * メインウィンドウクラスを登録する
 */
static	BOOL
init_application( void )
{
	WNDCLASS	wcl ;

	wcl.style         = 0 ;
	wcl.lpfnWndProc   = MainWndProc ;
	wcl.cbClsExtra    = 0 ;
	wcl.cbWndExtra    = 0 ;
	wcl.hInstance     = g_hInst ;
	wcl.hIcon         = NULL ;
	wcl.hCursor       = NULL ;
	wcl.hbrBackground = (HBRUSH) GetStockObject( WHITE_BRUSH ) ;
	wcl.lpszMenuName  = 0 ;
	wcl.lpszClassName = g_szClassName ;
	if ( !RegisterClass( &wcl ) ) {
		return FALSE ;
	}
	return TRUE ;
}

/*
 * メインウィンドウを作成する
 */
static	BOOL
init_instance( int nCmdShow )
{
	RECT	rect ;

	/* メインウィンドウを作成する */
	g_hwndMain = CreateWindowEx( 0, g_szClassName,
					g_szTitleName,
					WS_VISIBLE,
#ifdef	_WIN32_WCE
					0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
#else	/* _WIN32_WCE */
					0, 0, 480, 240,
#endif	/* _WIN32_WCE */
					NULL, NULL, g_hInst, NULL ) ;
	if ( !g_hwndMain ) {
		return FALSE;
	}
	GetClientRect( g_hwndMain, &rect ) ;

	/* TTYウィンドウを作成する */
	g_hwndTty = CreateWindowEx( 0, CTRL_TTYVIEW,
					TEXT(""),
					WS_VISIBLE|WS_CHILD,
					0, 0, rect.right, rect.bottom,
					g_hwndMain, (HMENU) IDC_TTY, g_hInst, NULL ) ;
	if ( !g_hwndTty ) {
		return FALSE;
	}
	/* キーボード入力通知用イベントを設定する */
	SendMessage( g_hwndTty, TTYM_SETEVENT, (WPARAM) g_hevtGetChar, 0 ) ;

	/* メインウィンドウを表示する */
	ShowWindow( g_hwndMain, nCmdShow ) ;
	UpdateWindow( g_hwndMain ) ;
	SetFocus( g_hwndTty ) ;

	/* スレッド開始のメッセージを送る */
	PostMessage( g_hwndMain, WM_COMMAND, IDM_START, 0 ) ;
	return TRUE ;
}

void
MainWMCreate( HWND hWnd )
{
	HICON	hIcon ;

	hIcon = (HICON) LoadImage( g_hInst, MAKEINTRESOURCE(IDI_APPICON),
							  IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ) ;
	if ( hIcon ) {
		SendMessage( hWnd, WM_SETICON, FALSE, (LPARAM)hIcon ) ;
	}
}

/*
 * メインウィンドウのWinProc
 */
LRESULT CALLBACK
MainWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
	DWORD	threadID ;

	switch ( message ) {
	case WM_CREATE:
		MainWMCreate( hWnd ) ;
		break ;
	case WM_CLOSE:
		DestroyWindow( hWnd ) ;
		break ;
	case WM_DESTROY:
		g_bExit = TRUE ;
		Sleep( 1000 ) ;
		PostQuitMessage( 0 ) ;
		break ;
	case WM_SETFOCUS:
		SetFocus( g_hwndTty ) ;
		break ;
	case WM_COMMAND:
		switch ( GET_WM_COMMAND_ID( wParam, lParam ) ) {
		case IDM_START:
			g_hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE) ThreadMain, 0, 0, &threadID ) ;
			if ( g_hThread != NULL ) {
				CloseHandle( g_hThread ) ;
				break ;
			}
			//
		case IDM_EXIT:
			SendMessage( hWnd, WM_CLOSE, 0, 0 ) ;
			break ;
		}
		break ;
	default:
		return DefWindowProc( hWnd, message, wParam, lParam ) ;
	}
	return 0 ;
}

int
Kbhit( void )
{
	return SendMessage( g_hwndTty, TTYM_KBHIT, 0, 0 ) ? 1 : 0 ;
}

int
KbhitSleep( DWORD sec )
{
	WaitForSingleObject( g_hevtGetChar, sec * 1000 ) ;
	if ( g_bExit ) {
		ExitThread( 0 ) ;
		return FALSE ;
	}
	return Kbhit() ;
}

int
GetChar( void )
{
	int		c ;

	while ( 1 ) {
		c = SendMessage( g_hwndTty, TTYM_GETCHAR, 0, 0 ) ;
		if ( c != -1 ) {
			break ;
		}
		WaitForSingleObject( g_hevtGetChar, INFINITE ) ;
		if ( g_bExit ) {
			ExitThread( 0 ) ;
			break ;
		}
	}
	ResetEvent( g_hevtGetChar ) ;
	return c ;
}

void
GotoXY( int x, int y )
{
	SendMessage( g_hwndTty, TTYM_GOTOXY, MAKEWPARAM( y, x ), 0 ) ;
}

void
EraseEOL( void )
{
	SendMessage( g_hwndTty, TTYM_ERASEEOL, 0, 0 ) ;
}

void
EraseEOP( void )
{
	SendMessage( g_hwndTty, TTYM_ERASEEOP, 0, 0 ) ;
}

void
PutChar( char c )
{
	SendMessage( g_hwndTty, TTYM_PUTCHAR, (WPARAM) c, 0 ) ;
}

void
PutKChar( char c1, char c2 )
{
	SendMessage( g_hwndTty, TTYM_PUTCHAR, MAKEWPARAM( c2, c1 ), 0 ) ;
}

void
PutLine( int y, unsigned char *sjis, short color )
{
	SendMessage( g_hwndTty, TTYM_PUTLINE, MAKEWPARAM( color, y ), (LPARAM) sjis ) ;
}

void
Flush( void )
{
	SendMessage( g_hwndTty, TTYM_FLUSH, 0, 0 ) ;
}

void
GetWH( int *w, int *h )
{
	DWORD	ret ;

	ret = SendMessage( g_hwndTty, TTYM_GETWH, 0, 0 ) ;
	*w = HIWORD( ret ) ;
	*h = LOWORD( ret ) ;
}

void
Exit( int code )
{
	RaiseException( EXCEPTION_QUIT, 0, 0, 0 ) ;
}

void
MessageOut( LPCSTR buf )
{
	sjis2unicode( buf, MessageBuf, sizeof MessageBuf ) ;
	MessageBox( g_hwndMain, MessageBuf, TEXT("NG"), MB_OK ) ;
}

/*
 * コマンドライン関係
 */
static void
cmdline2args( LPSTR cmdline, int *argc, char **argv )
{
	CHAR	c ;
	BOOL	f_skip = TRUE, f_quote = FALSE ;

	argv[ 0 ] = "" ;
	*argc = 1 ;
	while ( c = *cmdline ) {
		if ( f_skip ) {
			if ( !(c == ' ' || c == '\t') ) {
				if ( c == '"' ) {
					f_quote = TRUE ;
					cmdline ++ ;
				}
				argv[ (*argc) ++ ] = cmdline ;
				f_skip = FALSE ;
			}
		} else {
			if ( f_quote ) {
				if ( c == '"' ) {
					f_quote = FALSE ;
					*cmdline = 0 ;
					f_skip = TRUE ;
				}
			} else if ( (c == ' ' || c == '\t') ) {
				*cmdline = 0 ;
				f_skip = TRUE ;
			}
		}
		cmdline ++ ;
	}
}

/*
 * スレッドのメインルーチン
 */
static void
ThreadMain( void )
{
	__try {
		Main( g_dwArgc, g_szArgv ) ;
	} __except ( GetExceptionCode() == EXCEPTION_QUIT ) {
		// do nothing
	}
	SendMessage( g_hwndMain, WM_COMMAND, IDM_EXIT, 0 ) ;
	ExitThread( 0 ) ;
}

int
toggle_fep( int f, int n )
{
	Fep_Execute( g_hwndMain ) ;
	return TRUE ;
}
