/*
 * CONSOLE : Consoleプログラム：メインルーチン
 * Copyright(C) 1997-1999 Eiichiro Ito, Yasuhiro Mizukoshi
 *
 * 1997/07/04:Eiichiro Ito
 *  (1) 作成開始
 * 修正履歴
 * 1998/02/15:Yasuhiro Mizukoshi
 *  (1) ESCシーケンス対応
 * 1998/02/19:Eiichiro Ito
 *  (1) 画面更新ロジック修正
 * 1998/02/20:Eiichiro Ito
 *  (1) 反転表示対応
 * 1998/03/31:Eiichiro Ito
 *  (1) PalmPC向けにメニューを修正
 *  (2) アクティブ時にFEPを英数モードにする
 * 1998/04/11:Eiichiro Ito
 *  (1) FEP制御部分のソースを分離
 *
 */
#define	STRICT
#include	<windows.h>
#include	<string.h>
#include	<tchar.h>
#include	<windowsx.h>
#include	<commctrl.h>
#include	"resource.h"
#include	"tty.h"
#include	"client.h"
#include	"kctrl.h"
#include	"fepbox.h"

#define		VALID_KCTRL_VERSION		(13)
#define		BaseKey					TEXT("Software\\Gawaro\\Console\\Env")
#define		VAR_FEPOPTION			TEXT("FepOpt")
#define		VAR_EXITONNOCLIENT		TEXT("ExitOnNoClient")

HINSTANCE	hInst ;
HWND		hMainWnd ;
HWND		hCmdBar ;
HACCEL		hAccl ;
TCHAR		szWinName[] = TcpServer ;
DWORD		AppVersion = 28 ;
DWORD		DllVersion = 0 ;
TCHAR		MessageBuf[ MAX_PATH ] = TEXT("") ;

BOOL		F_quit = FALSE ;
DWORD		window_top = 0 ;
DWORD		window_width = 480, window_height = 190 ;
DWORD		Char_height = 12 ;
BOOL		g_bExitOnNoClient = TRUE ;
BOOL		g_bForceExit = FALSE ;

static	BOOL	init_application( void ) ;
static	BOOL	init_instance( int nCmdShow ) ;
LRESULT CALLBACK	MainWndFunc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) ;
BOOL CALLBACK		AboutDlgFunc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) ;
static	BOOL	get_reg( void ) ;
static	BOOL	PasteToClient( HWND hWnd ) ;

extern	struct ClientList_t	ClientList[MAX_CLIENT] ;
extern	DWORD				Cur_client ;

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 ;

	hInst = hThisInst ;
	if ( FindWindow( szWinName, NULL ) != NULL ) {
		wsprintf( MessageBuf, TEXT("Already loaded") ) ;
		MessageBox( NULL, MessageBuf, szWinName, MB_OK|MB_ICONASTERISK ) ;
		return FALSE ;
	}
	DllVersion = GetKVersion() ;
	if ( DllVersion < 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, szWinName, MB_OK|MB_ICONASTERISK ) ;
		return FALSE ;
	}
	if ( !InitFep() ) {
		MessageBox( NULL, TEXT("Can't initialize FEP."), szWinName, MB_OK|MB_ICONASTERISK ) ;
		return FALSE ;
	}
	get_reg() ;
	if ( !InitKanjiControls() ) {
		wsprintf( MessageBuf,
				  TEXT("KCTRL.DLL Initialize error\r\nError=%x"),
				  GetLastError() ) ;
		MessageBox( NULL, MessageBuf, szWinName, MB_OK|MB_ICONASTERISK ) ;
		return FALSE ;
	}
	Char_height = GetFontH() ;
#ifdef	_WIN32_WCE
	InitCommonControls();
	hAccl = LoadAccelerators( hInst,
							  MAKEINTRESOURCE(IDR_ACCELERATOR1) ) ;
#else	/* _WIN32_WCE */
	hAccl = LoadAccelerators( GetModuleHandle(NULL),
							  MAKEINTRESOURCE(IDR_ACCELERATOR1) ) ;
#endif	/* _WIN32_WCE */
	/* ウィンドウクラスを定義する */
	if ( !init_application() ) {
		goto ExitMain ;
	}
	/* ウィンドウを作成する */
	if ( !init_instance( nWinMode ) ) {
		goto ExitMain ;
	}
	/* コンソール画面の初期化 */
	tty_setwindow( 0, window_top, window_width, window_height, GetFontHW(), Char_height + 1 ) ;
	if ( !tty_init() ) {
		ReleaseKanjiControls() ;
		goto ExitMain ;
	}
	while ( GetMessage( &msg, NULL, 0, 0 ) ) {
		if ( !TranslateAccelerator( hMainWnd, hAccl, &msg ) ) {
			TranslateMessage( &msg ) ;
		}
		DispatchMessage( &msg ) ;
	}
	tty_release() ;

ExitMain:
	ReleaseKanjiControls() ;
	return TRUE ;
}

static	BOOL
init_application( void )
{
	WNDCLASS	wcl ;

	/* メインウィンドウクラスを登録する */
	wcl.hInstance = hInst ;
	wcl.lpszClassName = szWinName ;
	wcl.lpfnWndProc = MainWndFunc ;
	wcl.style = CS_HREDRAW|CS_VREDRAW ;
	wcl.hIcon   = NULL ;
	wcl.hCursor = NULL ;
#ifdef	_WIN32_WCE
	wcl.lpszMenuName = 0 ;
#else	/* _WIN32_WCE */
	wcl.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1) ;
#endif	/* _WIN32_WCE */
	wcl.cbClsExtra = 0 ;
	wcl.cbWndExtra = 0 ;
	wcl.hbrBackground = GetStockObject( WHITE_BRUSH ) ;
	if ( !RegisterClass( &wcl ) ) {
		return FALSE ;
	}
	return TRUE ;
}

static	BOOL
init_instance( int nCmdShow )
{
	const	DWORD	x0 = 0 ;
	RECT	rect ;

	/* メインウィンドウを作成する */
	hMainWnd = CreateWindowEx( 0, szWinName, szWinName, WS_VISIBLE,
#ifdef	_WIN32_WCE
						0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
#else	/* _WIN32_WCE */
						0, 0, 480, 240,
#endif	/* _WIN32_WCE */
						NULL, NULL, hInst, NULL ) ;
	if ( !hMainWnd ) {
		return FALSE;
	}
#ifdef	_WIN32_WCE
	/* コマンドバーを作成する */
	hCmdBar = CommandBar_Create( hInst, hMainWnd, 1 ) ;
	/* メニューをつける */
	CommandBar_InsertMenubar( hCmdBar, hInst, IDR_MENU1, 0 ) ;
	/* 終了ボタンをつける */
	CommandBar_AddAdornments( hCmdBar, CMDBAR_HELP, 0 ) ;
	window_top = CommandBar_Height( hCmdBar ) ;
#endif	/* _WIN32_WCE */
	GetClientRect( hMainWnd, &rect ) ;
	window_width  = rect.right - rect.left + 1 ;
	window_height = rect.bottom - rect.top + 1 ;
	window_height -= window_top ;
	/* メインウィンドウを表示する */
	ShowWindow( hMainWnd, nCmdShow ) ;
	UpdateWindow( hMainWnd ) ;
	return TRUE ;
}

LRESULT CALLBACK
MainWndFunc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
	TCHAR		c ;
	PAINTSTRUCT	ps ;
	HDC			hDC ;
	PCOPYDATASTRUCT	cds ;
	int			nVirtKey ;
	HICON		hIcon = 0 ;

	switch ( message ) {
	case WM_CREATE:
		hIcon = (HICON) LoadImage( hInst, MAKEINTRESOURCE(IDI_MAIN_ICON),
								  IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ) ;
		if ( hIcon ) {
			SendMessage( hWnd, WM_SETICON, FALSE, (LPARAM)hIcon ) ;
		}
		break ;
	case WM_DESTROY:
		PostQuitMessage( 0 ) ;
		break ;
    case WM_SETFOCUS:
        if ( CreateCaret( hWnd, NULL, 2, Char_height ) ) {
            ShowCaret( hWnd ) ;
			tty_setcaret() ;
        }
        return DefWindowProc( hWnd, message, wParam, lParam ) ;
    case WM_KILLFOCUS:
        HideCaret( hWnd ) ;
        DestroyCaret() ;
        return DefWindowProc( hWnd, message, wParam, lParam ) ;
	case WM_PAINT:
		HideCaret( hWnd ) ;
		hDC = BeginPaint( hWnd, &ps ) ;
		tty_invalidate( &ps.rcPaint ) ;
		tty_draw( hWnd, hDC ) ;
		EndPaint( hWnd, &ps ) ;
		ShowCaret( hWnd ) ;
		return DefWindowProc( hWnd, message, wParam, lParam ) ;
	case WM_CHAR:
		if ( Fep_WM_CHAR( hWnd, (TCHAR) wParam, (LONG) lParam ) ) {
			break ;
		}
		c = (TCHAR) wParam ;
		switch (CurTerm.ttymode){
		case TTY_VT100:
			if ( c == TEXT(' ') && GetAsyncKeyState( VK_CONTROL ) ) {
				c = TEXT('\0') ;
			}
			client_send( c ) ;
			if ( c == TEXT('\r') && IsSetMode( NEWL_LF ) ) {
				client_send( TEXT('\n') ) ;
			}
			break;
		case TTY_NORMAL:
		default:
			client_send( c ) ;
			break ;
		}
		return TRUE ;
	case WM_SYSCHAR:
		if ( Fep_WM_SYSCHAR( hWnd, (TCHAR) wParam, (LONG) lParam ) ) {
			break ;
		}
		return DefWindowProc( hWnd, message, wParam, lParam ) ;
	case WM_KEYDOWN:
		nVirtKey = (int) wParam ;
		switch ( nVirtKey ) {
		case VK_UP:
			switch ( CurTerm.ttymode ) {
			case TTY_VT100:
				str_client_send( IsSetMode(CURSORKEY) ? TEXT("\033OA") : TEXT("\033[A") ) ;
				break ;
			case TTY_NORMAL:
			default:
				client_send( 'P' - '@' ) ;
				break ;
			}
			break ;
		case VK_DOWN:
			switch ( CurTerm.ttymode ) {
			case TTY_VT100:
				str_client_send( IsSetMode(CURSORKEY) ? TEXT("\033OB") : TEXT("\033[B") ) ;
				break ;
			case TTY_NORMAL:
			default:
				client_send( 'N' - '@' ) ;
				break ;
			}
			break ;
		case VK_RIGHT:
			switch ( CurTerm.ttymode ) {
			case TTY_VT100:
				str_client_send( IsSetMode(CURSORKEY) ? TEXT("\033OC") : TEXT("\033[C") ) ;
				break ;
			case TTY_NORMAL:
			default:
				client_send( 'F' - '@' ) ;
				break ;
			}
			break;
		case VK_LEFT:
			switch ( CurTerm.ttymode ) {
			case TTY_VT100:
				str_client_send( IsSetMode(CURSORKEY) ? TEXT("\033OD") : TEXT("\033[D") ) ;
				break;
			case TTY_NORMAL:
			default:
				client_send( 'B' - '@' ) ;
				break ;
			}
			break ;
		case VK_DELETE:
			client_send( 0x7F ) ;
			break ;
		}
		break ;
	case WM_COPYDATA:
		cds = (PCOPYDATASTRUCT) lParam ;
		hDC = GetDC( hWnd ) ;
		switch ( cds->dwData ) {
		case TTY_VT100:
			if ( CurTerm.ttymode == TTY_NORMAL ) {
				CurTerm.ttymode = TTY_VT100 ;
			}
			vt100_addstr( hWnd, hDC, (LPCTSTR) cds->lpData ) ;
			break ;
		case TTY_NORMAL:
		default:
			tty_addstr( hWnd, hDC, (LPCTSTR) cds->lpData ) ;
			break ;
		}
		ReleaseDC( hWnd, hDC ) ;
		return TRUE ;
	case WM_COMMAND:
		switch ( GET_WM_COMMAND_ID( wParam, lParam ) ) {
		case IDM_EXIT:
			SendMessage( hWnd, WM_CLOSE, 0, 0 ) ;
			break ;
		case IDM_FEPOK:
			return IDM_FEPCHAR ;
		case IDM_FEPCHAR:
			c = (TCHAR) lParam ;
			c = c == TEXT('\n') ? TEXT('\r') : c ;
			client_send( c ) ;
			break ;
		case IDM_ADDCHAR:
			hDC = GetDC( hWnd ) ;
			tty_addchar( hWnd, hDC, (TCHAR) lParam ) ;
			ReleaseDC( hWnd, hDC ) ;
			break ;
		case IDM_ADDCLIENT:
			return client_add( (HANDLE) lParam ) ;
		case IDM_DELCLIENT:
			client_del( (HANDLE) lParam ) ;
			if ( g_bExitOnNoClient && !client_exists() ) {
				/* 確認なしで終了する */
				g_bForceExit = TRUE ;
				SendMessage( hWnd, WM_CLOSE, 0, 0 ) ;
			}
			break ;
		case IDM_CLS:
			hDC = GetDC( hWnd ) ;
	        HideCaret( hWnd ) ;
			tty_cls() ;
			tty_draw( hWnd, hDC ) ;
            ShowCaret( hWnd ) ;
			ReleaseDC( hWnd, hDC ) ;
			break ;
		case IDM_GETWH:
			return tty_getwh() ;
		case IDM_GETCUR:
			return tty_getcur() ;
		case IDM_SETCUR:
			tty_setcur( (DWORD) lParam ) ;
			return TRUE ;
		case IDM_CLEAR:
			hDC = GetDC( hWnd ) ;
			tty_cleareol( hWnd, hDC ) ;
			ReleaseDC( hWnd, hDC ) ;
			return TRUE ;
		case IDM_GETINDEX:
			return client_getindex( (HWND) lParam ) ;
		case IDM_SWITCH:
			return client_switch( (DWORD) lParam ) ;
		case IDM_BREAK:
			client_break() ;
			return TRUE ;
		case IDM_SCROLLUP:
			hDC = GetDC( hWnd ) ;
			tty_scroll_up( hWnd, hDC, (DWORD) (lParam / 256), (DWORD) (lParam % 256) ) ;
			ReleaseDC( hWnd, hDC ) ;
			return TRUE ;
		case IDM_SCROLLDOWN:
			hDC = GetDC( hWnd ) ;
			tty_scroll_down( hWnd, hDC, (DWORD) (lParam / 256), (DWORD) (lParam % 256) ) ;
			ReleaseDC( hWnd, hDC ) ;
			return TRUE ;
		case IDM_RESETTERMINAL:
			CurTerm.ttymode = TTY_NORMAL ;
			return TRUE ;
		case IDM_GETVERSION:
			return AppVersion ;
		case IDM_ABOUT:
			/* Aboutダイアログを表示する */
			DialogBox( hInst, MAKEINTRESOURCE(IDD_ABOUTDLG), hWnd, AboutDlgFunc ) ;
			return TRUE ;
		case IDM_PASTE:
			PasteToClient( hWnd ) ;
			break ;
		case IDM_SETATTR:
			tty_setattr( (BYTE) lParam ) ;
			break ;
		}
		break ;
	case WM_HELP:
		SendMessage( hWnd, WM_COMMAND, IDM_ABOUT, 0 ) ;
		break ;
	case WM_CLOSE:
		if ( !g_bForceExit && client_exists() ) {
			if ( MessageBox( hWnd, TEXT("Client exists, Are you sure?"), TEXT("Exit Console"), MB_YESNO|MB_ICONQUESTION ) != IDYES ) {
				break ;
			}
		}
		client_killall() ;
		DestroyWindow( hWnd ) ;
		break ;
	case WM_ACTIVATE:
		Fep_WM_ACTIVATE( hWnd, LOWORD(wParam), (BOOL) HIWORD(wParam), (HWND) lParam ) ;
		return DefWindowProc( hWnd, message, wParam, lParam ) ;
	default:
		return DefWindowProc( hWnd, message, wParam, lParam ) ;
	}
	return 0 ;
}

BOOL CALLBACK
AboutDlgFunc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
	TCHAR	buf[ MAX_PATH + 1 ] ;

	switch ( message ) {
	case WM_INITDIALOG:
		/* アプリケーションバージョン */
		wsprintf( buf, TEXT("%s Ver %d.%02d  for WindowsCE"),
				  szWinName, AppVersion / 100, AppVersion % 100 ) ;
		SendDlgItemMessage( hDlg, IDC_VERSION,
							WM_SETTEXT, 0, (LPARAM)buf ) ;
		/* DLLバージョン */
		wsprintf( buf, TEXT("KCTRL.DLL Ver %d.%02d"),
				  DllVersion / 100, DllVersion % 100 ) ;
		SendDlgItemMessage( hDlg, IDC_DLLVERSION,
							WM_SETTEXT, 0, (LPARAM)buf ) ;
		return TRUE ;
	case WM_COMMAND:
		switch ( GET_WM_COMMAND_ID( wParam, lParam ) ) {
		case IDOK:
		case IDCANCEL:
			EndDialog( hDlg, TRUE ) ;
			return TRUE ;
		}
		break ;
	}
	return FALSE ;
}

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

	/* レジストリキーをオープンする */
	lret = RegOpenKeyEx( HKEY_CURRENT_USER, BaseKey, 0,
						 KEY_QUERY_VALUE, &hk ) ;
	if ( lret == ERROR_SUCCESS ) {
		/* オプション */
		name = VAR_FEPOPTION ;
		dwType = REG_SZ ;
		lpData = (LPBYTE) sValue ;
		cbData = sizeof sValue ;
		if ( RegQueryValueEx( hk, name, NULL, &dwType, lpData, &cbData ) == ERROR_SUCCESS ) {
			g_fFepOption = _ttoi( sValue ) ;
		}
		/* クライアントが無い状態でConsole自体を終了するかどうか */
		name = VAR_EXITONNOCLIENT ;
		dwType = REG_SZ ;
		lpData = (LPBYTE) sValue ;
		cbData = sizeof sValue ;
		if ( RegQueryValueEx( hk, name, NULL, &dwType, lpData, &cbData ) == ERROR_SUCCESS ) {
			g_bExitOnNoClient = _ttoi( sValue ) ;
		}
		/* レジストリクローズ */
		RegCloseKey( hk ) ;
	}
	return TRUE ;
}

static	BOOL
PasteToClient( HWND hWnd )
{
	HLOCAL		hGMem ;

	if ( !OpenClipboard( hWnd ) ) {
		return FALSE ;
	}
	hGMem = GetClipboardData( CF_UNICODETEXT ) ;
	if ( hGMem ) {
		str_client_send( (LPCTSTR) hGMem ) ;
	}
	CloseClipboard() ;
	return TRUE ;
}
