#define	STRICT
#include	<windows.h>
#include	<windowsx.h>
#include	<commctrl.h>
#include	<commdlg.h>
#include	<tchar.h>
#include	"controls.h"
#include	"resource.h"
#include	"appmain.h"

#define		GawaroBaseKey	TEXT("Software\\Gawaro")
#define		MAX_RECENT		10

TCHAR	MessageBuf[ 512 ] ;

extern "C" {
	extern	BYTE	FileBuffer[ 512 ] ;
} ;
BYTE	FileBuffer[ 512 ] ;

void	SplitDirAndFile( LPCTSTR path, LPTSTR dir, LPTSTR fn ) ;
HFONT	CreateListboxFont() ;
void	catdir( LPTSTR body, LPCTSTR adddir, LPTSTR pPrevDir ) ;
void	AddRecent( LPCTSTR pAppName, LPCTSTR pPath ) ;

class MainWindow : public Window {
private:
	MainApp		*m_pApp ;			/* アプリケーションへのポインタ */
	HICON		m_hIcon ;			/* アプリアイコンのハンドル */
	BOOL		m_fUninstall ;		/* アンインストールフラグ */
	HWND		m_hWndTab ;
	HWND		m_hWndCurrent ;

public:
	MainWindow( MainApp *app ) ;

	BOOL	Create() ;
	BOOL	WMCreate( HWND hWnd ) ;
	BOOL	AddTaskBarIcon() const ;
	BOOL	DeleteTaskBarIcon() const ;

	void	WMDestroy() ;
	LRESULT	WMCommand( HWND hWnd, UINT msg, WPARAM wp, LPARAM lp ) ;
	void	WMNotify( HWND hWnd, int idCtrl, LPNMHDR pnmh ) ;
	BOOL	WMClose() ;
	void	WMSetFocus() ;

	static	BOOL	RegisterClass( HINSTANCE hInst ) ;
	static	LPCTSTR	GetClassName() { return TEXT("MINIPAD") ; }
} ;

/*-------------------------------------------------------------------------*
 * FileArea ダイアログ
 *-------------------------------------------------------------------------*/
class FileArea : public Window {
	MainApp		*m_pApp ;			/* アプリケーションへのポインタ */
	TCHAR		m_sWildCard[ MAX_PATH ] ;
	TCHAR		m_sFile[ MAX_PATH ] ;
	TCHAR		m_sDir[ MAX_PATH ] ;
	BOOL		m_fRecent ;

public:
	FileArea( MainApp *app ) ;
	~FileArea() ;

	LPCTSTR	GetDir() const { return m_sDir ; }

	BOOL	WMCreate( HWND hDlg ) ;
	LRESULT	WMCommand( HWND hDlg, UINT msg, WPARAM wp, LPARAM lp ) ;
	void	WMSize( DWORD fwSize, WORD nWidth, WORD nHeight ) ;
	void	WMNotify( HWND hWnd, int idCtrl, LPNMHDR pnmh ) ;
	void	WMSetFocus() ;

	BOOL	EnumDir( HWND hWnd, LPDWORD pCount, LPDWORD pMem ) ;
	BOOL	ListDir( HWND hWnd, LPCTSTR pPrevDir ) ;
	void	InitListDir( HWND hDlg ) ;
	BOOL	ChangeDir( HWND hDlg, LPBOOL pDone ) ;
	BOOL	EnumRecent( HWND hWnd ) ;
	BOOL	SelectRecent( HWND hDlg ) ;
	BOOL	InitListRecent( HWND hDlg ) ;
	void	InitList( HWND hDlg ) ;
	void	Execute( HWND hDlg ) ;

	static LPCTSTR	c_sDir ;
	static LPCTSTR	c_sPatDir ;
	static LPCTSTR	c_sPatFile ;
	static LPCTSTR	c_sFiles ;
} ;

/*-------------------------------------------------------------------------*
 * TaskArea ダイアログ
 *-------------------------------------------------------------------------*/
class TaskArea : public Window {
	MainApp		*m_pApp ;			/* アプリケーションへのポインタ */

public:
	TaskArea( MainApp *app ) ;
	~TaskArea() ;

	BOOL	WMCreate( HWND hDlg ) ;
	LRESULT	WMCommand( HWND hDlg, UINT msg, WPARAM wp, LPARAM lp ) ;
	void	WMSize( DWORD fwSize, WORD nWidth, WORD nHeight ) ;
	void	WMNotify( HWND hWnd, int idCtrl, LPNMHDR pnmh ) ;
	void	WMSetFocus() ;

	BOOL	GetListHwnd( HWND *phWnd ) const ;
	void	EnumTask() ;
	void	SwitchTask() ;
	void	KillTask() ;

	static	BOOL CALLBACK	EnumTaskSub( HWND hWnd, LPARAM lParam ) ;
} ;

class MainApp ;

/*-------------------------------------------------------------------------*
 * MainApp
 *-------------------------------------------------------------------------*/
MainApp::MainApp()
{
	m_pMainWnd = 0 ;
	m_pFileArea = 0 ;
	m_pTaskArea = 0 ;
	/* フォントを取得する */
	m_hFont = CreateListboxFont() ;
}

MainApp::~MainApp()
{
	DeleteObject( m_hFont ) ;
}

BOOL
MainApp::Create( HINSTANCE hInstance )
{
	m_hInst = hInstance ;

	if ( !ListBoxRegisterClass( m_hInst ) ) {
		return FALSE ;
	}
	if ( !MainWindow::RegisterClass( m_hInst ) ) {
		return FALSE ;
	}

#ifdef	_WIN32_WCE
	m_hAccl = LoadAccelerators( m_hInst,
								MAKEINTRESOURCE(IDR_ACCELERATOR1) ) ;
#else	/* _WIN32_WCE */
	m_hAccl = LoadAccelerators( GetModuleHandle(NULL),
								MAKEINTRESOURCE(IDR_ACCELERATOR1) ) ;
#endif	/* _WIN32_WCE */

	GetReg() ;

	m_pMainWnd = new MainWindow( this ) ;
	m_pFileArea = new FileArea( this ) ;
	m_pTaskArea = new TaskArea( this ) ;
	if ( !m_pMainWnd || !m_pFileArea || !m_pTaskArea ) {
		return FALSE ;
	}
	if ( !m_pMainWnd->Create() ) {
		delete m_pMainWnd ;
		return FALSE ;
	}

	return TRUE ;
}

int
MainApp::Run()
{
	MSG		msg ;

	while ( GetMessage( &msg, NULL, 0, 0 ) ) {
		if ( !TranslateAccelerator( m_pMainWnd->get_hwnd(), m_hAccl, &msg ) ) {
			TranslateMessage( &msg ) ;
		}
		DispatchMessage( &msg ) ;
	}
	return msg.wParam ;
}

BOOL
MainApp::GetReg()
{
	return TRUE ;
}

void
MainApp::SetReg() const
{
}

void
MainApp::DeleteReg() const
{
	TCHAR	sValue[ 256 ] ;

	wsprintf( sValue, TEXT("%s\\%s"), GawaroBaseKey, szTitleName ) ;
	RegDeleteKey( HKEY_CURRENT_USER, sValue ) ;
}

/*-------------------------------------------------------------------------*
 * MainWindow
 *-------------------------------------------------------------------------*/
MainWindow::MainWindow( MainApp *pApp )
{
	m_pApp = pApp ;
	m_hIcon = 0 ;
	m_fUninstall = FALSE ;
	m_hWndCurrent = 0 ;
}

BOOL
MainWindow::WMCreate( HWND hWnd )
{
	RECT		rect ;
	TC_ITEM		item ;
	HWND		dlg1, dlg2 ;
	HINSTANCE	hInst = m_pApp->get_inst() ;

	m_hWnd = hWnd ;

	/* ウインドウタイトルを設定する */
	wsprintf( MessageBuf, TEXT("%s V%d.%02d"),
			  szTitleName, AppVersion / 100, AppVersion % 100 ) ;
	SetWindowText( hWnd, MessageBuf ) ;

	/* アイコンを作成しタスクバーに登録する */
	m_hIcon = (HICON) LoadImage( hInst, MAKEINTRESOURCE(IDI_APPICON),
								 IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ) ;
	if ( m_hIcon ) {
		SendMessage( hWnd, WM_SETICON, FALSE, (LPARAM) m_hIcon ) ;
	}

	/* タスクバーに登録する */
	AddTaskBarIcon() ;

	/* 表示領域を求める */
	GetClientRect( m_hWnd, &rect ) ;

	m_hWndTab = CreateWindow( WC_TABCONTROL,  L"",
					WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS,
					0, 0, rect.right, rect.bottom - rect.top - 2,
					m_hWnd, (HMENU) IDC_TAB,
					hInst, NULL ) ;

	memset( &item, 0, sizeof item ) ;
	item.cchTextMax= 32 ;
	item.mask = (UINT) TCIF_TEXT | TCIF_PARAM ;
	item.pszText = TEXT("Files") ;
	dlg1 = CreateDialogParam( hInst,
					MAKEINTRESOURCE(IDD_DLG_BASE),
					m_hWndTab,
					DlgProc,
					(LPARAM) m_pApp->get_file() ) ;
	item.lParam = (LPARAM) dlg1 ;
	TabCtrl_InsertItem( m_hWndTab, 0, (TC_ITEM FAR*)&item ) ;

	item.cchTextMax= 32 ;
	item.mask = (UINT) TCIF_TEXT | TCIF_PARAM ;
	item.pszText = TEXT("Tasks") ;
	dlg2 = CreateDialogParam( hInst,
					MAKEINTRESOURCE(IDD_DLG_BASE),
					m_hWndTab,
					DlgProc,
					(LPARAM) m_pApp->get_task() ) ;
	item.lParam = (LPARAM) dlg2 ;
	TabCtrl_InsertItem( m_hWndTab, 1, (TC_ITEM FAR*)&item ) ;

	TabCtrl_AdjustRect( m_hWndTab, FALSE, &rect ) ;
	MoveWindow( dlg1, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE ) ;
	ShowWindow( dlg1, SW_SHOW ) ;
	MoveWindow( dlg2, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE ) ;
	ShowWindow( dlg2, SW_HIDE ) ;
	m_hWndCurrent = dlg1 ;

	SetFocus( dlg1 ) ;
	return FALSE ;
}

/*
 * タスクバーに通知アイコンを登録する
 */
BOOL
MainWindow::AddTaskBarIcon() const
{
	NOTIFYICONDATA	tnid ;
	HICON			hIcon ;

	/* 通知エリア用のアイコンを作成する */
	hIcon = (HICON) LoadImage( m_pApp->get_inst(), MAKEINTRESOURCE(IDI_APPICON),
							   IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ) ;
	memset( &tnid, 0, sizeof tnid ) ;
	tnid.cbSize = sizeof (NOTIFYICONDATA) ;
	tnid.hWnd = m_hWnd ;
	tnid.uID = IDM_NOTIFY ;
	tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP ;
	tnid.uCallbackMessage = WM_COMMAND ;
	tnid.hIcon = hIcon ;
	_tcscpy( tnid.szTip, szTitleName ) ;
	return Shell_NotifyIcon( NIM_ADD, &tnid ) ;
}

/*
 * 通知アイコンを削除する
 */
BOOL
MainWindow::DeleteTaskBarIcon() const
{
	NOTIFYICONDATA	tnid ;

	memset( &tnid, 0, sizeof tnid ) ;
	tnid.cbSize = sizeof (NOTIFYICONDATA) ;
	tnid.hWnd = m_hWnd ;
	tnid.uID = IDM_NOTIFY ;
	return Shell_NotifyIcon( NIM_DELETE, &tnid ) ;
}

void
MainWindow::WMDestroy()
{
	DeleteTaskBarIcon() ;
	if ( m_hIcon ) {
		::DeleteObject( m_hIcon ) ;
		m_hIcon = 0 ;
	}
	PostQuitMessage( 0 ) ;
}

LRESULT
MainWindow::WMCommand( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
	DWORD	index ;
	WORD	notifyCode = HIWORD(wParam), cmd = LOWORD(wParam) ;

	switch ( cmd ) {
	case IDM_EXIT:
		SendMessage( hWnd, WM_CLOSE, 0, 0 ) ;
		break ;
	case IDM_ENTER:
		if ( GetFocus() == m_hWndTab ) {
			SetFocus( m_hWndCurrent ) ;
		} else if ( m_hWndCurrent ) {
			SendMessage( m_hWndCurrent, WM_COMMAND, IDM_ENTER, 0 ) ;
		}
		break ;
	case IDM_ESCAPE:
		index = TabCtrl_GetCurFocus( m_hWndTab ) + 1 ;
		index %= TabCtrl_GetItemCount( m_hWndTab ) ;
		TabCtrl_SetCurFocus( m_hWndTab, index ) ;
		break ;
	case IDM_NOTIFY:
		SetForegroundWindow( m_hWnd ) ;
		break ;
	}
	return 0 ;
}

void
MainWindow::WMNotify( HWND hWnd, int idCtrl, LPNMHDR pnmh )
{
	int		iTab ;
	TC_ITEM	tcItem ;
	HWND	hwndTabCtrl ;

	switch ( pnmh->code ) {
	case TCN_SELCHANGING:
		memset( &tcItem, 0, sizeof tcItem ) ;
		hwndTabCtrl = GetDlgItem( hWnd, IDC_TAB ) ;
		iTab = TabCtrl_GetCurSel( hwndTabCtrl ) ;
		tcItem.mask = TCIF_PARAM ;
		TabCtrl_GetItem( hwndTabCtrl, iTab, &tcItem ) ;
		ShowWindow( (HWND) tcItem.lParam, SW_HIDE ) ;
		break;
	case TCN_SELCHANGE:
		hwndTabCtrl = GetDlgItem( hWnd, IDC_TAB ) ;
		iTab = TabCtrl_GetCurSel( hwndTabCtrl ) ;
		tcItem.mask = TCIF_PARAM;
		TabCtrl_GetItem( hwndTabCtrl, iTab, &tcItem ) ;
		ShowWindow( (HWND) tcItem.lParam, SW_SHOW ) ;
		m_hWndCurrent = (HWND) tcItem.lParam ;
		SendMessage( m_hWndCurrent, WM_COMMAND, IDM_REFRESH, 0 ) ;
		break ;
	}
}

void
MainWindow::WMSetFocus()
{
	if ( m_hWndCurrent ) {
		SetFocus( m_hWndCurrent ) ;
	}
}

BOOL
MainWindow::WMClose()
{
	if ( m_fUninstall ) {
		m_pApp->DeleteReg() ;
	} else {
		m_pApp->SetReg() ;
	}
	return FALSE ;
}

BOOL
MainWindow::Create()
{
	HWND	hWnd = CreateWindowEx( 0,
						GetClassName(),
						szTitleName,
						WS_VISIBLE|WS_BORDER|WS_CAPTION|WS_SYSMENU,
						0, 0, 240, 200,
						NULL,
						NULL,
						m_pApp->get_inst(),
						this ) ;
	if ( hWnd == 0 ) {
		return FALSE ;
	}
	ShowWindow( hWnd, SW_SHOW ) ;
    UpdateWindow( hWnd ) ;
    return TRUE ;
}

BOOL
MainWindow::RegisterClass( HINSTANCE hInst )
{
	WNDCLASS	wc ;

	wc.style         = NULL ;
	wc.lpfnWndProc   = (WNDPROC) WndProc ;
	wc.cbClsExtra    = 0 ;
	wc.cbWndExtra    = 4 ;
	wc.hInstance     = hInst ;
	wc.hIcon         = NULL ;
	wc.hCursor       = NULL ;
	wc.hbrBackground = (HBRUSH) GetStockObject( WHITE_BRUSH ) ;
#ifdef	_WIN32_WCE
	wc.lpszMenuName  = 0 ;
#else	/* _WIN32_WCE */
	wc.lpszMenuName  = 0 ;
#endif	/* _WIN32_WCE */
	wc.lpszClassName = 	GetClassName() ;
	return ::RegisterClass( &wc ) ;
}

/*-------------------------------------------------------------------------*
 * FileArea ダイアログ
 *-------------------------------------------------------------------------*/
LPCTSTR	FileArea::c_sDir = TEXT("   <DIR>") ;
LPCTSTR	FileArea::c_sPatDir = TEXT(" %s\t%s") ;
LPCTSTR	FileArea::c_sPatFile = TEXT("%s\t%8d") ;
LPCTSTR	FileArea::c_sFiles = TEXT(" (Directory)") ;

FileArea::FileArea( MainApp *pApp )
{
	m_pApp = pApp ;
	/* ワイルドカードを作成する */
	_tcscpy( m_sWildCard, TEXT("*.*") ) ;
	_tcscpy( m_sFile, TEXT("") ) ;
	_tcscpy( m_sDir,  TEXT("\\") ) ;
	m_fRecent = TRUE ;
}

FileArea::~FileArea()
{
}

BOOL
FileArea::WMCreate( HWND hDlg )
{
	DWORD	w ;
	HWND	hWnd ;
	RECT	rect ;
	int		tabs[ 1 ] ;

	m_hWnd = hDlg ;
	GetClientRect( hDlg, &rect ) ;
	/* ディレクトリ表示領域を作成する */
	hWnd = CreateWindow( TEXT("STATIC"),  L"",
					WS_CHILD|WS_VISIBLE,
					2, 0, rect.right - 6, 20,
					hDlg, (HMENU) IDC_CAP_DIR,
					m_pApp->get_inst(), NULL ) ;
	rect.top += 20 ;
	/* フォントを設定する */
	SendMessage( hWnd, WM_SETFONT, (WPARAM) m_pApp->get_font(), (LPARAM) TRUE ) ;
	/* ディレクトリリストを作成する */
	hWnd = CreateWindow( CTRL_LISTBOX,  L"",
					WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP,
					0, 20, rect.right - 6, rect.bottom - rect.top - 8,
					hDlg, (HMENU) IDC_LST_FILE,
					m_pApp->get_inst(), NULL ) ;
	/* フォントを設定する */
	SendMessage( hWnd, WM_SETFONT, (WPARAM) m_pApp->get_font(), (LPARAM) TRUE ) ;
	/* TABの位置を設定する */
	w = rect.right - 6 * 10 ;
	tabs[0] = w / ((LOWORD(GetDialogBaseUnits()) + 3) / 4) ;
	SendMessage( hWnd, LB_SETTABSTOPS, 1, (LPARAM) tabs ) ;

	/* リストボックスを初期化する */
	InitList( hDlg ) ;
	return TRUE ;
}

LRESULT
FileArea::WMCommand( HWND hDlg, UINT msg, WPARAM wp, LPARAM lp )
{
	BOOL	fDone ;
	HWND	hCtrl ;
	BOOL	fEnter = FALSE ;

	hCtrl = GetDlgItem( hDlg, IDC_LST_FILE ) ;
	switch ( GET_WM_COMMAND_ID( wp, lp ) ) {
	case IDC_LST_FILE:
		switch ( GET_WM_COMMAND_CMD( wp, lp ) ) {
		case LBN_DBLCLK:
			fEnter = TRUE ;
			break ;
		}
		break ;
	case IDM_ENTER:
		fEnter = TRUE ;
		break ;
	case IDM_REFRESH:
		::SetFocus( GetDlgItem( m_hWnd, IDC_LST_FILE ) ) ;
		break ;
	}
	if ( fEnter ) {
		if ( m_fRecent ) {
			if ( SelectRecent( hDlg ) ) {
				if ( !_tcscmp( m_sFile, c_sFiles ) ) {
					/* ディレクトリ内容を初期表示する */
					InitListDir( hDlg ) ;
				} else {
					Execute( hDlg ) ;
				}
				return TRUE ;
			}
		} else {
			if ( ChangeDir( hDlg, &fDone ) ) {
				if ( fDone ) {
					Execute( hDlg ) ;
				}
				return TRUE ;
			}
		}
	}
	return 0 ;
}

void
FileArea::WMSize( DWORD fwSize, WORD nWidth, WORD nHeight )
{
	RECT	rect ;
	HWND	hWndCtrl ;

	hWndCtrl = GetDlgItem( m_hWnd, IDC_CAP_DIR ) ;
	GetClientRect( hWndCtrl, &rect ) ;
	SetWindowPos( hWndCtrl, 0,
				  0, 0, nWidth - 2, rect.bottom,
				  SWP_NOZORDER ) ;
	rect.bottom += 2 ;
	hWndCtrl = GetDlgItem( m_hWnd, IDC_LST_FILE ) ;
	SetWindowPos( hWndCtrl, 0,
				  0, rect.bottom + 2, nWidth - 2, nHeight - rect.bottom - 4,
				  SWP_NOMOVE|SWP_NOZORDER ) ;
}

void
FileArea::WMNotify( HWND hWnd, int idCtrl, LPNMHDR pnmh )
{
	MessageBeep( MB_OK ) ;
}

void
FileArea::WMSetFocus()
{
	::SetFocus( GetDlgItem( m_hWnd, IDC_LST_FILE ) ) ;
}

BOOL
FileArea::EnumDir( HWND hWnd, LPDWORD pCount, LPDWORD pMem )
{
	WIN32_FIND_DATA	find ;
	HANDLE			hFind ;
	TCHAR			findPath[ MAX_PATH ] ;
	BOOL			fAdd = !pCount && !pMem ;
	DWORD			count = 0, num_mem = 0, attr ;

	attr = GetFileAttributes( m_sDir ) ;
	if ( attr == 0xFFFFFFFF || !(attr & FILE_ATTRIBUTE_DIRECTORY) ) {
		return FALSE ;
	}
	if ( m_sDir && _tcscmp( m_sDir, TEXT("\\") ) ) {
		/* 親ディレクトリへのエントリを作成する */
		wsprintf( findPath, c_sPatDir, TEXT(".."), c_sDir ) ;
		if ( fAdd ) {
			SendMessage( hWnd, LB_ADDSTRING, 0, (LPARAM) findPath ) ;
		} else {
			count ++ ;
			num_mem += _tcslen( findPath ) ;
		}
	}
	/* ディレクトリ検索用のワイルドカードを作成する */
	_tcscpy( findPath, m_sDir ) ;
	catdir( findPath, TEXT("*.*"), NULL ) ;
	/* ディレクトリを検索する */
	hFind = FindFirstFile( findPath, &find ) ;
	if ( hFind != INVALID_HANDLE_VALUE ) {
		do {
			if ( !_tcscmp( find.cFileName, TEXT(".") ) ) {
				continue ;
			} else if ( !_tcscmp( find.cFileName, TEXT("..") ) ) {
				continue ;
			} else if ( !(find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
				continue ;
			}
			wsprintf( findPath, c_sPatDir, find.cFileName, c_sDir ) ;
			if ( fAdd ) {
				/* リストボックスに項目を追加する */
				SendMessage( hWnd, LB_ADDSTRING, 0, (LPARAM) findPath ) ;
			} else {
				count ++ ;
				num_mem += _tcslen( findPath ) + 1 ;
			}
		} while ( FindNextFile( hFind, &find ) ) ;
		FindClose( hFind ) ;
	}
	/* ファイル検索用のワイルドカードを作成する */
	_tcscpy( findPath, m_sDir ) ;
	catdir( findPath, m_sWildCard, NULL ) ;
	/* ファイルを検索する */
	hFind = FindFirstFile( findPath, &find ) ;
	if ( hFind != INVALID_HANDLE_VALUE ) {
		do {
			if ( find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
				continue ;
			}
			wsprintf( findPath, c_sPatFile, find.cFileName, find.nFileSizeLow ) ;
			if ( fAdd ) {
				/* リストボックスに項目を追加する */
				SendMessage( hWnd, LB_ADDSTRING, 0, (LPARAM) findPath ) ;
			} else {
				count ++ ;
				num_mem += _tcslen( findPath ) + 1 ;
			}
		} while ( FindNextFile( hFind, &find ) ) ;
		FindClose( hFind ) ;
	}
	if ( pCount ) {
		*pCount = count ;
	}
	if ( pMem ) {
		*pMem = num_mem ;
	}
	return TRUE ;
}

BOOL
FileArea::ListDir( HWND hWnd, LPCTSTR pPrevDir )
{
	DWORD	index = 0 ;
	TCHAR	buf[ MAX_PATH ] ;

	/* リストボックスをクリアする */
	SendMessage( hWnd, LB_RESETCONTENT, 0, 0 ) ;
	/* ディレクトリ内容を列挙する */
	if ( !EnumDir( hWnd, NULL, NULL ) ) {
		return FALSE ;
	}
	if ( pPrevDir ) {
		wsprintf( buf, c_sPatDir, pPrevDir, c_sDir ) ;
		index = SendMessage( hWnd, LB_FINDSTRINGEXACT, (WPARAM) -1, (LPARAM) buf ) ;
		if ( index == LB_ERR ) {
			index = 0 ;
		}
	}
	SendMessage( hWnd, LB_SETCURSEL, (WPARAM) index, 0 ) ;
	return TRUE ;
}

/*
 * ディレクトリ内容の初期表示を行う
 */
void
FileArea::InitListDir( HWND hDlg )
{
	HWND	hWnd = GetDlgItem( hDlg, IDC_LST_FILE ) ;

	/* 最新のファイル表示モードを抜ける */
	m_fRecent = FALSE ;
	/* 初期ディレクトリのリストを作成する */
	if ( !ListDir( hWnd, NULL ) ) {
		_tcscpy( m_sDir, TEXT("\\") ) ;
		ListDir( hWnd, NULL ) ;
	}
	/* カレントディレクトリを表示する */
	SetDlgItemText( hDlg, IDC_CAP_DIR, m_sDir ) ;
}

BOOL
FileArea::ChangeDir( HWND hDlg, LPBOOL pDone )
{
	LPTSTR	ptr ;
	int		index ;
	TCHAR	buf[ MAX_PATH ], sPrevDir[ MAX_PATH ] ;
	HWND	hWnd = GetDlgItem( hDlg, IDC_LST_FILE ) ;

	index = SendMessage( hWnd, LB_GETCURSEL, 0, 0 ) ;
	if ( index == LB_ERR ) {
		return FALSE ;
	}
	SendMessage( hWnd, LB_GETTEXT, (WPARAM) index, (LPARAM) buf ) ;
	ptr = _tcschr( buf, TEXT('\t') ) ;
	if ( ptr ) {
		*ptr++ = 0 ;
		if ( !_tcsicmp( ptr, c_sDir ) ) {
			catdir( m_sDir, &buf[1], sPrevDir ) ;
			if ( !ListDir( hWnd, sPrevDir ) ) {
				_tcscpy( m_sDir, TEXT("\\") ) ;
				ListDir( hWnd, NULL ) ;
			}
			SetDlgItemText( hDlg, IDC_CAP_DIR, m_sDir ) ;
			*pDone = FALSE ;
		} else {
			_tcscpy( m_sFile, m_sDir ) ;
			catdir( m_sFile, buf, NULL ) ;
			*pDone = TRUE ;
		}
	}
	return TRUE ;
}

BOOL
FileArea::EnumRecent( HWND hWnd )
{
	HKEY	hKey ;
	LONG	lret ;
	LPTSTR	pBuffer ;
	TCHAR	buf[ MAX_PATH ], data[ MAX_PATH ] ;
	DWORD	index, cchName, dwType, cbData, i ;

	pBuffer = (LPTSTR) LocalAlloc( LPTR, sizeof (TCHAR) * MAX_PATH * MAX_RECENT ) ;
	if ( !pBuffer ) {
		return FALSE ;
	}
	/* レジストリから最近使ったファイルの一覧を得る */
	wsprintf( buf, TEXT("%s\\%s\\Recent"), GawaroBaseKey, szTitleName ) ;
	lret = RegOpenKeyEx( HKEY_CURRENT_USER, buf, 0,
#ifdef	_WIN32_WCE
						0,
#else	/* _WIN32_WCE */
						KEY_ALL_ACCESS,
#endif	/* _WIN32_WCE */
						&hKey ) ;
	if ( lret != ERROR_SUCCESS ) {
		LocalFree( (HLOCAL) pBuffer ) ;
		return FALSE ;
	}
	index = 0 ;
	while ( 1 ) {
		cchName = sizeof buf / sizeof (TCHAR) ;
		cbData  = sizeof data ;
		lret = RegEnumValue( hKey, index ++,
							 buf, &cchName,
							 NULL, &dwType,
							 (LPBYTE) data, &cbData ) ;
		if ( lret != ERROR_SUCCESS ) {
			break ;
		} else if ( dwType != REG_SZ ) {
			continue ;
		}
		i = _ttol( buf ) ;
		if ( i >= 0 && i < MAX_RECENT ) {
			_tcscpy( &pBuffer[ i * MAX_PATH ], data ) ;
		}
	}
	RegCloseKey( hKey ) ;
	/* 最近使ったファイルの一覧をリストボックスに加える */
	SendMessage( hWnd, LB_RESETCONTENT, 0, 0 ) ;
	SendMessage( hWnd, LB_ADDSTRING, 0, (LPARAM) c_sFiles ) ;
	index = 0 ;
	for ( i = 0 ; i < MAX_RECENT ; i ++ ) {
		LPCTSTR	ptr = &pBuffer[ i * MAX_PATH ] ;
		if ( *ptr ) {
			index ++ ;
			SendMessage( hWnd, LB_INSERTSTRING, (WPARAM) -1, (LPARAM) ptr ) ;
		}
	}

	LocalFree( (HLOCAL) pBuffer ) ;
	return index ? TRUE : FALSE ;
}

BOOL
FileArea::SelectRecent( HWND hDlg )
{
	int		index ;
	HWND	hWnd = GetDlgItem( hDlg, IDC_LST_FILE ) ;

	index = SendMessage( hWnd, LB_GETCURSEL, 0, 0 ) ;
	if ( index == LB_ERR ) {
		return FALSE ;
	}
	SendMessage( hWnd, LB_GETTEXT, (WPARAM) index, (LPARAM) m_sFile ) ;
	return TRUE ;
}

BOOL
FileArea::InitListRecent( HWND hDlg )
{
	m_fRecent = TRUE ;
	/* 最新のファイル一覧を得る */
	if ( EnumRecent( GetDlgItem( hDlg, IDC_LST_FILE ) ) ) {
		/* カレントディレクトリを表示する */
		SetDlgItemText( hDlg, IDC_CAP_DIR, TEXT("Recent Files...") ) ;
		return TRUE ;
	}
	return FALSE ;
}

void
FileArea::InitList( HWND hDlg )
{
	/* 最新のファイル一覧を得る */
	if ( !InitListRecent( hDlg ) ) {
		/* ディレクトリ内容を初期表示する */
		InitListDir( hDlg ) ;
	}
	/* ディレクトリリストの選択を解除する */
	SendDlgItemMessage( hDlg, IDC_LST_FILE, LB_SETCURSEL, (WPARAM) 0, 0 ) ;
}

void
FileArea::Execute( HWND hDlg )
{
#ifdef	_WIN32_WCE
	SHELLEXECUTEINFO		sei ;

	memset( &sei, 0, sizeof sei ) ;
	sei.cbSize = sizeof sei ;
	sei.fMask = 0 ;
	sei.hwnd = NULL ;
	sei.lpVerb = TEXT("Open") ;
	sei.lpFile = m_sFile ;
	sei.lpParameters = NULL ;
	sei.lpDirectory = NULL ;
	sei.nShow = SW_SHOW ;
	ShellExecuteEx( &sei ) ;
#endif	/* _WIN32_WCE */
	AddRecent( szTitleName, m_sFile ) ;
	/* リストボックスを初期化する */
	InitList( hDlg ) ;
}

/*-------------------------------------------------------------------------*
 * TaskArea ダイアログ
 *-------------------------------------------------------------------------*/
TaskArea::TaskArea( MainApp *pApp )
{
	m_pApp = pApp ;
}

TaskArea::~TaskArea()
{
}

BOOL
TaskArea::WMCreate( HWND hDlg )
{
	HWND	hWnd ;
	RECT	rect ;

	m_hWnd = hDlg ;
	GetClientRect( hDlg, &rect ) ;
	/* Switchボタンを作成する */
	hWnd = CreateWindow( TEXT("BUTTON"), TEXT("Switch"),
					WS_CHILD|WS_VISIBLE|
					BS_DEFPUSHBUTTON,
					0, 2, 70, 16,
					hDlg, (HMENU) IDC_BTN_SWITCH,
					m_pApp->get_inst(), NULL ) ;
	/* フォントを設定する */
	SendMessage( hWnd, WM_SETFONT, (WPARAM) m_pApp->get_font(), (LPARAM) TRUE ) ;
	/* Refreshボタンを作成する */
	hWnd = CreateWindow( TEXT("BUTTON"), TEXT("Refresh"),
					WS_CHILD|WS_VISIBLE,
					80, 2, 70, 16,
					hDlg, (HMENU) IDC_BTN_REFRESH,
					m_pApp->get_inst(), NULL ) ;
	/* フォントを設定する */
	SendMessage( hWnd, WM_SETFONT, (WPARAM) m_pApp->get_font(), (LPARAM) TRUE ) ;
	/* Killボタンを作成する */
	hWnd = CreateWindow( TEXT("BUTTON"), TEXT("Kill"),
					WS_CHILD|WS_VISIBLE,
					160, 2, 70, 16,
					hDlg, (HMENU) IDC_BTN_KILL,
					m_pApp->get_inst(), NULL ) ;
	/* フォントを設定する */
	SendMessage( hWnd, WM_SETFONT, (WPARAM) m_pApp->get_font(), (LPARAM) TRUE ) ;
	/* ディレクトリリストの高さを調整する */
	rect.top += 22 ;
	/* ディレクトリリストを作成する */
	hWnd = CreateWindow( CTRL_LISTBOX,  L"",
					WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP,
					0, rect.top, rect.right - 2, rect.bottom - rect.top - 4,
					hDlg, (HMENU) IDC_LST_FILE,
					m_pApp->get_inst(), NULL ) ;

	/* フォントを設定する */
	SendMessage( hWnd, WM_SETFONT, (WPARAM) m_pApp->get_font(), (LPARAM) TRUE ) ;
	/* タスク一覧を作成する */
	EnumTask() ;
	return TRUE ;
}

LRESULT
TaskArea::WMCommand( HWND hDlg, UINT msg, WPARAM wp, LPARAM lp )
{
	BOOL	fEnter = FALSE ;

	switch ( GET_WM_COMMAND_ID( wp, lp ) ) {
	case IDC_LST_FILE:
		switch ( GET_WM_COMMAND_CMD( wp, lp ) ) {
		case LBN_DBLCLK:
			fEnter = TRUE ;
			break ;
		}
		break ;
	case IDM_ENTER:
		fEnter = TRUE ;
		break ;
	case IDC_BTN_SWITCH:
		fEnter = TRUE ;
		break ;
	case IDM_REFRESH:
	case IDC_BTN_REFRESH:
		/* タスク一覧を作成する */
		EnumTask() ;
		::SetFocus( GetDlgItem( m_hWnd, IDC_LST_FILE ) ) ;
		return TRUE ;
	case IDC_BTN_KILL:
		KillTask() ;
		::SetFocus( GetDlgItem( m_hWnd, IDC_LST_FILE ) ) ;
		return TRUE ;
	}
	if ( fEnter ) {
		SwitchTask() ;
		::SetFocus( GetDlgItem( m_hWnd, IDC_LST_FILE ) ) ;
		return TRUE ;
	}
	return 0 ;
}

void
TaskArea::WMSize( DWORD fwSize, WORD nWidth, WORD nHeight )
{
	RECT	rect ;
	HWND	hWndCtrl ;

	hWndCtrl = GetDlgItem( m_hWnd, IDC_BTN_SWITCH ) ;
	GetClientRect( hWndCtrl, &rect ) ;
	rect.bottom += 2 ;
	hWndCtrl = GetDlgItem( m_hWnd, IDC_LST_FILE ) ;
	SetWindowPos( hWndCtrl, 0,
				  0, rect.bottom + 2, nWidth - 2, nHeight - rect.bottom - 4,
				  SWP_NOMOVE|SWP_NOZORDER ) ;
}

void
TaskArea::WMNotify( HWND hWnd, int idCtrl, LPNMHDR pnmh )
{
	MessageBeep( MB_OK ) ;
}

void
TaskArea::WMSetFocus()
{
	::SetFocus( GetDlgItem( m_hWnd, IDC_LST_FILE ) ) ;
}

BOOL
TaskArea::GetListHwnd( HWND *phWnd ) const
{
	DWORD	index ;
	HWND	hWndCtrl = GetDlgItem( m_hWnd, IDC_LST_FILE ), hWnd ;

	index = SendMessage( hWndCtrl, LB_GETCURSEL, 0, 0 ) ;
	if ( index == LB_ERR ) {
		return FALSE ;
	}
	hWnd = (HWND) SendMessage( hWndCtrl, LB_GETITEMDATA, index, 0 ) ;
	if ( hWnd == (HWND) LB_ERR ) {
		return FALSE ;
	}
	*phWnd = hWnd ;
	return TRUE ;
}

void
TaskArea::EnumTask()
{
	HWND	hWndCtrl = GetDlgItem( m_hWnd, IDC_LST_FILE ) ;

	/* リストボックスをクリアする */
	SendMessage( hWndCtrl, LB_RESETCONTENT, 0, 0 ) ;
	/* ウィンドウリストをリストボックスに加える */
	EnumWindows( EnumTaskSub, (LPARAM) hWndCtrl ) ;
	/* 先頭の項目にカーソルを設定する */
	SendMessage( hWndCtrl, LB_SETCURSEL, (WPARAM) 0, 0 ) ;
}

BOOL CALLBACK
TaskArea::EnumTaskSub( HWND hWnd, LPARAM lParam )
{
	DWORD	index ;
	TCHAR	buf[ 128 ] ;
	HWND	hWndCtrl = (HWND) lParam ;

	if ( !GetClassName( hWnd, buf, sizeof buf / sizeof buf[0] ) || !*buf ) {
		return TRUE ;
	}
	GetWindowText( hWnd, buf, sizeof buf / sizeof buf[0] ) ;
	if ( *buf ) {
		index = SendMessage( hWndCtrl, LB_ADDSTRING, 0, (LPARAM) buf ) ;
		if ( index != LB_ERR ) {
			SendMessage( hWndCtrl, LB_SETITEMDATA, (WPARAM) index, (LPARAM) hWnd ) ;
		}
	}
	return TRUE ;
}

void
TaskArea::SwitchTask()
{
	HWND	hWnd ;

	if ( !GetListHwnd( &hWnd ) ) {
		return ;
	}
	SetForegroundWindow( hWnd ) ;
}

void
TaskArea::KillTask()
{
	HWND	hWnd ;

	if ( !GetListHwnd( &hWnd ) ) {
		return ;
	}
	if ( IsWindow( hWnd ) ) {
		SendMessage( hWnd, WM_CLOSE, 0, 0 ) ;
	}
	EnumTask() ;
}

void
SplitDirAndFile( LPCTSTR path, LPTSTR dir, LPTSTR fn )
{
	LPTSTR	ptr ;

	if ( dir ) {
		_tcscpy( dir, path ) ;
		ptr = _tcsrchr( dir, TEXT('\\') ) ;
		if ( ptr ) {
			*ptr = 0 ;
			if ( fn ) {
				_tcscpy( fn, ptr + 1 ) ;
			}
		} else {
			*dir = 0 ;
			if ( fn ) {
				_tcscpy( fn, path ) ;
			}
		}
	} else {
		ptr = _tcsrchr( path, TEXT('\\') ) ;
		_tcscpy( fn, ptr ? ptr + 1 : path ) ;
	}
}

/*
 * リストボックス用の固定ピッチフォントを作成する
 */
HFONT
CreateListboxFont()
{
	LOGFONT         lf ;

	/* フォントを取得する */
	memset( &lf, 0, sizeof lf ) ;
	lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN ;
	lf.lfCharSet = 128 ;
	lf.lfWidth = 6 ;
	lf.lfHeight = 12 ;
	return CreateFontIndirect( &lf ) ;
}

void
slash2backslash( LPTSTR str )
{
	LPTSTR	ptr ;

	/* '/'を'\'に変換する */
	while ( ptr = _tcschr( str, TEXT('/') ) ) {
		*ptr = TEXT('\\') ;
	}
}

void
catdir( LPTSTR body, LPCTSTR adddir, LPTSTR pPrevDir )
{
	DWORD	len ;
	LPTSTR	ptr ;

	slash2backslash( body ) ;
	if ( pPrevDir ) {
		_tcscpy( pPrevDir, TEXT("..") ) ;
	}
	while ( *adddir ) {
		if ( _tcschr( TEXT("/\\"), *adddir ) ) {
			/* 先頭が"/"か"\"の場合は読み飛ばす */
			adddir ++ ;
			continue ;
		}
		if ( adddir[0] == TEXT('.') && adddir[1] == TEXT('.') ) {
			ptr = _tcsrchr( body, TEXT('\\') ) ;
			if ( ptr && pPrevDir ) {
				_tcscpy( pPrevDir, ptr + 1 ) ;
			}
			if ( ptr && ptr != body ) {
				*ptr = 0 ;
			} else {
				_tcscpy( body, TEXT("\\") ) ;
			}
			adddir += 2 ;
		} else if ( adddir[0] == TEXT('.') ) {
			adddir ++ ;
		} else {
			break ;
		}
	}
	if ( !*adddir ) {
		return ;
	}
	len = _tcslen( body ) ;
	if ( !len || body[ len - 1 ] != TEXT('\\') ) {
		body[ len ++ ] = TEXT('\\') ;
	}
	_tcscpy( &body[ len ], adddir ) ;
	slash2backslash( body ) ;
}

void
AddRecent( LPCTSTR pAppName, LPCTSTR pPath )
{
	HKEY	hKey ;
	LONG	lret ;
	LPBYTE	lpData ;
	LPTSTR	pBuffer, name ;
	BOOL	fWrite = TRUE ;
	TCHAR	buf[ MAX_PATH ], data[ MAX_PATH ] ;
	DWORD	index, cchName, dwType, cbData, i, ret ;

	pBuffer = (LPTSTR) LocalAlloc( LPTR, sizeof (TCHAR) * MAX_PATH * MAX_RECENT ) ;
	if ( !pBuffer ) {
		return ;
	}
	/* レジストリから最近使ったファイルの一覧を得る */
	wsprintf( buf, TEXT("%s\\%s\\Recent"), GawaroBaseKey, pAppName ) ;
	lret = RegCreateKeyEx( HKEY_CURRENT_USER, buf, 0, TEXT(""), 0,
#ifdef	_WIN32_WCE
						   0,
#else	/* _WIN32_WCE */
						   KEY_ALL_ACCESS,
#endif	/* _WIN32_WCE */
						   NULL, &hKey, &ret ) ;
	if ( lret != ERROR_SUCCESS ) {
		LocalFree( (HLOCAL) pBuffer ) ;
		return ;
	}
	index = 0 ;
	while ( 1 ) {
		cchName = sizeof buf / sizeof (TCHAR) ;
		cbData  = sizeof data ;
		lret = RegEnumValue( hKey, index ++,
							 buf, &cchName,
							 NULL, &dwType,
							 (LPBYTE) data, &cbData ) ;
		if ( lret != ERROR_SUCCESS ) {
			break ;
		} else if ( dwType != REG_SZ ) {
			continue ;
		}
		i = _ttol( buf ) ;
		if ( i >= 0 && i < MAX_RECENT ) {
			if ( _tcsicmp( data, pPath ) ) {
				_tcscpy( &pBuffer[ i * MAX_PATH ], data ) ;
			} else if ( i == 0 ) {
				fWrite = FALSE ;
			}
		}
	}
	if ( fWrite ) {
		/* 最近使ったファイルの一覧をレジストリに書き込む */
		index = 0 ;
		/* 指定されたファイルを書き込む */
		wsprintf( buf, TEXT("%d"), index ++ ) ;
		name = buf ;
		dwType = REG_SZ ;
		lpData = (LPBYTE) pPath ;
		cbData = (_tcslen(pPath) + 1) * sizeof (*pPath) ;
		RegSetValueEx( hKey, name, 0, dwType, lpData, cbData ) ;
		/* 残りのファイルを書き込む */
		for ( i = 0 ; i < MAX_RECENT ; i ++ ) {
			LPCTSTR	ptr = &pBuffer[ i * MAX_PATH ] ;

			if ( !*ptr ) {
				continue ;
			}
			wsprintf( buf, TEXT("%d"), index ++ ) ;
			name = buf ;
			dwType = REG_SZ ;
			lpData = (LPBYTE) ptr ;
			cbData = (_tcslen(ptr) + 1) * sizeof (*ptr) ;
			RegSetValueEx( hKey, name, 0, dwType, lpData, cbData ) ;
		}
	}
	RegCloseKey( hKey ) ;
	LocalFree( (HLOCAL) pBuffer ) ;
}
