/** pahooWebView2.cpp
 * WebView2コンポーネントを扱う関数
 *
 * @copyright	(c)studio pahoo
 * @author		パパぱふぅ
 * @動作環境	MinGW C++ + WebView2
 * @参考URL		http://www.pahoo.org/e-soul/webtech/cpp01-12-01.shtm
 */
#define CINTERFACE
#include <iostream>
#include <tchar.h>
#include <locale>
#include <string>
#include "WebView2.h"
#include "event.h"
#include "pahooWebView2.hpp"
#ifndef UNICODE
#include <codecvt>
#endif

using namespace std;

//親ウィンドウ：メインプログラムで定義する．
extern HWND hParent;

//テンポラリファイル名：メインプログラムで定義する．
extern wchar_t *wUri;

//WebView2関連
ICoreWebView2* webView2 = nullptr;
static ICoreWebView2Controller* controller = nullptr;
static bool webView2Ready = false;

/**
 * WebView2が準備できているかどうか．
 * @param	なし
 * @return	bool true：準備できている／false：できていない
*/
bool isWeb2Ready(void) {
	if (webView2Ready) {
		return true;
	} else {
		return false;
	}
}

/**
 * LPCTSTR→wstring変換
 * @param	LPCTSTR str		変換元の文字列
 * @return	wstring			変換後の文字列
*/
std::wstring TStrToWStr(LPCTSTR str) {
#ifdef UNICODE
    return std::wstring(str);
#else
	// ANSI/MultiByte から UTF-16（wstring）への変換
	int size_needed = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0);
	if (size_needed == 0) {
		return L"";			// 変換失敗時は空文字列を返す
	}
	std::wstring result(size_needed, 0);
	MultiByteToWideChar(CP_UTF8, 0, str, -1, &result[0], size_needed);
	result.pop_back(); // null terminator を削除
	return result;
#endif
}

/**
 * エラーメッセージを表示してプログラムを終了する．
 * @param	LPCTSTR errmsg	エラー・メッセージ
 * @return	なし
 */
void FatalError(LPCTSTR errmsg, ...) {
	MessageBox(NULL, errmsg, TEXT("エラー"), MB_OK | MB_ICONSTOP);
	ExitProcess(1);
}

/**
 * データ・パスを取得する．
 * @param	LPTSTR szOut	データ・パスを格納する領域
 * @param	DWORD nSize		データ・サイズ
 * @return	なし
*/
void GetDataPath(LPTSTR szOut, DWORD nSize) {
	TCHAR szExePath[MAX_PATH];
	GetModuleFileName(nullptr, szExePath, _countof(szExePath));

	LPTSTR szExeName = _tcsrchr(szExePath, TEXT('\\'));
	szExeName = szExeName ? szExeName + 1 : szExePath;

	TCHAR szAppData[MAX_PATH];
	GetEnvironmentVariable(TEXT("AppData"), szAppData, _countof(szAppData));

	_tcsncpy(szOut, szAppData, nSize);
	_tcsncat(szOut, TEXT("\\"), nSize);
	_tcsncat(szOut, szExeName, nSize);
}

/**
 * WebView2をリサイズする．
 * @param	HWND hWnd	ウィンドウ・ハンドラ
 * @return	なし
*/
void ResizeBrowser(HWND hWnd) {
	if (!controller) {
		return;
	}
	RECT bounds;
	GetClientRect(hWnd, &bounds);
	controller->lpVtbl->put_Bounds(controller, bounds);
}

/**
 * イベントハンドラ：WebView2
 * @param	HWND hDlg		親ウィンドウ・ハンドラ
 * @paramm	UINT uMsg		メッセージ識別子
 * @param	WPARAM wParam	メッセージの最初のパラメータ
 * @paramL	PARAM lParam	メッセージの2番目のパラメータ
 * @return	LRESULT WINAPI	メッセージ処理結果
*/
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
	switch (msg) {
	case WM_CLOSE:
		EndDialog(hParent, 0);
		return 0;
		break;
	case WM_DESTROY:
        PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, msg, wParam, lParam);
	}
	return 0;
}

/**
 * WebView2を生成する．
 * @param	HINSTANCE hInst		現在のインターフェイス
 * @param	HWND hDlg			親ウィンドウ・ハンドラ
 * @paramm	int x, y			WebView2の左上座標
 * @paramm	int width, height	WebView2の幅、高さ
 * @param	LPCWSTR uri			表示するURI
 * @return	HWND				WebView2へのハンドラ
*/
HWND createWebView2(HINSTANCE hInst, HWND hDlg, int x, int y, int width, int height, LPCWSTR uri) {
	//ウィンドウ クラス情報
	static WNDCLASSEX wc{};
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.hInstance = hInst;
	wc.lpszClassName = TEXT("webview");
	wc.lpfnWndProc = WndProc;
	RegisterClassEx(&wc);

	//ウィンドウ生成
	static HWND hWnd = CreateWindowEx(
		0,
		TEXT("webview"),
		TEXT("MinGW WebView2"),
		WS_CHILD | WS_VISIBLE | ES_LEFT,
		x, y, width, height,
		hDlg,
		nullptr,
		hInst,
		nullptr
	);
	ShowWindow(hWnd, SW_SHOW);
	UpdateWindow(hWnd);
	SetFocus(hWnd);

	//データ・パス取得
	TCHAR szDataPath[MAX_PATH + 1];
	GetDataPath(szDataPath, MAX_PATH);
	//イベントハンドラ
	static EventHandler handler{};

	handler.EnvironmentCompleted = [&](HRESULT result, ICoreWebView2Environment* created_environment) {
//		cout << "EnvironmentCompleted" << endl;
		if (FAILED(result)) {
			FatalError(TEXT("Failed to create environment?"));
		}
		created_environment->lpVtbl->CreateCoreWebView2Controller(created_environment, hWnd, &handler);
		return S_OK;
	};

	handler.ControllerCompleted = [&](HRESULT result, ICoreWebView2Controller* new_controller) {
//		cout << "ControllerCompleted" << endl;
		if (FAILED(result)) {
			FatalError(TEXT("Failed to create controller?"));
		}
		controller = new_controller;
		controller->lpVtbl->AddRef(controller);
		controller->lpVtbl->get_CoreWebView2(controller, &webView2);
		webView2->lpVtbl->AddRef(webView2);
		webView2->lpVtbl->Navigate(webView2, uri);
		ResizeBrowser(hWnd);
		webView2Ready = true;
		return S_OK;
	};

	HRESULT result = CreateCoreWebView2EnvironmentWithOptions(
		nullptr,
		TStrToWStr(szDataPath).c_str(),
		nullptr,
		&handler
	);

	if (FAILED(result)) {
		FatalError(TEXT("Call to CreateCoreWebView2EnvironmentWithOptions failed!"));
	}

	return hWnd;
}

/*
 ** バージョンアップ履歴 =====================================================
 *
 * @version 1.1.0 2025/06/07  TStrToWStr() -- C++17 対応
 * @version 1.0.0 2024/04/27  初版
 */
