/*
Miranda Crash Dumper Plugin
Copyright (C) 2008 - 2012 Boris Krasnovskiy All Rights Reserved

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation version 2
of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "stdafx.h"

HWND hViewWnd;
extern HINSTANCE hInst;

HDWP MyResizeWindow(HDWP hDwp, HWND hwndDlg, HWND hwndCtrl, int nHorizontalOffset, int nVerticalOffset, int nWidthOffset, int nHeightOffset)
{
	if (nullptr == hwndDlg) /* Wine fix. */
		return hDwp;
	// get current bounding rectangle
	RECT rcinit;
	GetWindowRect(hwndCtrl, &rcinit);

	// get current top left point
	POINT pt;
	pt.x = rcinit.left;
	pt.y = rcinit.top;
	ScreenToClient(hwndDlg, &pt);

	return DeferWindowPos(hDwp, hwndCtrl, nullptr,
		pt.x + nHorizontalOffset,
		pt.y + nVerticalOffset,
		rcinit.right - rcinit.left + nWidthOffset,
		rcinit.bottom - rcinit.top + nHeightOffset,
		SWP_NOZORDER);
}

BOOL MyResizeGetOffset(HWND hwndCtrl, int nWidth, int nHeight, int* nDx, int* nDy)
{
	RECT rcinit;

	// get current bounding rectangle
	GetWindowRect(hwndCtrl, &rcinit);

	// calculate offsets
	*nDx = nWidth - (rcinit.right - rcinit.left);
	*nDy = nHeight - (rcinit.bottom - rcinit.top);

	return rcinit.bottom != rcinit.top && nHeight > 0;
}

INT_PTR CALLBACK DlgProcView(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
	RECT rc;

	switch (msg) {
	case WM_INITDIALOG:
		TranslateDialogDefault(hwndDlg);
		Window_SetIcon_IcoLib(hwndDlg, GetIconHandle(IDI_VI));
		{
			CHARFORMAT2 chf;
			chf.cbSize = sizeof(chf);
			SendDlgItemMessage(hwndDlg, IDC_VIEWVERSIONINFO, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&chf);
			mir_wstrcpy(chf.szFaceName, TEXT("Courier New"));
			SendDlgItemMessage(hwndDlg, IDC_VIEWVERSIONINFO, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&chf);

			CMStringW buffer;
			PrintVersionInfo(buffer, (unsigned int)lParam);
			SetDlgItemText(hwndDlg, IDC_VIEWVERSIONINFO, buffer.c_str());
			SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
		}

		if (lParam & VI_FLAG_PRNDLL)
			SetWindowText(hwndDlg, TranslateT("View Version Information (with DLLs)"));

		Utils_RestoreWindowPositionNoMove(hwndDlg, NULL, PluginName, "ViewInfo_");
		ShowWindow(hwndDlg, SW_SHOW);
		break;

	case WM_SIZE:
		GetWindowRect(GetDlgItem(hwndDlg, IDC_FILEVER), &rc);

		int dx, dy;
		if (MyResizeGetOffset(GetDlgItem(hwndDlg, IDC_VIEWVERSIONINFO), LOWORD(lParam) - 20, HIWORD(lParam) - 30 - (rc.bottom - rc.top), &dx, &dy)) {
			HDWP hDwp = BeginDeferWindowPos(4);
			hDwp = MyResizeWindow(hDwp, hwndDlg, GetDlgItem(hwndDlg, IDC_FILEVER), 0, dy, 0, 0);
			hDwp = MyResizeWindow(hDwp, hwndDlg, GetDlgItem(hwndDlg, IDC_CLIPVER), dx / 2, dy, 0, 0);
			hDwp = MyResizeWindow(hDwp, hwndDlg, GetDlgItem(hwndDlg, IDCANCEL), dx, dy, 0, 0);
			hDwp = MyResizeWindow(hDwp, hwndDlg, GetDlgItem(hwndDlg, IDC_VIEWVERSIONINFO), 0, 0, dx, dy);
			EndDeferWindowPos(hDwp);
		}
		break;

	case WM_GETMINMAXINFO:
		{
			LPMINMAXINFO mmi = (LPMINMAXINFO)lParam;
			mmi->ptMinTrackSize.x = 400; // The minimum width in points
			mmi->ptMinTrackSize.y = 300; // The minimum height in points
		}
		break;

	case WM_COMMAND:
		switch (LOWORD(wParam)) {
		case IDC_CLIPVER:
			CallService(MS_CRASHDUMPER_STORETOCLIP, 0, GetWindowLongPtr(hwndDlg, GWLP_USERDATA));
			break;

		case IDC_FILEVER:
			CallService(MS_CRASHDUMPER_STORETOFILE, 0, GetWindowLongPtr(hwndDlg, GWLP_USERDATA));
			break;

		case IDCANCEL:
			DestroyWindow(hwndDlg);
			break;
		}
		break;

	case WM_CONTEXTMENU:
		{
			HWND hView = GetDlgItem(hwndDlg, IDC_VIEWVERSIONINFO);
			GetWindowRect(hView, &rc);

			POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
			if (PtInRect(&rc, pt)) {
				static const CHARRANGE all = { 0, -1 };

				HMENU hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_CONTEXT));
				HMENU hSubMenu = GetSubMenu(hMenu, 0);
				TranslateMenu(hSubMenu);

				CHARRANGE sel;
				SendMessage(hView, EM_EXGETSEL, 0, (LPARAM)&sel);
				if (sel.cpMin == sel.cpMax)
					EnableMenuItem(hSubMenu, IDM_COPY, MF_BYCOMMAND | MF_GRAYED);

				switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, nullptr)) {
				case IDM_COPY:
					SendMessage(hView, WM_COPY, 0, 0);
					break;

				case IDM_COPYALL:
					SendMessage(hView, EM_EXSETSEL, 0, (LPARAM)&all);
					SendMessage(hView, WM_COPY, 0, 0);
					SendMessage(hView, EM_EXSETSEL, 0, (LPARAM)&sel);
					break;

				case IDM_SELECTALL:
					SendMessage(hView, EM_EXSETSEL, 0, (LPARAM)&all);
					break;
				}
				DestroyMenu(hMenu);
			}
		}
		break;

	case WM_DESTROY:
		hViewWnd = nullptr;
		Window_FreeIcon_IcoLib(hwndDlg);
		Utils_SaveWindowPosition(hwndDlg, NULL, PluginName, "ViewInfo_");
		if (servicemode)
			PostQuitMessage(0);
		break;
	}
	return FALSE;
}


void DestroyAllWindows(void)
{
	if (hViewWnd != nullptr) {
		DestroyWindow(hViewWnd);
		hViewWnd = nullptr;
	}
}

INT_PTR CALLBACK DlgProcOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg) {
	case WM_INITDIALOG:
		TranslateDialogDefault(hwndDlg);
		{
			DBVARIANT dbv;
			if (db_get_s(NULL, PluginName, "Username", &dbv) == 0) {
				SetDlgItemTextA(hwndDlg, IDC_USERNAME, dbv.pszVal);
				db_free(&dbv);
			}
			if (db_get_s(NULL, PluginName, "Password", &dbv) == 0) {
				SetDlgItemTextA(hwndDlg, IDC_PASSWORD, dbv.pszVal);
				db_free(&dbv);
			}
			CheckDlgButton(hwndDlg, IDC_UPLOADCHN, db_get_b(NULL, PluginName, "UploadChanged", 0) ? BST_CHECKED : BST_UNCHECKED);
			CheckDlgButton(hwndDlg, IDC_CLASSICDATES, clsdates ? BST_CHECKED : BST_UNCHECKED);
			CheckDlgButton(hwndDlg, IDC_DATESUBFOLDER, dtsubfldr ? BST_CHECKED : BST_UNCHECKED);
			CheckDlgButton(hwndDlg, IDC_CATCHCRASHES, catchcrashes ? BST_CHECKED : BST_UNCHECKED);
			if (!catchcrashes) {
				EnableWindow(GetDlgItem(hwndDlg, IDC_CLASSICDATES), FALSE);
				EnableWindow(GetDlgItem(hwndDlg, IDC_DATESUBFOLDER), FALSE);
			}
			if (needrestart)
				ShowWindow(GetDlgItem(hwndDlg, IDC_RESTARTNOTE), SW_SHOW);
		}
		break;

	case WM_COMMAND:
		switch (LOWORD(wParam)) {
		case IDC_CATCHCRASHES:
			if (IsDlgButtonChecked(hwndDlg, IDC_CATCHCRASHES)) {
				EnableWindow(GetDlgItem(hwndDlg, IDC_CLASSICDATES), TRUE);
				EnableWindow(GetDlgItem(hwndDlg, IDC_DATESUBFOLDER), TRUE);
			}
			else {
				EnableWindow(GetDlgItem(hwndDlg, IDC_CLASSICDATES), FALSE);
				EnableWindow(GetDlgItem(hwndDlg, IDC_DATESUBFOLDER), FALSE);
			}
			ShowWindow(GetDlgItem(hwndDlg, IDC_RESTARTNOTE), SW_SHOW);
			needrestart = 1;
		}
		if ((HIWORD(wParam) == EN_CHANGE || HIWORD(wParam) == BN_CLICKED) && (HWND)lParam == GetFocus())
			SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
		break;

	case WM_NOTIFY:
		if (((LPNMHDR)lParam)->code == (unsigned)PSN_APPLY) {
			char szSetting[100];
			GetDlgItemTextA(hwndDlg, IDC_USERNAME, szSetting, _countof(szSetting));
			db_set_s(NULL, PluginName, "Username", szSetting);

			GetDlgItemTextA(hwndDlg, IDC_PASSWORD, szSetting, _countof(szSetting));
			db_set_s(NULL, PluginName, "Password", szSetting);

			db_set_b(NULL, PluginName, "UploadChanged", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_UPLOADCHN));

			clsdates = IsDlgButtonChecked(hwndDlg, IDC_CLASSICDATES) == BST_CHECKED;
			if (clsdates)
				db_set_b(NULL, PluginName, "ClassicDates", 1);
			else
				db_set_b(NULL, PluginName, "ClassicDates", 0);
			dtsubfldr = IsDlgButtonChecked(hwndDlg, IDC_DATESUBFOLDER) == BST_CHECKED;
			if (dtsubfldr)
				db_set_b(NULL, PluginName, "SubFolders", 1);
			else
				db_set_b(NULL, PluginName, "SubFolders", 0);
			catchcrashes = IsDlgButtonChecked(hwndDlg, IDC_CATCHCRASHES) == BST_CHECKED;
			if (catchcrashes)
				db_set_b(NULL, PluginName, "CatchCrashes", 1);
			else
				db_set_b(NULL, PluginName, "CatchCrashes", 0);
		}
		break;
	}
	return FALSE;
}


LRESULT CALLBACK DlgProcPopup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg) {
	case WM_CONTEXTMENU:
		PUDeletePopup(hWnd);
		break;

	case WM_COMMAND:
		switch ((INT_PTR)PUGetPluginData(hWnd)) {
		case 0:
			OpenAuthUrl("https://vi.miranda-ng.org/detail/%s");
			break;

		case 1:
			OpenAuthUrl("https://vi.miranda-ng.org/global/%s");
			break;

		case 3:
			wchar_t path[MAX_PATH];
			mir_snwprintf(path, TEXT("%s\\VersionInfo.txt"), VersionInfoFolder);
			ShellExecute(nullptr, TEXT("open"), path, nullptr, nullptr, SW_SHOW);
			break;

		}
		PUDeletePopup(hWnd);
		break;

	case UM_FREEPLUGINDATA:
		Window_FreeIcon_IcoLib(hWnd);
		break;
	}

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

void ShowMessage(int type, const wchar_t* format, ...)
{
	POPUPDATAT pi = { 0 };

	va_list va;
	va_start(va, format);
	int len = mir_vsnwprintf(pi.lptzText, _countof(pi.lptzText) - 1, format, va);
	pi.lptzText[len] = 0;
	va_end(va);

	if (ServiceExists(MS_POPUP_ADDPOPUPT)) {
		mir_wstrcpy(pi.lptzContactName, TEXT(PluginName));
		pi.lchIcon = LoadIconEx(IDI_VI);
		pi.PluginWindowProc = DlgProcPopup;
		pi.PluginData = (void*)type;

		PUAddPopupT(&pi);
	}
	else MessageBox(nullptr, pi.lptzText, TEXT(PluginName), MB_OK | MB_ICONINFORMATION);
}