#include "stdafx.h"
#include "FWatchApp.hpp"
#include "resource.h"

#include "ServiceEntry.hpp"
#include "FWatchUI.hpp"
#include "FWatchVersionDlg.hpp"
#include "FWatchSettingDlg.hpp"

#include <assert.h>

#define MAX_LOADSTRING 100

/*!
 * タスクバーの再生成通知のウィンドウメッセージ定義
 */
const UINT FWatchUI::WM_TASKBARCREATED = ::RegisterWindowMessage(_T("TaskbarCreated"));


FWatchUI::FWatchUI()
	: pTskIcon_(NULL)
	, hWnd_(NULL)
	, lockmenu_(false)
{
}

FWatchUI::~FWatchUI()
{
	delete pTskIcon_;
}

bool FWatchUI::create()
{
	//required:
	assert(hWnd_ == NULL && "メインウィンドウは作成済みです。");

	//do:
	TCHAR szTitle[MAX_LOADSTRING] = {0};
	TCHAR szWindowClass[MAX_LOADSTRING] = {0};

	app.LoadString(IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	app.LoadString(IDC_FWATCH, szWindowClass, MAX_LOADSTRING);

	RegisterClass(szWindowClass);
	return ::CreateWindow(
		szWindowClass,
		szTitle,
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		0,
		CW_USEDEFAULT,
		0,
		NULL,
		NULL,
		app.getInstanceHandle(),
		this
		) != NULL;
}

/*!
 * ウィンドウを表示します。
 */
void FWatchUI::showEditDialog()
{
	//required:
	assert(hWnd_ != NULL && "メインウィンドウが作成されていません。");

	//do:
	PostMessage(hWnd_, WM_COMMAND, IDM_SETTING, 0);
}


ATOM FWatchUI::RegisterClass(LPCTSTR szWindowClass)
{
	WNDCLASSEX wcex;
	wcex.cbSize = sizeof(WNDCLASSEX); 
	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= (WNDPROC) WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= app.getInstanceHandle();
	wcex.hIcon			= LoadIcon(app.getInstanceHandle(), (LPCTSTR) IDI_FWATCH);
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH) (COLOR_WINDOW + 1);
	wcex.lpszMenuName	= NULL; // (LPCSTR)IDC_FWATCH;
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(app.getInstanceHandle(), (LPCTSTR) IDI_SMALL);

	return RegisterClassEx(&wcex);
}

void FWatchUI::onClose()
{
	if (app.getCL().isModified()) {
		if (app.showMessageBox(
				MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
				NULL,
				IDS_CLOSECONFIRM_NOSAVE) != IDYES) {
			return;
		}
	}
	::DestroyWindow(hWnd_);
}

void FWatchUI::onDestroy()
{
	delete pTskIcon_;
	pTskIcon_ = NULL;
}

void FWatchUI::onTaskbarCreate()
{
	pTskIcon_->ReCreate();
}

void FWatchUI::onCreate(LPCREATESTRUCT)
{
	pTskIcon_ = new CTaskIcon(
		hWnd_,
		1,
		WM_USER_NOTIFYTASKICON,
		IDI_FWATCH,
		IDS_TASKMES_WATCH
		);
	pTskIcon_->Create();
}

void FWatchUI::onCommand(UINT wmId)
{
	if (wmId == IDM_HELP) {
		app.showHelp(hWnd_);
	}
	else if ( !lockmenu_) {
		lockmenu_ = true;
		switch (wmId) 
		{
		case IDM_SETTING:
			{
				FWatchSettingDlg dlg;
				dlg.show(hWnd_);
			}
			break;

		case IDM_ABOUT:
			{
				FWatchVersionDlg dlg;
				dlg.show(hWnd_);
			}
			break;

		case IDM_EXIT:
			::SendMessage(hWnd_, WM_CLOSE, 0, 0);
			break;

		case IDM_SERVICE_START:
			ServiceReStart();
			break;

		case IDM_SERVICE_STOP:
			ServiceStop();
			break;
		}
		lockmenu_ = false;
	}
}

void FWatchUI::onTaskIconNotify(WPARAM , LPARAM lParam)
{
	UINT uMouseMsg = (UINT) lParam; 
	if (uMouseMsg == WM_LBUTTONDOWN) {
		::SetForegroundWindow(hWnd_);
	}
	else if (uMouseMsg == WM_LBUTTONDBLCLK) {
		::SendMessage(hWnd_, WM_COMMAND, IDM_SETTING, 0);
	}
	else if (uMouseMsg == WM_RBUTTONUP || uMouseMsg == WM_CONTEXTMENU) {
		::SetForegroundWindow(hWnd_);

		HMENU hMenu = ::LoadMenu(app.getInstanceHandle(), MAKEINTRESOURCE(IDC_FWATCH));
		POINT pt;
		GetCursorPos(&pt);
		BOOL returnCode = FALSE;
		if (!lockmenu_) {
			lockmenu_ = true;
			BOOL bRunning = FALSE;
			if (IsRegistService(bRunning)) {
				// サービスがインストールされていればサービスの状態の表示とコントロールを可能にする
				HMENU hSubMenu = GetSubMenu(hMenu, 1);
				MENUITEMINFO minfo = {0};
				minfo.cbSize = sizeof(MENUITEMINFO);
				minfo.fMask  = MIIM_STATE;
				minfo.fState =  bRunning ? MFS_GRAYED : MFS_ENABLED;
				SetMenuItemInfo(hMenu, IDM_SERVICE_START, false, &minfo);
				minfo.fState = !bRunning ? MFS_GRAYED : MFS_ENABLED;
				SetMenuItemInfo(hMenu, IDM_SERVICE_STOP, false, &minfo);
				returnCode = TrackPopupMenu(
					hSubMenu,
					TPM_LEFTALIGN | TPM_BOTTOMALIGN | TPM_RIGHTBUTTON,
					pt.x,
					pt.y,
					0,
					hWnd_,
					NULL);
			}
			else {
				// サービスがインストールされていない場合
				HMENU hSubMenu = GetSubMenu(hMenu, 0);
				returnCode = TrackPopupMenu(
					hSubMenu,
					TPM_LEFTALIGN | TPM_BOTTOMALIGN | TPM_RIGHTBUTTON,
					pt.x,
					pt.y,
					0,
					hWnd_,
					NULL);
			}
			lockmenu_ = false;
		}
		else{
			HMENU hSubMenu = GetSubMenu(hMenu, 2);
			returnCode = TrackPopupMenu(
				hSubMenu,
				TPM_LEFTALIGN | TPM_BOTTOMALIGN | TPM_RIGHTBUTTON,
				pt.x,
				pt.y,
				0,
				hWnd_,
				NULL);
		}
		PostMessage(hWnd_, WM_NULL, 0, 0); // PRB: Menus for Notification Icons Do Not Work Correctly
	}
}

LRESULT CALLBACK FWatchUI::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	FWatchUI* me = (FWatchUI*) ::GetWindowLongPtr(hWnd, GWLP_USERDATA);
	assert((me == NULL || me->hWnd_ == hWnd ) && "参照が不正です。");

	if (message == WM_CREATE) {
		me = (FWatchUI*) ((LPCREATESTRUCT) lParam)->lpCreateParams;
		assert(me != NULL && "インスタンスへのポインタが設定されていません。");
		::SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG) me);
		me->hWnd_ = hWnd;
		me->onCreate((LPCREATESTRUCT) lParam);
	}
	else if (message == WM_TASKBARCREATED) {
		assert(me != NULL && "インスタンスへのポインタが設定されていません。");
		me->onTaskbarCreate();
	}
	else {
		switch (message)
		{
		case WM_COMMAND:
			assert(me != NULL && "インスタンスへのポインタが設定されていません。");
			me->onCommand(LOWORD(wParam));
			break;

		case WM_CLOSE:
			assert(me != NULL && "インスタンスへのポインタが設定されていません。");
			me->onClose();
			return 0;

		case WM_DESTROY:
			assert(me != NULL && "インスタンスへのポインタが設定されていません。");
			me->onDestroy();
			PostQuitMessage(0);
			break;

		case WM_ENDSESSION:
			if (wParam) {
				::DestroyWindow(hWnd);
			}
			break;

		case WM_USER_NOTIFYTASKICON:
			assert(me != NULL && "インスタンスへのポインタが設定されていません。");
			me->onTaskIconNotify(wParam, lParam);
			break;

		default:
			break;
		}
	}
	return DefWindowProc(hWnd, message, wParam, lParam);
}

