/*
Quick Messages plugin for Miranda IM

Copyright (C) 2008 Danil Mozhar

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, either version 3 of the License, or
(at your option) any later version.

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"

int g_iOPButtonsCount;
BOOL bNeedRestart = FALSE;
BOOL drag = FALSE, bOptionsInit = TRUE;
HTREEITEM hDragItem = NULL;
HWND hButtonsList = NULL;
HWND hMenuTree = NULL;
HWND hwndEdit = NULL;
				   
HWND g_opHdlg = NULL, g_varhelpDlg = NULL;

INT_PTR CALLBACK HelpDlgProc(HWND hdlg, UINT msg, WPARAM, LPARAM lparam)
{
	switch (msg) {
	case WM_INITDIALOG:
		{
			LOGFONT logFont;
			HFONT hFont;
			RECT rc;
			g_varhelpDlg = hdlg;
			TranslateDialogDefault(hdlg);
			hFont = (HFONT)SendDlgItemMessage(hdlg, IDC_STATICTITLE, WM_GETFONT, 0, 0);
			GetObject(hFont, sizeof logFont, &logFont);
			logFont.lfWeight = FW_BOLD;
			hFont = CreateFontIndirect(&logFont);
			SendDlgItemMessage(hdlg, IDC_STATICTITLE, WM_SETFONT, (WPARAM)hFont, 0);
			SendDlgItemMessage(hdlg, IDC_STATICTITLE2, WM_SETFONT, (WPARAM)hFont, 0);
			SendDlgItemMessage(hdlg, IDC_VARTEXT, WM_SETFONT, (WPARAM)hFont, 0);
			SendDlgItemMessage(hdlg, IDC_VARCLIP, WM_SETFONT, (WPARAM)hFont, 0);
			SendDlgItemMessage(hdlg, IDC_VARPUNAME, WM_SETFONT, (WPARAM)hFont, 0);
			SendDlgItemMessage(hdlg, IDC_VARPLNAME, WM_SETFONT, (WPARAM)hFont, 0);
			SendDlgItemMessage(hdlg, IDC_VARCNAME, WM_SETFONT, (WPARAM)hFont, 0);
			SendDlgItemMessage(hdlg, IDC_VARCFNAME, WM_SETFONT, (WPARAM)hFont, 0);
			SendDlgItemMessage(hdlg, IDC_VARCLNAME, WM_SETFONT, (WPARAM)hFont, 0);

			GetWindowRect(g_opHdlg, &rc);
			SetWindowPos(hdlg, 0, rc.left, rc.top, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE);
		}
		break;

	case WM_LBUTTONDOWN:
		PostMessage(hdlg, WM_NCLBUTTONDOWN, HTCAPTION, lparam);
		break;

	case WM_CLOSE:
	case WM_DESTROY:
		DestroyWindow(g_varhelpDlg);
		g_varhelpDlg = NULL;
		break;

	default:
		return FALSE;
	}
	return TRUE;
}

static LRESULT CALLBACK LabelEditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg) {
	case WM_GETDLGCODE:
		return DLGC_WANTALLKEYS;
	}
	return mir_callNextSubclass(hwnd, LabelEditSubclassProc, msg, wParam, lParam);
}

static LRESULT CALLBACK EditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	HWND hParent = GetParent(hwnd);
	switch (msg) {
	case WM_GETDLGCODE:
		return DLGC_WANTALLKEYS | DLGC_HASSETSEL;

	case WM_SETFOCUS:
		PostMessage(hwnd, EM_SETSEL, 0, -1);
		break;

	case WM_KEYDOWN:
		{
			if (wParam == VK_RETURN)
				if (hwnd == GetDlgItem(hParent, IDC_BUTTONNAME))
					SendMessage(hParent, WM_COMMAND, IDC_BLISTADD, 0);
				else
					SendMessage(hParent, WM_COMMAND, IDC_MTREEADD, 0);
		}break;
	}

	return mir_callNextSubclass(hwnd, EditSubclassProc, msg, wParam, lParam);
}

void SetMenuEntryProperties(HWND hdlg)
{
	TVITEM tvi;
	HTREEITEM hItem = NULL;
	int pos = 0;

	if (TreeView_GetCount(hButtonsList) && (tvi.hItem = TreeView_GetSelection(hButtonsList))) {
		tvi.mask = TVIF_HANDLE | TVIF_PARAM;
		TreeView_GetItem(hButtonsList, &tvi);

		if (tvi.lParam) {
			ListData* ld = (ListData*)tvi.lParam;
			TCHAR szValue[256];
			GetDlgItemText(hdlg, IDC_RCLICKVALUE, szValue, _countof(szValue));
			if (mir_tstrlen(szValue)) {
				if (ld->ptszOPQValue && (ld->ptszOPQValue != ld->ptszQValue))
					mir_free(ld->ptszOPQValue);
				ld->ptszOPQValue = mir_tstrdup(szValue);
			}
			ld->bIsOpServName = IsDlgButtonChecked(hdlg, IDC_ISSERVNAME2);
		}
	}

	tvi.hItem = NULL;
	if (TreeView_GetCount(hMenuTree) && (tvi.hItem = TreeView_GetSelection(hMenuTree))) {
		tvi.mask = TVIF_HANDLE | TVIF_PARAM;
		TreeView_GetItem(hMenuTree, &tvi);

		if (tvi.lParam) {
			ButtonData *bd = (ButtonData*)tvi.lParam;
			TCHAR szValue[256];
			GetDlgItemText(hdlg, IDC_MENUVALUE, szValue, _countof(szValue));
			if (mir_tstrlen(szValue)) {
				if (mir_tstrlen(bd->pszOpValue) && (bd->pszOpValue != bd->pszValue))
					mir_free(bd->pszOpValue);
				bd->pszOpValue = mir_tstrdup(szValue);
			}
			bd->bOpInQMenu = IsDlgButtonChecked(hdlg, IDC_INQMENU);
			bd->bIsOpServName = IsDlgButtonChecked(hdlg, IDC_ISSERVNAME);
		}

		tvi.mask = TVIF_HANDLE | TVIF_PARAM;
		tvi.hItem = TreeView_GetRoot(hMenuTree);
	}
	while (tvi.hItem) {
		TreeView_GetItem(hMenuTree, &tvi);
		ButtonData *bd = (ButtonData*)tvi.lParam;

		bd->dwOPPos = pos++;

		if (hItem = TreeView_GetChild(hMenuTree, tvi.hItem)) {

			bd->fEntryOpType &= ~QMF_EX_CHILD;

			if (bd->pszOpValue) {
				mir_free(bd->pszOpValue);
				bd->pszOpValue = NULL;
			}
			tvi.hItem = hItem;
			continue;
		}
		else {
			if (bd->fEntryOpType&QMF_EX_SEPARATOR) {
				if (bd->pszOpValue) {
					mir_free(bd->pszOpValue);
					bd->pszOpValue = NULL;
				}
			}
			else {
				if (!bd->pszOpValue)
					bd->pszOpValue = mir_tstrdup(LPGENT("Enter Value"));
			}
			if (TreeView_GetParent(hMenuTree, tvi.hItem))
				bd->fEntryOpType |= QMF_EX_CHILD;
			else bd->fEntryOpType &= ~QMF_EX_CHILD;

			if (!(hItem = TreeView_GetNextSibling(hMenuTree, tvi.hItem)))
				tvi.hItem = TreeView_GetNextSibling(hMenuTree, TreeView_GetParent(hMenuTree, tvi.hItem));
			else
				tvi.hItem = hItem;

		}
	}
}

void SaveMenuTree()
{
	int iBl = 0, i = 0, k = 0;
	int iBtd = g_iButtonsCount;
	BOOL bDeleted = FALSE;
	char szMEntry[256] = { '\0' };
	TCHAR strbuf[256];
	HTREEITEM hti = NULL;
	TVITEM tvi;

	g_iButtonsCount = TreeView_GetCount(hButtonsList);

	tvi.pszText = strbuf;
	tvi.cchTextMax = _countof(strbuf);
	tvi.mask = TVIF_HANDLE | TVIF_TEXT;
	tvi.hItem = TreeView_GetRoot(hButtonsList);

	TreeView_GetItem(hButtonsList, &tvi);

	li_ZeroQuickList(QuickList);

	BalanceButtons(iBtd, g_iButtonsCount);

	while (ButtonsList[iBl]) {
		SortedList * sl = NULL;
		ListData* ld = ButtonsList[iBl];

		if (!ld->sl) break;

		sl = ld->sl;

		if (ld->dwOPFlags&QMF_DELETNEEDED) {
			bDeleted = (ld->dwOPFlags&QMF_NEW) ? FALSE : TRUE;
			if (bDeleted) CleanSettings(ld->dwPos, -1);
			DestroyButton(iBl);
			continue;
		}
		if (ld->ptszQValue != ld->ptszOPQValue) {
			if (ld->ptszQValue)
				mir_free(ld->ptszQValue);

			ld->ptszQValue = (ld->ptszOPQValue) ? ld->ptszOPQValue : NULL;
		}

		if (ld->ptszButtonName)
			mir_free(ld->ptszButtonName);
		if (iBl > 0)
			if (hti = TreeView_GetNextSibling(hButtonsList, hti ? hti : tvi.hItem)) {
				tvi.hItem = hti;
				TreeView_GetItem(hButtonsList, &tvi);
			}

		ld->ptszButtonName = mir_tstrdup(tvi.pszText);

		if (ld->ptszQValue) {
			mir_snprintf(szMEntry, "ButtonValue_%u", iBl);
			db_set_ts(NULL, PLGNAME, szMEntry, ld->ptszQValue);
		}


		if (ServiceExists(MS_BB_MODIFYBUTTON) && ((ld->dwOPFlags&QMF_NEW) || (ld->dwOPFlags&QMF_RENAMED) || bDeleted)) {
			BBButton bb = { 0 };
			bb.cbSize = sizeof(BBButton);
			bb.pszModuleName = PLGNAME;
			bb.dwButtonID = iBl;
			bb.ptszTooltip = ld->ptszButtonName;
			CallService(MS_BB_MODIFYBUTTON, 0, (LPARAM)&bb);
		}


		mir_snprintf(szMEntry, "ButtonName_%u", iBl);
		db_set_ts(NULL, PLGNAME, szMEntry, ld->ptszButtonName);

		ld->dwOPFlags = 0;
		ld->dwPos = iBl;
		ld->bIsServName = ld->bIsOpServName;
		mir_snprintf(szMEntry, "RCEntryIsServiceName_%u", iBl);
		db_set_b(NULL, PLGNAME, szMEntry, ld->bIsServName);

		bDeleted = FALSE;

		qsort(sl->items, sl->realCount, sizeof(ButtonData *), sstSortButtons);

		for (i = 0; i < sl->realCount; i++) {
			ButtonData * bd = (ButtonData *)sl->items[i];

			if (bd->dwOPFlags&QMF_DELETNEEDED) {
				RemoveMenuEntryNode(sl, i--);
				continue;
			}
			bd->bIsServName = bd->bIsOpServName;
			bd->bInQMenu = bd->bOpInQMenu;
			bd->dwPos = bd->dwOPPos;
			bd->fEntryType = bd->fEntryOpType;
			bd->dwOPFlags = 0;

			if (bd->pszName != bd->pszOpName) {
				if (bd->pszName)
					mir_free(bd->pszName);
				bd->pszName = bd->pszOpName ? bd->pszOpName : NULL;
			}

			if (bd->pszValue != bd->pszOpValue) {
				if (bd->pszValue)
					mir_free(bd->pszValue);
				bd->pszValue = bd->pszOpValue ? bd->pszOpValue : NULL;
			}
			if (bd->bInQMenu) {
				QuickData* qd = (QuickData *)mir_alloc(sizeof(QuickData));
				qd->dwPos = k++;
				qd->fEntryType = bd->fEntryType;
				qd->bIsService = bd->bIsServName;
				qd->ptszValue = bd->pszValue;
				qd->ptszValueName = bd->pszName;
				List_InsertPtr(QuickList, qd);
			}

			SaveModuleSettings(iBl, bd);
		}
		CleanSettings(iBl, sl->realCount);

		iBl++;
	}

	db_set_b(NULL, PLGNAME, "ButtonsCount", (BYTE)g_iButtonsCount);
}

void RestoreModuleData()
{
	int iBl = 0, i = 0;

	while (ButtonsList[iBl]) {
		SortedList * sl = NULL;
		ListData* ld = ButtonsList[iBl];

		if (!(sl = ld->sl)) break;

		if (ld->dwOPFlags&QMF_NEW) {
			DestroyButton(iBl);
			continue;
		}

		if (ld->ptszQValue != ld->ptszOPQValue) {
			if (ld->ptszOPQValue)
				mir_free(ld->ptszOPQValue);

			ld->ptszOPQValue = (ld->ptszQValue) ? ld->ptszQValue : NULL;
		}

		ld->bIsOpServName = ld->bIsServName;
		ld->dwOPFlags = 0;

		qsort(sl->items, sl->realCount, sizeof(ButtonData *), sstSortButtons);

		for (i = 0; i < sl->realCount; i++) {
			ButtonData * bd = (ButtonData *)sl->items[i];

			if (bd->dwOPFlags&QMF_NEW) {
				RemoveMenuEntryNode(sl, i--);
				continue;
			}
			bd->bIsOpServName = bd->bIsServName;
			bd->bOpInQMenu = bd->bInQMenu;
			bd->dwOPPos = bd->dwPos;
			bd->fEntryOpType = bd->fEntryType;
			bd->dwOPFlags = 0;

			if (bd->pszName != bd->pszOpName) {
				if (bd->pszOpName)
					mir_free(bd->pszOpName);
				bd->pszOpName = bd->pszName ? bd->pszName : NULL;
			}

			if (bd->pszValue != bd->pszOpValue) {
				if (bd->pszOpValue)
					mir_free(bd->pszOpValue);
				bd->pszOpValue = bd->pszValue ? bd->pszValue : NULL;
			}
		}
		iBl++;
	}
}

static int BuildMenuTree(HWND hToolBarTree, SortedList * sl)
{
	TVINSERTSTRUCT tvis;
	int i;
	HTREEITEM hParent = NULL;
	tvis.hParent = NULL;
	tvis.hInsertAfter = TVI_LAST;
	tvis.item.mask = TVIF_PARAM | TVIF_TEXT;

	TreeView_DeleteAllItems(hToolBarTree);
	if (!sl) return 1;

	qsort(sl->items, sl->realCount, sizeof(ButtonData *), sstOpSortButtons);

	for (i = 0; i < sl->realCount; i++) {
		ButtonData * bd = (ButtonData *)sl->items[i];

		if (bd->dwOPFlags&QMF_DELETNEEDED)
			continue;

		tvis.item.lParam = (LPARAM)bd;
		tvis.item.pszText = bd->pszOpName;

		if (bd->fEntryOpType == 0)
			tvis.hParent = NULL;

		hParent = TreeView_InsertItem(hToolBarTree, &tvis);
		if (tvis.hParent) TreeView_Expand(hMenuTree, tvis.hParent, TVE_EXPAND);
		if (!bd->pszOpValue&&bd->fEntryOpType == 0) {
			tvis.hParent = hParent;
		}
		// 		else if (!(bd->fEntryOpType&QMF_EX_CHILD))
		// 			tvis.hParent = NULL;
	}

	return 1;
}

static int BuildButtonsList(HWND hToolBarTree)
{
	TVINSERTSTRUCT tvis;
	int i = 0;
	tvis.hParent = NULL;
	tvis.hInsertAfter = TVI_LAST;
	tvis.item.mask = TVIF_PARAM | TVIF_TEXT;

	TreeView_DeleteAllItems(hToolBarTree);

	//for(i=0;i<g_iButtonsCount;i++)
	while (ButtonsList[i]) {
		tvis.item.lParam = (LPARAM)ButtonsList[i];
		tvis.item.pszText = ButtonsList[i]->ptszButtonName;

		TreeView_InsertItem(hToolBarTree, &tvis);
		i++;
	}
	return 1;
}
///////////////////////////////////
//From UserInfoEx by DeathAxe
//
void MoveItem(HTREEITEM hItem, HTREEITEM hInsertAfter, BOOLEAN bAsChild)
{
	TVINSERTSTRUCT tvis;
	//TCHAR strbuf[128];
	HTREEITEM hParent, hChild, hNewItem;

	if (!hItem || !hInsertAfter)
		return;
	if (hItem == hInsertAfter)
		return;

	switch ((ULONG_PTR)hInsertAfter) {
	case TVI_ROOT:
	case TVI_FIRST:
	case TVI_LAST:
		hParent = NULL;
		bAsChild = FALSE;
		break;
	default:
		hParent = TreeView_GetParent(hMenuTree, hInsertAfter);
		break;
	}
	// do not move a parent next to its own children!
	if (hItem == hParent)
		return;

	// prepare the insert structure
	{
		TCHAR strbuf[128];
		tvis.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_TEXT;

		tvis.item.pszText = strbuf;
		tvis.item.cchTextMax = _countof(strbuf);
		tvis.item.hItem = hItem;
		TreeView_GetItem(hMenuTree, &tvis.item);
	}

	// item should be inserted as the first child of an existing root item
	if (bAsChild) {
		tvis.hParent = hInsertAfter;
		tvis.hInsertAfter = (bAsChild == 2) ? TVI_LAST : TVI_FIRST;
	}
	// item should be inserted after an existing item
	else {
		tvis.hParent = hParent;
		tvis.hInsertAfter = hInsertAfter;
	}
	// insert the item
	if (!(hNewItem = TreeView_InsertItem(hMenuTree, &tvis)))
		return;

	// move children
	hInsertAfter = hNewItem;
	while (hChild = TreeView_GetChild(hMenuTree, hItem)) {
		MoveItem(hChild, hInsertAfter, 2);
	}
	// delete old tree
	TreeView_DeleteItem(hMenuTree, hItem);

	TreeView_SelectItem(hMenuTree, hNewItem);
	//TreeView_Expand( hMenuTree, hNewItem, TVE_EXPAND );
}


///////
INT_PTR CALLBACK OptionsProc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
{
	switch (msg) {
	case WM_INITDIALOG:{
			DWORD style;
			g_opHdlg = hdlg;
			bOptionsInit = TRUE;
			TranslateDialogDefault(hdlg);
			if (g_iButtonsCount != db_get_b(NULL, PLGNAME, "ButtonsCount", 0)) {
				LOGFONT logFont;
				HFONT hFont;
				bNeedRestart = TRUE;
				EnableWindow(GetDlgItem(hdlg, IDC_BUTTONSLIST), FALSE);
				EnableWindow(GetDlgItem(hdlg, IDC_BLISTADD), FALSE);
				EnableWindow(GetDlgItem(hdlg, IDC_BLISTREMOVE), FALSE);
				EnableWindow(GetDlgItem(hdlg, IDC_MENUTREE), FALSE);
				EnableWindow(GetDlgItem(hdlg, IDC_MTREEADD), FALSE);
				EnableWindow(GetDlgItem(hdlg, IDC_MTREEREMOVE), FALSE);
				EnableWindow(GetDlgItem(hdlg, IDC_MENUVALUE), FALSE);
				EnableWindow(GetDlgItem(hdlg, IDC_RCLICKVALUE), FALSE);
				EnableWindow(GetDlgItem(hdlg, IDC_BUTTONNAME), FALSE);
				EnableWindow(GetDlgItem(hdlg, IDC_INQMENU), FALSE);
				EnableWindow(GetDlgItem(hdlg, IDC_ISSERVNAME), FALSE);
				EnableWindow(GetDlgItem(hdlg, IDC_MENUNAME), FALSE);
				ShowWindow(GetDlgItem(hdlg, IDC_WARNING), SW_SHOW);

				hFont = (HFONT)SendDlgItemMessage(hdlg, IDC_WARNING, WM_GETFONT, 0, 0);
				GetObject(hFont, sizeof(logFont), &logFont);
				logFont.lfWeight = FW_BOLD;
				hFont = CreateFontIndirect(&logFont);
				SendDlgItemMessage(hdlg, IDC_WARNING, WM_SETFONT, (WPARAM)hFont, 0);
				break;
			}

			g_iOPButtonsCount = g_iButtonsCount;

			hButtonsList = GetDlgItem(hdlg, IDC_BUTTONSLIST);
			hMenuTree = GetDlgItem(hdlg, IDC_MENUTREE);

			style = GetWindowLongPtr(hButtonsList, GWL_STYLE);
			style |= TVS_NOHSCROLL;
			SetWindowLongPtr(hButtonsList, GWL_STYLE, style);

			style = GetWindowLongPtr(hMenuTree, GWL_STYLE);
			style |= TVS_NOHSCROLL;
			SetWindowLongPtr(hMenuTree, GWL_STYLE, style);
			BuildButtonsList(hButtonsList);

			if (!TreeView_GetCount(hButtonsList))
				EnableWindow(GetDlgItem(hdlg, IDC_RCLICKVALUE), FALSE);

			mir_subclassWindow(GetDlgItem(hdlg, IDC_BUTTONNAME), EditSubclassProc);
			mir_subclassWindow(GetDlgItem(hdlg, IDC_MENUNAME), EditSubclassProc);

			EnableWindow(GetDlgItem(hdlg, IDC_MENUVALUE), FALSE);
			EnableWindow(GetDlgItem(hdlg, IDC_INQMENU), FALSE);
			EnableWindow(GetDlgItem(hdlg, IDC_ISSERVNAME), FALSE);
			CheckDlgButton(hdlg, IDC_RAUTOSEND, (g_bRClickAuto = db_get_b(NULL, PLGNAME, "RClickAuto", 0)) ? BST_CHECKED : BST_UNCHECKED);
			CheckDlgButton(hdlg, IDC_LAUTOSEND, (g_bLClickAuto = db_get_b(NULL, PLGNAME, "LClickAuto", 0)) ? BST_CHECKED : BST_UNCHECKED);
			CheckDlgButton(hdlg, IDC_ENABLEQUICKMENU, (g_bQuickMenu = db_get_b(NULL, PLGNAME, "QuickMenu", 1)) ? BST_CHECKED : BST_UNCHECKED);

			bOptionsInit = FALSE;
		}break;

	case WM_LBUTTONUP:
		if (drag) {
			TVHITTESTINFO hti;
			HTREEITEM htiAfter = NULL;
			ButtonData* bd = NULL;
			TVITEM tvi;
			RECT rc;
			BYTE height;
			BOOLEAN bAsChild = FALSE;

			TreeView_SetInsertMark(hMenuTree, NULL, 0);
			ReleaseCapture();
			SetCursor(LoadCursor(NULL, IDC_ARROW));

			hti.pt.x = (SHORT)LOWORD(lparam);
			hti.pt.y = (SHORT)HIWORD(lparam);
			ClientToScreen(hdlg, &hti.pt);
			ScreenToClient(hMenuTree, &hti.pt);
			TreeView_HitTest(hMenuTree, &hti);

			if (TreeView_GetParent(hMenuTree, hti.hItem) && TreeView_GetChild(hMenuTree, hDragItem))
				break;

			if (TreeView_GetChild(hMenuTree, hti.hItem) && TreeView_GetChild(hMenuTree, hDragItem))
				break;


			if (hti.flags & TVHT_ABOVE) {
				htiAfter = TVI_FIRST;
			}
			else
				if (hti.flags & (TVHT_NOWHERE | TVHT_BELOW)) {
					htiAfter = TVI_LAST;
				}
				else
					if (hti.flags & (TVHT_ONITEM | TVHT_ONITEMRIGHT)) {
						// check where over the item, the pointer is
						if (!TreeView_GetItemRect(hMenuTree, hti.hItem, &rc, FALSE)) {
							drag = 0;
							break;
						}
						height = (BYTE)(rc.bottom - rc.top);

						if (hti.pt.y - (height / 3) < rc.top) {
							HTREEITEM hItem = hti.hItem;

							if (!(hti.hItem = TreeView_GetPrevSibling(hMenuTree, hItem))) {
								if (!(hti.hItem = TreeView_GetParent(hMenuTree, hItem)))
									htiAfter = TVI_FIRST;
								else
									bAsChild = TRUE;
							}
						}
						else
							if (hti.pt.y + (height / 3) <= rc.bottom) {
								bAsChild = TRUE;
							}
					}


			if (TreeView_GetChild(hMenuTree, hDragItem) && bAsChild)
				break;


			if (hti.hItem) {
				tvi.hItem = hti.hItem;
				tvi.mask = TVIF_PARAM | TVIF_HANDLE;
				TreeView_GetItem(hMenuTree, &tvi);
				if ((bd = (ButtonData*)tvi.lParam) && (bd->fEntryOpType&QMF_EX_SEPARATOR))
					bAsChild = FALSE;
			}

			if (TreeView_GetParent(hMenuTree, hti.hItem))
				bAsChild = FALSE;


			MoveItem(hDragItem, htiAfter ? htiAfter : hti.hItem, bAsChild);
			SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
			drag = 0;

		}
		break;

		///////////////////////////////////
		//From UserInfoEx by DeathAxe
		//
	case WM_MOUSEMOVE:
		{
			if (!drag) break;
			{
				TVHITTESTINFO hti;

				hti.pt.x = (short)LOWORD(lparam);
				hti.pt.y = (short)HIWORD(lparam);
				ClientToScreen(hdlg, &hti.pt);
				ScreenToClient(hMenuTree, &hti.pt);
				TreeView_HitTest(hMenuTree, &hti);
				if (hti.flags & (TVHT_ONITEM | TVHT_ONITEMRIGHT)) {
					RECT rc;
					BYTE height;

					if (TreeView_GetItemRect(hMenuTree, hti.hItem, &rc, FALSE)) {
						height = (BYTE)(rc.bottom - rc.top);

						if (hti.pt.y - (height / 3) < rc.top) {
							SetCursor(LoadCursor(NULL, IDC_ARROW));
							TreeView_SetInsertMark(hMenuTree, hti.hItem, 0);
						}
						else
							if (hti.pt.y + (height / 3) > rc.bottom) {
								SetCursor(LoadCursor(NULL, IDC_ARROW));
								TreeView_SetInsertMark(hMenuTree, hti.hItem, 1);
							}
							else {
								TreeView_SetInsertMark(hMenuTree, NULL, 0);
								SetCursor(LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(183)));
							}
					}
				}
				else {
					if (hti.flags & TVHT_ABOVE) SendMessage(hMenuTree, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), 0);
					if (hti.flags & TVHT_BELOW) SendMessage(hMenuTree, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), 0);
					TreeView_SetInsertMark(hMenuTree, NULL, 0);
				}
			}
		}break;
		/////////////
	case WM_DESTROY:
		if (g_varhelpDlg)
			DestroyWindow(g_varhelpDlg);
		g_varhelpDlg = NULL;
		break;

	case WM_NOTIFY:
		switch (((LPNMHDR)lparam)->idFrom) {
		case 0:
			if (((LPNMHDR)lparam)->code == PSN_APPLY) {
				if (!bNeedRestart) {
					SetMenuEntryProperties(hdlg);
					SaveMenuTree();
				}
				db_set_b(NULL, PLGNAME, "RClickAuto", (BYTE)(g_bRClickAuto = IsDlgButtonChecked(hdlg, IDC_RAUTOSEND)));
				db_set_b(NULL, PLGNAME, "LClickAuto", (BYTE)(g_bLClickAuto = IsDlgButtonChecked(hdlg, IDC_LAUTOSEND)));
				db_set_b(NULL, PLGNAME, "QuickMenu", (BYTE)(g_bQuickMenu = IsDlgButtonChecked(hdlg, IDC_ENABLEQUICKMENU)));
				return 1;
			}
			else if (((LPNMHDR)lparam)->code == PSN_RESET) {
				if (!bNeedRestart)
					RestoreModuleData();
				return 1;
			}
			break;

		case IDC_MENUTREE:
			switch (((LPNMHDR)lparam)->code) {
			case TVN_KEYDOWN:{
					TV_KEYDOWN* pTVKeyDown = (TV_KEYDOWN*)((LPNMHDR)lparam);
					if (pTVKeyDown->wVKey == VK_F2)
						TreeView_EditLabel(hMenuTree, TreeView_GetSelection(hMenuTree));
					else if (pTVKeyDown->wVKey == VK_DELETE)
						SendMessage(hdlg, WM_COMMAND, IDC_MTREEREMOVE, 0);
				}break;

			case TVN_BEGINLABELEDIT:
				hwndEdit = TreeView_GetEditControl(hMenuTree);
				mir_subclassWindow(hwndEdit, LabelEditSubclassProc);
				break;

			case TVN_ENDLABELEDIT:
				{
					TVITEM tvi;
					ButtonData* bd = NULL;
					TCHAR strbuf[256];
					TCHAR szLabel[256];

					tvi.pszText = strbuf;
					tvi.cchTextMax = _countof(strbuf);
					tvi.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_PARAM;
					tvi.hItem = TreeView_GetSelection(hMenuTree);
					TreeView_GetItem(hMenuTree, &tvi);

					GetWindowText(hwndEdit, szLabel, _countof(szLabel));
					hwndEdit = NULL;
					if (!mir_tstrlen(szLabel)) break;
					if (bd = (ButtonData*)tvi.lParam) {
						if (!mir_tstrcmp(szLabel, _T("---"))) {
							if (TreeView_GetChild(hMenuTree, tvi.hItem))
								break;
							else {
								bd->fEntryOpType = QMF_EX_SEPARATOR;
								EnableWindow(GetDlgItem(hdlg, IDC_MENUVALUE), FALSE);
								EnableWindow(GetDlgItem(hdlg, IDC_ISSERVNAME), FALSE);
								SetDlgItemText(hdlg, IDC_MENUVALUE, _T(""));
							}
						}
						else {
							bd->fEntryOpType &= ~QMF_EX_SEPARATOR;
							EnableWindow(GetDlgItem(hdlg, IDC_MENUVALUE), TRUE);
							EnableWindow(GetDlgItem(hdlg, IDC_ISSERVNAME), TRUE);
							SetDlgItemText(hdlg, IDC_MENUVALUE, bd->pszOpValue/*?bd->pszOpValue:bd->pszValue*/);
						}

						bd->pszOpName = mir_tstrdup(szLabel);

						tvi.pszText = szLabel;
						TreeView_SetItem(hMenuTree, &tvi);
						SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
					}
				}
				break;

			case NM_KILLFOCUS:
				TreeView_EndEditLabelNow(hButtonsList, 1);
				break;

			case TVN_BEGINDRAG:
				SetCapture(hdlg);
				drag = 1;
				hDragItem = ((LPNMTREEVIEW)lparam)->itemNew.hItem;
				TreeView_SelectItem(hMenuTree, hDragItem);
				break;

			case TVN_SELCHANGING:
				{
					HTREEITEM hti = TreeView_GetSelection(hMenuTree);
					if (hti == NULL)
						break;

					TVITEM tvi;
					tvi.hItem = hti;
					tvi.mask = TVIF_HANDLE | TVIF_PARAM;
					TreeView_GetItem(hMenuTree, &tvi);
					if (tvi.lParam == 0)
						break;

					ButtonData *bd = (ButtonData*)tvi.lParam;
					if (bd) {
						TCHAR szValue[256];
						GetDlgItemText(hdlg, IDC_MENUVALUE, szValue, _countof(szValue));
						if (mir_tstrlen(szValue)) {
							if (bd->pszOpValue && (bd->pszOpValue != bd->pszValue))
								mir_free(bd->pszOpValue);
							bd->pszOpValue = mir_tstrdup(szValue);
						}
						bd->bOpInQMenu = IsDlgButtonChecked(hdlg, IDC_INQMENU);
						bd->bIsOpServName = IsDlgButtonChecked(hdlg, IDC_ISSERVNAME);
					}
				}
				break;

			case TVN_SELCHANGED:
				{
					HTREEITEM hti = TreeView_GetSelection(hMenuTree);
					if (hti == NULL)
						break;

					TVITEM tvi;
					tvi.mask = TVIF_HANDLE | TVIF_PARAM;
					tvi.hItem = hti;
					TreeView_GetItem(hMenuTree, &tvi);

					ButtonData *bd = (ButtonData*)tvi.lParam;
					if (bd) {
						if (!TreeView_GetChild(hMenuTree, tvi.hItem) && !(bd->fEntryOpType&QMF_EX_SEPARATOR)) {
							EnableWindow(GetDlgItem(hdlg, IDC_MENUVALUE), TRUE);
							EnableWindow(GetDlgItem(hdlg, IDC_ISSERVNAME), TRUE);
							EnableWindow(GetDlgItem(hdlg, IDC_INQMENU), TRUE);
							SetDlgItemText(hdlg, IDC_MENUVALUE, bd->pszOpValue/*?bd->pszOpValue:bd->pszValue*/);
						}
						else {
							EnableWindow(GetDlgItem(hdlg, IDC_MENUVALUE), FALSE);
							EnableWindow(GetDlgItem(hdlg, IDC_ISSERVNAME), FALSE);
							if (!(bd->fEntryOpType&QMF_EX_SEPARATOR))
								EnableWindow(GetDlgItem(hdlg, IDC_INQMENU), FALSE);
							SetDlgItemText(hdlg, IDC_MENUVALUE, _T(""));
						}
						CheckDlgButton(hdlg, IDC_INQMENU, bd->bOpInQMenu ? BST_CHECKED : BST_UNCHECKED);
						CheckDlgButton(hdlg, IDC_ISSERVNAME, bd->bIsOpServName ? BST_CHECKED : BST_UNCHECKED);
					}
				}
			}
			break;

		case IDC_BUTTONSLIST:
			switch (((LPNMHDR)lparam)->code) {
			case TVN_KEYDOWN:{
					TV_KEYDOWN* pTVKeyDown = (TV_KEYDOWN*)((LPNMHDR)lparam);
					if (pTVKeyDown->wVKey == VK_F2)
						TreeView_EditLabel(hButtonsList, TreeView_GetSelection(hButtonsList));
					else if (pTVKeyDown->wVKey == VK_DELETE)
						SendMessage(hdlg, WM_COMMAND, IDC_BLISTREMOVE, 0);
				}break;

			case TVN_BEGINLABELEDIT:
				hwndEdit = TreeView_GetEditControl(hButtonsList);
				mir_subclassWindow(hwndEdit, LabelEditSubclassProc);
				break;

			case TVN_ENDLABELEDIT:
				{
					TVITEM tvi;
					TCHAR strbuf[128];
					TCHAR szLabel[128];

					tvi.pszText = strbuf;
					tvi.cchTextMax = _countof(strbuf);
					tvi.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_PARAM;
					tvi.hItem = TreeView_GetSelection(hButtonsList);
					TreeView_GetItem(hButtonsList, &tvi);

					GetWindowText(hwndEdit, szLabel, _countof(szLabel));
					hwndEdit = NULL;
					if (!mir_tstrlen(szLabel)) break;

					tvi.pszText = szLabel;
					((ListData*)tvi.lParam)->dwOPFlags |= QMF_RENAMED;

					TreeView_SetItem(hButtonsList, &tvi);
					SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
				}
				break;

			case TVN_SELCHANGING:
				SetMenuEntryProperties(hdlg);
				break;

			case TVN_SELCHANGED:
				{
					HTREEITEM hti = TreeView_GetSelection(hButtonsList);
					if (hti == NULL || !TreeView_GetCount(hButtonsList)) {
						EnableWindow(GetDlgItem(hdlg, IDC_MENUVALUE), FALSE);
						EnableWindow(GetDlgItem(hdlg, IDC_ISSERVNAME), FALSE);
						EnableWindow(GetDlgItem(hdlg, IDC_INQMENU), FALSE);
						EnableWindow(GetDlgItem(hdlg, IDC_ISSERVNAME2), FALSE);
						SetDlgItemText(hdlg, IDC_MENUVALUE, _T(""));
						break;
					}

					TVITEM tvi;
					tvi.mask = TVIF_HANDLE | TVIF_PARAM;
					tvi.hItem = hti;
					TreeView_GetItem(hButtonsList, &tvi);

					if (tvi.lParam == 0) break;

					BuildMenuTree(hMenuTree, (SortedList *)((ListData*)tvi.lParam)->sl);

					SetDlgItemText(hdlg, IDC_MENUVALUE, _T(""));
					EnableWindow(GetDlgItem(hdlg, IDC_RCLICKVALUE), TRUE);
					EnableWindow(GetDlgItem(hdlg, IDC_ISSERVNAME2), TRUE);
					CheckDlgButton(hdlg, IDC_ISSERVNAME2, ((ListData*)tvi.lParam)->bIsOpServName ? BST_CHECKED : BST_UNCHECKED);

					if (((ListData*)tvi.lParam)->ptszOPQValue)
						SetDlgItemText(hdlg, IDC_RCLICKVALUE, ((ListData*)tvi.lParam)->ptszOPQValue);
					else
						SetDlgItemText(hdlg, IDC_RCLICKVALUE, _T(""));
				}
				break;
			}
			break;
		}
		break;

	case WM_COMMAND:
		switch (LOWORD(wparam)) {
		case IDC_VARHELP:
			if (!g_varhelpDlg)
				g_varhelpDlg = CreateDialog(hinstance, MAKEINTRESOURCE(IDD_HELPDIALOG), 0, HelpDlgProc);
			else
				//ShowWindow(g_varhelpDlg,SW_SHOWDEFAULT);
				SetWindowPos(g_varhelpDlg, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
			break;
		case IDC_BLISTADD:
			{
				TVINSERTSTRUCT tvis;
				ListData* ld = NULL;
				TCHAR namebuff[MAX_PATH] = { '\0' };
				int count = TreeView_GetCount(hButtonsList);
				if (count > 10) break;
				if (g_iOPButtonsCount == 99) {
					MessageBox(NULL, TranslateT("Congratulation!\r\nYou have clicked this button 100 times!\r\nThere was access violation at this point...\r\nAnd now function for freeing resources must be called...\r\nBut no! there's only break :D"), TranslateT("You win!"), MB_OK);
					break;
				}

				ld = (ListData *)mir_alloc(sizeof(ListData));
				ButtonsList[g_iOPButtonsCount++] = ld;

				ld->sl = List_Create(0, 1);
				ld->dwOPFlags = QMF_NEW;
				ld->bIsOpServName = 0;
				ld->ptszButtonName = NULL;
				ld->ptszOPQValue = NULL;
				ld->ptszQValue = NULL;
				tvis.hParent = NULL;
				tvis.hInsertAfter = TVI_LAST;

				GetDlgItemText(hdlg, IDC_BUTTONNAME, namebuff, _countof(namebuff));

				tvis.item.mask = TVIF_PARAM | TVIF_TEXT;
				tvis.item.pszText = (mir_tstrlen(namebuff)) ? namebuff : TranslateT("New Button");
				tvis.item.lParam = (LPARAM)ld;
				TreeView_SelectItem(hButtonsList, TreeView_InsertItem(hButtonsList, &tvis));
			}break;

		case IDC_BLISTREMOVE:
			{
				TVITEM tvi;
				ListData* ld;

				if (!(tvi.hItem = TreeView_GetSelection(hButtonsList)))
					break;

				tvi.mask = TVIF_HANDLE | TVIF_PARAM;
				TreeView_GetItem(hButtonsList, &tvi);

				ld = (ListData*)tvi.lParam;

				ld->dwOPFlags |= QMF_DELETNEEDED;

				TreeView_DeleteItem(hButtonsList, tvi.hItem);
				if (!TreeView_GetCount(hButtonsList)) {
					TreeView_DeleteAllItems(hMenuTree);
					EnableWindow(GetDlgItem(hdlg, IDC_MENUVALUE), FALSE);
					EnableWindow(GetDlgItem(hdlg, IDC_RCLICKVALUE), FALSE);
					EnableWindow(GetDlgItem(hdlg, IDC_ISSERVNAME), FALSE);
					EnableWindow(GetDlgItem(hdlg, IDC_INQMENU), FALSE);
					EnableWindow(GetDlgItem(hdlg, IDC_ISSERVNAME2), FALSE);
					SetDlgItemText(hdlg, IDC_MENUVALUE, _T(""));
					SetDlgItemText(hdlg, IDC_RCLICKVALUE, _T(""));
				}
			}break;

		case IDC_MTREEADD:
			{
				TVINSERTSTRUCT tvis;
				TVITEM tvi;
				ButtonData *bd = NULL;
				SortedList *sl = NULL;
				TCHAR namebuff[MAX_PATH] = { '\0' };

				if (!TreeView_GetCount(hButtonsList)) break;
				if (!(tvi.hItem = TreeView_GetSelection(hButtonsList))) break;

				bd = (ButtonData *)mir_alloc(sizeof(ButtonData));
				memset(bd, 0, sizeof(ButtonData));

				GetDlgItemText(hdlg, IDC_MENUNAME, namebuff, _countof(namebuff));

				bd->dwOPPos = TreeView_GetCount(hMenuTree) - 1;
				bd->pszOpName = mir_tstrlen(namebuff) ? mir_tstrdup(namebuff) : mir_tstrdup(TranslateT("New Menu Entry"));
				bd->pszOpValue = mir_tstrdup(bd->pszOpName);
				bd->fEntryOpType = !mir_tstrcmp(namebuff, _T("---")) ? QMF_EX_SEPARATOR : 0;
				bd->dwOPFlags = QMF_NEW;
				bd->pszName = NULL;
				bd->pszValue = NULL;


				tvi.mask = TVIF_HANDLE | TVIF_PARAM;

				TreeView_GetItem(hButtonsList, &tvi);

				sl = ((ListData*)tvi.lParam)->sl;

				List_InsertPtr(sl, bd);

				tvis.hParent = NULL;
				tvis.hInsertAfter = TVI_LAST;
				tvis.item.mask = TVIF_PARAM | TVIF_TEXT;
				tvis.item.pszText = bd->pszOpName;
				tvis.item.lParam = (LPARAM)bd;
				TreeView_SelectItem(hMenuTree, TreeView_InsertItem(hMenuTree, &tvis));
			}break;

		case IDC_MTREEREMOVE:
			{
				TVITEM tvi;
				TVINSERTSTRUCT tvis;
				HTREEITEM hti = NULL;
				ButtonData *bd = NULL;
				tvi.mask = TVIF_HANDLE | TVIF_PARAM;
				if (!(tvi.hItem = TreeView_GetSelection(hMenuTree)))
					break;
				TreeView_GetItem(hMenuTree, &tvi);
				hti = tvi.hItem;

				bd = (ButtonData*)tvi.lParam;
				bd->dwOPFlags |= QMF_DELETNEEDED;

				if (tvi.hItem = TreeView_GetChild(hMenuTree, tvi.hItem)) {
					TCHAR strbuf[128];
					while (tvi.hItem) {
						tvis.hInsertAfter = hti;
						tvi.pszText = strbuf;
						tvi.cchTextMax = _countof(strbuf);
						tvi.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_TEXT;

						TreeView_GetItem(hMenuTree, &tvi);
						tvis.hParent = NULL;
						tvis.item = tvi;
						TreeView_InsertItem(hMenuTree, &tvis);
						tvi.hItem = TreeView_GetNextSibling(hMenuTree, tvi.hItem);
					}
				}

				TreeView_DeleteItem(hMenuTree, hti);
				if (!TreeView_GetCount(hMenuTree)) {
					EnableWindow(GetDlgItem(hdlg, IDC_MENUVALUE), FALSE);
					EnableWindow(GetDlgItem(hdlg, IDC_ISSERVNAME), FALSE);
					EnableWindow(GetDlgItem(hdlg, IDC_INQMENU), FALSE);
					SetDlgItemText(hdlg, IDC_MENUVALUE, _T(""));
				}
			}break;
		}
		break;

	case WM_CLOSE:
		EndDialog(hdlg, 0);
		return 0;
	}

	if (HIWORD(wparam) == BN_CLICKED && GetFocus() == (HWND)lparam)
		SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
	else if ((HIWORD(wparam) == EN_CHANGE) && (GetFocus() == (HWND)lparam))
		if (!bOptionsInit)	SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);

	return 0;
}

int OptionsInit(WPARAM wparam, LPARAM)
{
	OPTIONSDIALOGPAGE odp = { 0 };
	odp.position = 940000000;
	odp.hInstance = hinstance;
	odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS);
	odp.pszTitle = LPGEN("Quick Messages");
	odp.pfnDlgProc = OptionsProc;
	odp.pszGroup = LPGEN("Message sessions");
	odp.flags = ODPF_BOLDGROUPS;
	Options_AddPage(wparam, &odp);
	return 0;
}