/******************************************************************************
Ootake

 [TurboConfig.cpp]
	連射ボタンの設定をするためのフォーム

Copyright(C)2006-2021 Kitao Nakamura.
	改造版・後継版を公開なさるときは必ずソースコードを添付してください。
	その際に事後でかまいませんので、ひとことお知らせいただけると幸いです。
	商的な利用は禁じます。
	あとは「GNU General Public License(一般公衆利用許諾契約書)」に準じます。

******************************************************************************/
#define _CRT_SECURE_NO_DEPRECATE

#define DIRECTINPUT_VERSION	0x0500	//Kitao追加。環境にもよるかもしれないが、DirectInput5が軽い。7だとやや遅延あり。スペースハリアーがわかりやすい。

#include <string.h>
#include "TurboConfig.h"
#include "App.h"
#include "PadConfig.h"
#include "resource.h"
#include "JoyPad.h"
#include "KeyConfig.h"
#include "Printf.h" //テスト用


#define LINE_LEN	39
#define N_LINES		12

enum OptionComponent
{
	BUTTON_2BPAD = 1,
	EDIT_2BPAD,
	BUTTON_3BPAD,
	EDIT_3BPAD,
	BUTTON_HELP,
	BUTTON_CLOSE,
};

static HWND			_hWndC[BUTTON_CLOSE]; //各コンポーネントのハンドル

static HBRUSH		_hMyBrush; //自作ブラシ色
static HFONT		_hFontB; //ボタン用フォント
static HBRUSH		_hEditBrush; //EDITの枠の色

static Uint32		_FontWidth;
static Uint32		_FontHeight;
static const char*	_pCaption = "\"Ootake\" Turbo Button Setting";
static HINSTANCE	_hInstance = NULL;
static HWND 		_hWnd = NULL;
static HWND 		_hParentWnd = NULL;

static Sint32		_PadID;
static Sint32		_SetOk = -1; //戻り値。設定完了なら1。キャンセルなら-1。未設定中は0。
static Sint32*		_pSetOk;


//フォントの高さを取得
static Uint32
get_font_height(
	HWND			hWnd)
{
	HDC 			hDC;
	HFONT			hFont;
	HFONT			hFontOld;
	TEXTMETRIC		tm;

	hDC 	 = GetDC(hWnd);
	hFont	 = (HFONT)GetStockObject(OEM_FIXED_FONT);	 /* 固定ピッチフォント */
	hFontOld = (HFONT)SelectObject(hDC, hFont);

	GetTextMetrics(hDC, &tm);

	SelectObject(hDC, hFontOld);
	DeleteObject(hFont);
	ReleaseDC(hWnd, hDC);

	return (Uint32)(tm.tmHeight);
}

//フォントの横幅を取得
static Uint32
get_font_width(
	HWND			hWnd)
{
	HDC 			hDC;
	HFONT			hFont;
	HFONT			hFontOld;
	TEXTMETRIC		tm;

	hDC 	 = GetDC(hWnd);
	hFont	 = (HFONT)GetStockObject(OEM_FIXED_FONT);	 /* 固定ピッチフォント */
	hFontOld = (HFONT)SelectObject(hDC, hFont);

	GetTextMetrics(hDC, &tm);

	SelectObject(hDC, hFontOld);
	DeleteObject(hFont);
	ReleaseDC(hWnd, hDC);

	return (Uint32)tm.tmAveCharWidth;
}

//Windowサイズを設定
static void
set_window_size(
	HWND			hWnd)
{
	RECT		rc;
	Uint32		wndW = _FontWidth  * LINE_LEN;
	Uint32		wndH = _FontHeight * N_LINES +1;

	SetRect(&rc, 0, 0, wndW, wndH);
	AdjustWindowRectEx(&rc, GetWindowLong(hWnd, GWL_STYLE),
						GetMenu(hWnd) != NULL, GetWindowLong(hWnd, GWL_EXSTYLE));
	wndW = rc.right - rc.left;
	wndH = rc.bottom - rc.top;
	GetWindowRect(_hParentWnd, &rc);
	MoveWindow(hWnd, rc.right-wndW, rc.top, wndW, wndH, TRUE);
}

//ボタン設定の状態を表示
static void
update_status()
{
	PCEPAD	pcePad;
	char	buf[128];
	char	buf2[3+1]; //v2.96修正
	
	//２ボタンパッドの連射ボタン設定状態
	APP_GetPcePad2(_PadID, &pcePad);
	strcpy(buf, " I..[");
	KEYCONFIG_ToChrPcePad(buf2, pcePad.button5);
	strcat(buf, buf2);
	strcat(buf, "]  II..[");
	KEYCONFIG_ToChrPcePad(buf2, pcePad.button6);
	strcat(buf, buf2);
	strcat(buf, "]");
	SendDlgItemMessage(_hWnd, EDIT_2BPAD, EM_SETSEL, 0, -1);	
	SendDlgItemMessage(_hWnd, EDIT_2BPAD, EM_REPLACESEL, FALSE, (LPARAM)buf);	

	//３ボタンパッドのボタン設定状態
	APP_GetPcePad3(_PadID, &pcePad);
	strcpy(buf, " I..[");
	KEYCONFIG_ToChrPcePad(buf2, pcePad.button5);
	strcat(buf, buf2);
	strcat(buf, "]  II..[");
	KEYCONFIG_ToChrPcePad(buf2, pcePad.button6);
	strcat(buf, buf2);
	strcat(buf, "]");
	SendDlgItemMessage(_hWnd, EDIT_3BPAD, EM_SETSEL, 0, -1);	
	SendDlgItemMessage(_hWnd, EDIT_3BPAD, EM_REPLACESEL, FALSE, (LPARAM)buf);	
}

//Window表示を更新
static void
update_window(
	HWND			hWnd)
{
	HDC 			hDC;
	HFONT			hFont;
	HFONT			hFontOld;
	PAINTSTRUCT 	ps;
	Uint32			x;
	Uint32			y;

	/* 描画準備 */
	hDC = BeginPaint(hWnd, &ps);
	SetBkMode(hDC, OPAQUE);	//文字の背景を塗りつぶす
	SetBkColor(hDC, RGB(64,128,64));
	SetTextColor(hDC, RGB(240,240,240));
	hFont = (HFONT)GetStockObject(OEM_FIXED_FONT);
	hFontOld = (HFONT)SelectObject(hDC, hFont);

	x = _FontWidth*2;
	y = _FontHeight +3;
	if (JOYPAD_GetConnectSixButton())
		TextOut(hDC, x, y, "[ playing 6-Button Pad Game now! ]", 34);
	else if (JOYPAD_GetConnectThreeButton())
		TextOut(hDC, x, y, "[ playing 3-Button Pad Game now! ]", 34);
	else if (APP_GetInit()) //ゲームをすでに起動している場合(つまり起動時のSettingボタンからの呼び出しじゃない場合)
		TextOut(hDC, x, y, "[ playing 2-Button Pad Game now! ]", 34);
	else	
		TextOut(hDC, x, y, "[ Most games use 2-Button Pad. ]", 32);
	x = _FontWidth*3 +2;
	y += _FontHeight*2 -3;
	TextOut(hDC, x, y, "Turbo for 2-Button Pad Games", 28);
	y += _FontHeight*3;
	TextOut(hDC, x, y, "Turbo for 3-Button Pad Games", 28);

	/* 終了処理 */
	EndPaint(hWnd, &ps);
	SelectObject(hDC, hFontOld);
	DeleteObject(hFont);
	ReleaseDC(hWnd, hDC);
}


static LRESULT CALLBACK
turboconfig_wnd_proc(
	HWND		hWnd,
	UINT		uMsg,
	WPARAM		wParam,
	LPARAM		lParam)
{
	MSG			msg;
	PCEPAD		pcePad; //ボタン設定用バッファ
	Sint32		setOk;

	switch (uMsg)
	{
	case WM_CREATE:
		EnableWindow(_hParentWnd, FALSE);//親ウィンドウを無効化してモーダルに。
		_hFontB = CreateFont(  0,						// 高さ。0 = デフォルト
		                       0,						// 幅。0なら高さに合った幅
    		                   0,						// 角度
        		               0,						// ベースラインとの角度
            		           FW_NORMAL,				// 太さ
                		       FALSE,					// イタリック
	                    	   FALSE,					// アンダーライン
		                       FALSE,					// 打ち消し線
    		                   0,						// 日本語を取り扱うときはSHIFTJIS_CHARSETにする。
        		               0,						// 出力精度
            		           0,						// クリッピング精度
                		       0,						// 出力品質
                    		   0,						// ピッチとファミリー
		                       ""						// 書体名
							); //英語のデフォルトフォントに設定
		_FontWidth	= get_font_width(hWnd);
		_FontHeight = get_font_height(hWnd);
		set_window_size(hWnd);
		_hEditBrush = CreateSolidBrush(RGB(0,0,0)); //EDITの枠の色
		break;

	case WM_PAINT:
		update_window(hWnd);
		break;

	case WM_CTLCOLORSTATIC:
		{	//読み取り専用のEDITはWM_CTLCOLORSTATICで扱われるのでここで色指定する。
			SetBkMode((HDC)wParam, OPAQUE);	//文字の背景を塗りつぶす
			SetTextColor(((HDC)wParam), RGB(255,255,255)); //EDITの文字色
			SetBkColor(((HDC)wParam), RGB(0,0,0)); //EDITの背景色
		}
		return (LRESULT)_hEditBrush; //枠表示に使う色を返す

	case WM_KEYDOWN:
		if (wParam == VK_ESCAPE)
		{
			TURBOCONFIG_Deinit();
			return 0;
		}
		break;

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
			case BUTTON_2BPAD:
				//２ボタンパッドの連射ボタン設定
				setOk = 0;
				ZeroMemory(&pcePad, sizeof(pcePad));
				APP_GetPcePad2(_PadID, &pcePad);
				PADCONFIG_Init(_hWnd, _hInstance, 1, _PadID, 2, &pcePad, &setOk); //PadConfigダイアログを表示
				while (setOk == 0) //ダイアログが結果を返すまでループ
				{ 
					GetMessage(&msg ,NULL, 0, 0);
					TranslateMessage(&msg);
					DispatchMessage(&msg);
				}
				if (setOk == 1) //設定が成功した場合
				{
					APP_SetPcePad2(_PadID, pcePad);
					update_status(); //ボタン設定の状況表示を更新
					_SetOk = 1; //全体のフラグ(１つでも設定更新したらフラグを立てる)も立てる
				}
				break;
		
			case BUTTON_3BPAD:
				//３ボタンパッドの連射ボタン設定
				setOk = 0;
				ZeroMemory(&pcePad, sizeof(pcePad));
				APP_GetPcePad3(_PadID, &pcePad);
				PADCONFIG_Init(_hWnd, _hInstance, 1, _PadID, 3, &pcePad, &setOk); //PadConfigダイアログを表示
				while (setOk == 0) //ダイアログが結果を返すまでループ
				{ 
					GetMessage(&msg ,NULL, 0, 0);
					TranslateMessage(&msg);
					DispatchMessage(&msg);
				}
				if (setOk == 1) //設定が成功した場合
				{
					APP_SetPcePad3(_PadID, pcePad);
					update_status(); //ボタン設定の状況表示を更新
					_SetOk = 1; //全体のフラグ(１つでも設定更新したらフラグを立てる)も立てる
				}
				break;
		
			case BUTTON_HELP:
				//連射ボタン設定時に注意する点などを表示
				MessageBox(hWnd,
					"You can set a special button for Auto-Fire. And, if you set the    \n"
					"normal Auto-Fire (check \"TurboButton I\" and \"TurboButton II\"    \n"
					"in the \"Input\" menu), you can use this Auto-Fire button as a    \n"
					"\"Non-Auto-Fire button\".    \n"
					"\n"
					"In Japanese language\n"
					"連射専用のボタンを設定できます。この連射専用ボタンを設定した   \n"
					"場合、同時に通常の連射設定（\"Input\"メニューの\"TurboButton I\",   \n"
					"\"TurboButton II\"にチェックを入れる）をした際には、逆に   \n"
					"\"非連射ボタン\"として使うことができます。   ",
					"About \"Turbo Button\" Setting", MB_OK);
				break;
		
			case BUTTON_CLOSE:
				TURBOCONFIG_Deinit();
				return 0;
		}
		break;

	case WM_CLOSE:
		TURBOCONFIG_Deinit();
		return 0;
	}

	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}


static BOOL
turboconfig_main()
{
	WNDCLASS	wc;
	HWND		hWnd;
	RECT		rc;
	Uint32		x;
	Uint32		y;
	HWND		hWndTmp;
	
	ZeroMemory(&wc, sizeof(wc));
	wc.style		 = 0;
	wc.lpfnWndProc	 = turboconfig_wnd_proc;
	wc.cbClsExtra	 = 0;
	wc.cbWndExtra	 = 0;
	wc.hInstance	 = _hInstance;
	wc.hIcon		 = LoadIcon(_hInstance, MAKEINTRESOURCE(IDI_ICON)); //アイコンを読み込み
	wc.hCursor		 = LoadCursor(NULL, IDC_ARROW);
	_hMyBrush = CreateSolidBrush(RGB(64,128,64)); //ブラシを作る
	wc.hbrBackground = _hMyBrush;
	wc.lpszMenuName  = "";
	wc.lpszClassName = _pCaption;

	if (RegisterClass(&wc) == 0)
		return FALSE;

	hWnd = CreateWindow(
		_pCaption,
		_pCaption,
		WS_SYSMENU | WS_CAPTION,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		0,
		0,
		_hParentWnd,
		NULL,
		_hInstance,
		NULL
	);

	if (hWnd == NULL)
		return FALSE;

	_hWnd = hWnd;

	//２ボタンパッド設定のボタンを作成
	x = _FontWidth*3 +2;
	y = _FontHeight*4 +2;
	hWndTmp = CreateWindow(
		"BUTTON", "Set ",
		WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
		x, y, _FontWidth*6-1, _FontHeight+6,
		_hWnd, (HMENU)BUTTON_2BPAD, _hInstance, NULL
	);
	SendMessage(hWndTmp, WM_SETFONT, (WPARAM)_hFontB, MAKELPARAM(TRUE, 0));

	//２ボタンパッド設定状況の表示エディット(Read Only)作成
	x += _FontWidth*6;
	hWndTmp = CreateWindow(
		"EDIT", " I..[ N ]  II..[Spc]",
		WS_CHILD | WS_VISIBLE | ES_LEFT | ES_READONLY,
		x, y, _FontWidth*28-1, _FontHeight+5,
		_hWnd, (HMENU)EDIT_2BPAD, _hInstance, NULL
	);
	SendMessage(hWndTmp, WM_SETFONT, (WPARAM)_hFontB, MAKELPARAM(TRUE, 0));

	//３ボタンパッド設定のボタンを作成
	x = _FontWidth*3 +2;
	y += _FontHeight*3;
	hWndTmp = CreateWindow(
		"BUTTON", "Set ",
		WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
		x, y, _FontWidth*6-1, _FontHeight+6,
		_hWnd, (HMENU)BUTTON_3BPAD, _hInstance, NULL
	);
	SendMessage(hWndTmp, WM_SETFONT, (WPARAM)_hFontB, MAKELPARAM(TRUE, 0));

	//３ボタンパッド設定状況の表示エディット(Read Only)作成
	x += _FontWidth*6;
	hWndTmp = CreateWindow(
		"EDIT", " I..[ N ]  II..[Spc]",
		WS_CHILD | WS_VISIBLE | ES_LEFT | ES_READONLY,
		x, y, _FontWidth*28-1, _FontHeight+5,
		_hWnd, (HMENU)EDIT_3BPAD, _hInstance, NULL
	);
	SendMessage(hWndTmp, WM_SETFONT, (WPARAM)_hFontB, MAKELPARAM(TRUE, 0));

	//Helpボタンを作成
	x = _FontWidth*16 +6;
	y += _FontHeight*2 +7;
	hWndTmp = CreateWindow(
		"BUTTON", "Help",
		WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
		x, y, _FontWidth*10, _FontHeight*2-3,
		_hWnd, (HMENU)BUTTON_HELP, _hInstance, NULL
	);
	SendMessage(hWndTmp, WM_SETFONT, (WPARAM)_hFontB, MAKELPARAM(TRUE, 0));

	//Closeボタンを作成
	x += _FontWidth*11 -3;
	hWndTmp = CreateWindow(
		"BUTTON", "Close",
		WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
		x, y, _FontWidth*10, _FontHeight*2-3,
		_hWnd, (HMENU)BUTTON_CLOSE, _hInstance, NULL
	);
	SendMessage(hWndTmp, WM_SETFONT, (WPARAM)_hFontB, MAKELPARAM(TRUE, 0));

	//ボタン設定の状況を表示
	update_status();

	ShowWindow(_hWnd, SW_SHOWNORMAL);
	UpdateWindow(_hWnd);
	GetWindowRect(_hWnd, &rc);
	SetWindowPos(_hWnd, HWND_TOP, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_FRAMECHANGED);
	ImmAssociateContext(_hWnd, 0); //IMEを無効にする

	return TRUE;
}


BOOL
TURBOCONFIG_Init(
	HWND		hWnd,
	HINSTANCE	hInstance,
	Sint32	 	padID,
	Sint32*		setOk)
{
	if (_hInstance != NULL)
		TURBOCONFIG_Deinit();

	_hParentWnd = hWnd; //親ウィンドウのハンドル
	_hInstance = hInstance;

	_PadID	= padID;
	_pSetOk	= setOk;
	_SetOk	= -1; //キャンセル

	return turboconfig_main();
}


void
TURBOCONFIG_Deinit()
{
	if (_hInstance != NULL)
	{
		DestroyWindow(_hWnd);
		_hWnd = NULL;
		UnregisterClass(_pCaption, _hInstance);
		_hInstance = NULL;
		
		DeleteObject(_hFontB); //ボタン用フォントを開放
		DeleteObject(_hMyBrush); //ブラシを開放
		DeleteObject(_hEditBrush); //ブラシを開放
		
		//メインウィンドウにフォーカスを戻し前面に。
		EnableWindow(_hParentWnd, TRUE);
		SetForegroundWindow(_hParentWnd);
		
		*_pSetOk = _SetOk; //戻り値を設定。この瞬間にKeyConfigウィンドウは動き出す。
	}
}

