
/// 
/// インクルード
/// 
#include <Windows.h>
#include <string>
#include <CommCtrl.h>

///  
/// ライブラリのリンク
/// 
#pragma comment(lib, "comctl32.lib")

///
/// 定数
/// 
const std::wstring WINDOW_CAPTION_NAME{ L"Sample Skeleton" };
const std::wstring WINDOW_CLASS_NAME{ L"WINDOW PROGRAM" };

const int s_Window_Width{ 1280 };
const int s_Window_Height{ 720 };

const DWORD dwStyle { WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME };
const DWORD dwExStyle{ WS_EX_OVERLAPPEDWINDOW };

const UINT_PTR uIdSubclassMainWindowId{ 10000 };

/// 
/// プロトタイプ宣言
/// 
LRESULT CALLBACK MainWindowSubclassProc(HWND, UINT, WPARAM, LPARAM, UINT_PTR, DWORD_PTR);


/// 
/// グローバル変数
/// 
HINSTANCE g_hInstance = nullptr;	// インスタンスハンドル
HWND      g_hMainWindow = nullptr;	// ウィンドウハンドル
BOOL      g_fActive = FALSE;		// アクティブフラグ

///
/// WinMain()
/// memo: Windows Programming において最初に呼ばれる関数
/// 
int WINAPI 
WinMain(
	HINSTANCE		hInst,				// 実行時のインスタンスハンドル
	HINSTANCE		hPrevInst,			// Windows 95以降は常にNULL
	LPSTR			lpszCmdLine,		// 実行時のコマンドライン
	int				nCmdShow)			// 実行時のウィンドウの状態
{
	// インスタンスハンドルのコピー
	g_hInstance = hInst;

	// ウィンドウクラスの設定
	WNDCLASSEX wcex = {
        sizeof(WNDCLASSEX),
        CS_VREDRAW | CS_HREDRAW,
        DefWindowProc, 
        0, 0,
        static_cast<HINSTANCE>(GetModuleHandle(nullptr)),
        LoadIcon(nullptr, IDI_APPLICATION),
        LoadCursor(nullptr, IDC_ARROW),
        static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)),
        nullptr, 
        WINDOW_CLASS_NAME.c_str(),
        nullptr,
	};

    // ウィンドウクラスの登録
    if (!RegisterClassEx(&wcex)) {
        LPCTSTR lpMessage{ TEXT("ウィンドウクラスの登録に失敗") };
        LPCTSTR lpTitle{ TEXT("RegisterClassEx()") };
        UINT type = MB_OK;
        MessageBox(nullptr, lpMessage, lpTitle, type);
        return 0;
    }

    HWND hwnd;
    RECT window_rect, client_rect;
    
    RECT window_size = { 0, 0, s_Window_Width, s_Window_Height };
    const auto& target_width = window_size.right - window_size.left;
    const auto& target_height = window_size.bottom - window_size.top;

    // ウィンドウの作成
    hwnd = CreateWindowEx(dwExStyle, WINDOW_CLASS_NAME.c_str(),
        WINDOW_CAPTION_NAME.c_str(),
        dwStyle, CW_USEDEFAULT, CW_USEDEFAULT,
        target_width, target_height, nullptr, nullptr, g_hInstance, nullptr);
    if (hwnd == nullptr) {
        LPCTSTR lpMessage{ TEXT("ウィンドウの作成に失敗") };
        LPCTSTR lpTitle{ TEXT("CreateWindowEx()") };
        UINT type = MB_OK;
        MessageBox(nullptr, lpMessage, lpTitle, type);
        return 0;
    }

    if (!GetWindowRect(hwnd, &window_rect)) {
        LPCTSTR lpMessage{ TEXT("ウィンドウ全体のサイズの取得に失敗") };
        LPCTSTR lpTitle{ TEXT("GetWindowRect()") };
        UINT type = MB_OK;
        MessageBox(nullptr, lpMessage, lpTitle, type);
        return 0;
    }

    if (!GetClientRect(hwnd, &client_rect)) {
        LPCTSTR lpMessage{ TEXT("ウィンドウのクライアント領域のサイズの取得に失敗") };
        LPCTSTR lpTitle{ TEXT("GetClientRect()") };
        UINT type = MB_OK;
        MessageBox(nullptr, lpMessage, lpTitle, type);
        return 0;
    }

    // フレームサイズの算出
    const int frame_size_x = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
    const int frame_size_y = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);

    // リサイズ用のウィンドウサイズの算出
    const int resize_width = frame_size_x + target_width;
    const int resize_height = frame_size_y + target_height;

    SetWindowPos(hwnd, nullptr, CW_USEDEFAULT, CW_USEDEFAULT, resize_width, resize_height, SWP_NOMOVE);

    // ウィンドウハンドルのコピー
    g_hMainWindow = hwnd;

    // ウィンドウハンドルとプロシージャーの関連付け
    SetWindowSubclass(g_hMainWindow, MainWindowSubclassProc, uIdSubclassMainWindowId, 0);

    // ウィンドウの表示と描画の更新
    ShowWindow(g_hMainWindow, nCmdShow);
    UpdateWindow(g_hMainWindow);
    

    // メッセージループ
    MSG msg = {};
    while (1) {
        if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
            if (msg.message == WM_QUIT) {
                break;
            }
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        } else {
            // ウィンドウがアクティブな時だけ処理をする
            if (g_fActive) {
                // 
            } else {
                WaitMessage();
            }
        }

    }
    
    // ウィンドウクラスの登録解除およびウィンドウハンドルとプロシージャーの関連付けを解除
    UnregisterClass(WINDOW_CLASS_NAME.c_str(), g_hInstance);
    RemoveWindowSubclass(g_hMainWindow, MainWindowSubclassProc, uIdSubclassMainWindowId);

    return static_cast<int>(msg.wParam);

}

///
/// MainWindowSubclassProc()
/// memo: 発行されたウィンドウメッセージの処理を行う
/// 
LRESULT CALLBACK MainWindowSubclassProc(
            HWND            hWnd,           // メッセージが発行されたウィンドウハンドル
            UINT            msg,            // 発行されたメッセージ
            WPARAM          wParam,         // 発行されたメッセージの情報その1
            LPARAM          lParam,         // 発行されたメッセージの情報その2
            UINT_PTR        uIdSubclass,    // サブクラスID
            DWORD_PTR       dwRefData)      // サブクラスの参照データ
{
    switch (msg) {
    case WM_ACTIVATEAPP:
        g_fActive = static_cast<BOOL>(wParam);
        return 0;
    case WM_KEYDOWN:
        switch (LOWORD(wParam)) {
        case VK_ESCAPE:
            DestroyWindow(hWnd);
            return 0;
        }
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefSubclassProc(hWnd, msg, wParam, lParam);

}
