#include "stdafx.h"

static MWindowList hPopupsList = nullptr;

static uint8_t OnePopup;
static uint8_t StartDisabled;
static uint8_t StopDisabled;
static uint8_t ColorMode;
static uint8_t TimeoutMode;
static uint8_t TimeoutMode2;
static int     Timeout;
static int     Timeout2;

static HANDLE hntfStarted = nullptr;
static HANDLE hntfStopped = nullptr;

struct
{
	int res;
	char desc[10];
	COLORREF color;
}
static colorPicker[4] =
{
	{ IDC_TYPEON_BG, "ON_BG", RGB(255, 255, 255) },
	{ IDC_TYPEON_TX, "ON_TX", RGB(0, 0, 0) },
	{ IDC_TYPEOFF_BG, "OFF_BG", RGB(255, 255, 255) },
	{ IDC_TYPEOFF_TX, "OFF_TX", RGB(0, 0, 0) }
};

static LRESULT CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message) {
	case WM_COMMAND:
		if (HIWORD(wParam) == STN_CLICKED) {
			CallService(MS_MSG_SENDMESSAGEW, (WPARAM)PUGetContact(hWnd), 0);
			PUDeletePopup(hWnd);
			return 1;
		}
		break;

	case WM_CONTEXTMENU:
		PUDeletePopup(hWnd);
		return 1;

	case UM_INITPOPUP:
		WindowList_Add(hPopupsList, hWnd, PUGetContact(hWnd));
		return 1;

	case UM_FREEPLUGINDATA:
		WindowList_Remove(hPopupsList, hWnd);
		return 1;
	}
	return DefWindowProc(hWnd, message, wParam, lParam);
}

void TN_TypingMessage(MCONTACT hContact, int iMode)
{
	// hidden & ignored contacts check
	if (Contact::IsHidden(hContact) || (db_get_dw(hContact, "Ignore", "Mask1", 0) & 1)) // 9 - online notification
		return;

	if (!Contact::OnList(hContact) && !g_plugin.bTypingUnknown)
		return;

	if (!g_plugin.bPopups)
		return;

	wchar_t *szContactName = Clist_GetContactDisplayName(hContact);

	if (OnePopup) {
		HWND hPopupWnd = WindowList_Find(hPopupsList, hContact);
		while (hPopupWnd) {
			PUDeletePopup(hPopupWnd);
			WindowList_Remove(hPopupsList, hPopupWnd);
			hPopupWnd = WindowList_Find(hPopupsList, hContact);
		}
	}

	int notyping;
	POPUPDATAW ppd;

	if (iMode == PROTOTYPE_CONTACTTYPING_OFF) {
		if (StopDisabled)
			return;
		wcsncpy_s(ppd.lpwzContactName, szContactName, _TRUNCATE);
		wcsncpy_s(ppd.lpwzText, TranslateT("...has stopped typing."), _TRUNCATE);
		ppd.hNotification = hntfStopped;
		notyping = 1;
	}
	else {
		if (StartDisabled)
			return;
		wcsncpy_s(ppd.lpwzContactName, szContactName, _TRUNCATE);
		wcsncpy_s(ppd.lpwzText, TranslateT("...is typing a message."), _TRUNCATE);
		ppd.hNotification = hntfStarted;
		notyping = 0;
	}

	switch (ColorMode) {
	case COLOR_OWN:
		ppd.colorBack = colorPicker[2 * notyping].color;
		ppd.colorText = colorPicker[2 * notyping + 1].color;
		break;
	case COLOR_WINDOWS:
		ppd.colorBack = GetSysColor(COLOR_BTNFACE);
		ppd.colorText = GetSysColor(COLOR_WINDOWTEXT);
		break;
	case COLOR_POPUP:
	default:
		ppd.colorBack = ppd.colorText = 0;
		break;
	}

	if (notyping)
		switch (TimeoutMode2) {
		case TIMEOUT_CUSTOM:
			ppd.iSeconds = Timeout2;
			break;
		case TIMEOUT_PERMANENT:
			ppd.iSeconds = -1;
			break;
		case TIMEOUT_POPUP:
		default:
			ppd.iSeconds = 0;
			break;
	}
	else
		switch (TimeoutMode) {
		case TIMEOUT_CUSTOM:
			ppd.iSeconds = Timeout;
			break;
		case TIMEOUT_PROTO:
			ppd.iSeconds = iMode;
			break;
		case TIMEOUT_PERMANENT:
			ppd.iSeconds = -1;
			break;
		case TIMEOUT_POPUP:
		default:
			ppd.iSeconds = 0;
			break;
	}

	ppd.lchIcon = PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING];
	ppd.lchContact = hContact;
	ppd.PluginWindowProc = PopupDlgProc;
	PUAddPopupW(&ppd);
}

class CTypingOpts : public CDlgBase
{
	CCtrlEdit value1, value2;
	CCtrlCheck chkWinColors, chkPopupColors;
	CCtrlCheck chkPopup, chkCustom, chkPermanent, chkProto;
	CCtrlCheck chkPopup2, chkCustom2, chkPermanent2;
	CCtrlButton btnPreview;

public:
	CTypingOpts() :
		CDlgBase(g_plugin, IDD_OPT_TYPINGNOTIFYPOPUP),
		btnPreview(this, IDC_PREVIEW),
		value1(this, IDC_TIMEOUT_VALUE),
		value2(this, IDC_TIMEOUT_VALUE2),
		chkProto(this, IDC_TIMEOUT_PROTO),
		chkPopup(this, IDC_TIMEOUT_POPUP),
		chkPopup2(this, IDC_TIMEOUT_POPUP2),
		chkCustom(this, IDC_TIMEOUT_CUSTOM),
		chkCustom2(this, IDC_TIMEOUT_CUSTOM2),
		chkPermanent(this, IDC_TIMEOUT_PERMANENT),
		chkPermanent2(this, IDC_TIMEOUT_PERMANENT2),
		chkWinColors(this, IDC_USEWINCOLORS),
		chkPopupColors(this, IDC_USEPOPUPCOLORS)
	{
		btnPreview.OnClick = Callback(this, &CTypingOpts::onClick_Preview);

		chkWinColors.OnChange = Callback(this, &CTypingOpts::onChange_UseWinColors);
		chkPopupColors.OnChange = Callback(this, &CTypingOpts::onChange_UsePopupColors);
	}

	bool OnInitDialog() override
	{
		bool bWindows = (ColorMode == COLOR_WINDOWS);
		chkWinColors.SetState(bWindows);
		chkWinColors.Enable(bWindows);
		chkPopupColors.SetState(!bWindows);
		chkPopupColors.Enable(!bWindows);

		for (auto &it : colorPicker) {
			SendDlgItemMessage(m_hwnd, it.res, CPM_SETCOLOUR, 0, it.color);
			Utils::enableDlgControl(m_hwnd, it.res, (ColorMode == COLOR_OWN));
		}

		switch (TimeoutMode) {
		case TIMEOUT_POPUP: chkPopup.SetState(true); break;
		case TIMEOUT_PROTO: chkProto.SetState(true); break;
		case TIMEOUT_CUSTOM: chkCustom.SetState(true); break;
		case TIMEOUT_PERMANENT: chkPermanent.SetState(true); break;
		}
		value1.SetInt(Timeout);

		switch (TimeoutMode2) {
		case TIMEOUT_POPUP: chkPopup2.SetState(true); break;
		case TIMEOUT_CUSTOM: chkCustom2.SetState(true); break;
		case TIMEOUT_PERMANENT: chkPermanent2.SetState(true); break;
		}
		value2.SetInt(Timeout2);

		CheckDlgButton(m_hwnd, IDC_START, (StartDisabled) ? BST_UNCHECKED : BST_CHECKED);
		CheckDlgButton(m_hwnd, IDC_STOP, (StopDisabled) ? BST_UNCHECKED : BST_CHECKED);
		CheckDlgButton(m_hwnd, IDC_ONEPOPUP, (OnePopup) ? BST_CHECKED : BST_UNCHECKED);
		return true;
	}

	void OnChange() override
	{
		value1.Enable(chkCustom.IsChecked());
		value2.Enable(chkCustom2.IsChecked());
	}

	bool OnApply() override
	{
		for (int i = 0; i < sizeof(colorPicker) / sizeof(colorPicker[0]); i++) {
			colorPicker[i].color = SendDlgItemMessage(m_hwnd, colorPicker[i].res, CPM_GETCOLOUR, 0, 0);
			db_set_dw(0, TypingModule, colorPicker[i].desc, colorPicker[i].color);
		}

		if (chkCustom.IsChecked())
			TimeoutMode = TIMEOUT_CUSTOM;
		else if (chkPermanent.IsChecked())
			TimeoutMode = TIMEOUT_PERMANENT;
		else if (chkProto.IsChecked())
			TimeoutMode = TIMEOUT_PROTO;
		else
			TimeoutMode = TIMEOUT_POPUP;
		Timeout = value1.GetInt();

		if (chkCustom2.IsChecked())
			TimeoutMode2 = TIMEOUT_CUSTOM;
		else if (chkPermanent2.IsChecked())
			TimeoutMode2 = TIMEOUT_PERMANENT;
		else
			TimeoutMode2 = TIMEOUT_POPUP;
		Timeout2 = value2.GetInt(); 

		if (chkWinColors.IsChecked())
			ColorMode = COLOR_WINDOWS;
		else if (chkPopupColors.IsChecked())
			ColorMode = COLOR_POPUP;
		else
			ColorMode = COLOR_OWN;

		StartDisabled = IsDlgButtonChecked(m_hwnd, IDC_START) ? 0 : 2;
		StopDisabled = IsDlgButtonChecked(m_hwnd, IDC_STOP) ? 0 : 4;
		OnePopup = IsDlgButtonChecked(m_hwnd, IDC_ONEPOPUP);

		db_set_b(0, TypingModule, SET_ONEPOPUP, OnePopup);
		db_set_b(0, TypingModule, SET_DISABLED, (uint8_t)(StartDisabled | StopDisabled));
		db_set_b(0, TypingModule, SET_COLOR_MODE, ColorMode);
		db_set_b(0, TypingModule, SET_TIMEOUT_MODE, TimeoutMode);
		db_set_b(0, TypingModule, SET_TIMEOUT, (uint8_t)Timeout);
		db_set_b(0, TypingModule, SET_TIMEOUT_MODE2, TimeoutMode2);
		db_set_b(0, TypingModule, SET_TIMEOUT2, (uint8_t)Timeout2);
		return true;
	}

	void onChange_UseWinColors(CCtrlCheck *pCheck)
	{
		bool bEnableOthers = !pCheck->IsChecked();

		for (auto &it : colorPicker)
			Utils::enableDlgControl(m_hwnd, it.res, bEnableOthers);

		chkPopupColors.Enable(bEnableOthers);
	}

	void onChange_UsePopupColors(CCtrlCheck *pCheck)
	{
		bool bEnableOthers = !pCheck->IsChecked();

		for (int i = 0; i < sizeof(colorPicker) / sizeof(colorPicker[0]); i++)
			Utils::enableDlgControl(m_hwnd, colorPicker[i].res, bEnableOthers);

		chkWinColors.Enable(bEnableOthers);
	}

	void onClick_Preview(CCtrlButton *)
	{
		for (int i = 0; i < 2; i++) {
			POPUPDATAW ppd;
			int notyping;
			if (i == PROTOTYPE_CONTACTTYPING_OFF) {
				wcsncpy_s(ppd.lpwzContactName, TranslateT("Contact"), _TRUNCATE);
				wcsncpy_s(ppd.lpwzText, TranslateT("...has stopped typing."), _TRUNCATE);
				notyping = 1;
			}
			else {
				wcsncpy_s(ppd.lpwzContactName, TranslateT("Contact"), _TRUNCATE);
				wcsncpy_s(ppd.lpwzText, TranslateT("...is typing a message."), _TRUNCATE);
				notyping = 0;
			}

			if (chkWinColors.IsChecked()) {
				ppd.colorBack = GetSysColor(COLOR_BTNFACE);
				ppd.colorText = GetSysColor(COLOR_WINDOWTEXT);
			}
			else if (chkPopupColors.IsChecked()) {
				ppd.colorBack = ppd.colorText = 0;
			}
			else {
				ppd.colorText = SendDlgItemMessage(m_hwnd, colorPicker[2 * notyping + 1].res, CPM_GETCOLOUR, 0, 0);
				ppd.colorBack = SendDlgItemMessage(m_hwnd, colorPicker[2 * notyping].res, CPM_GETCOLOUR, 0, 0);
			}

			if (notyping) {
				if (chkCustom2.IsChecked())
					ppd.iSeconds = value2.GetInt();
				else if (chkPermanent2.IsChecked())
					ppd.iSeconds = -1;
				else
					ppd.iSeconds = 0;
			}
			else {
				if (chkCustom.IsChecked())
					ppd.iSeconds = value1.GetInt();
				else if (chkPermanent.IsChecked())
					ppd.iSeconds = -1;
				else if (chkProto.IsChecked())
					ppd.iSeconds = 10;
				else
					ppd.iSeconds = 0;
			}
			ppd.lchIcon = PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING];
			ppd.lchContact = 0;
			ppd.PluginWindowProc = nullptr;
			ppd.PluginData = nullptr;
			PUAddPopupW(&ppd);
		}
	}
};

int TN_OptionsInitialize(WPARAM wParam, LPARAM)
{
	OPTIONSDIALOGPAGE odp = {};
	odp.flags = ODPF_BOLDGROUPS;
	odp.position = 100000000;
	odp.szTitle.a = LPGEN("Typing notify");
	odp.szGroup.a = LPGEN("Popups");
	odp.pDialog = new CTypingOpts();
	g_plugin.addOptions(wParam, &odp);
	return 0;
}

int TN_ModuleInit()
{
	hPopupsList = WindowList_Create();

	OnePopup = db_get_b(0, TypingModule, SET_ONEPOPUP, DEF_ONEPOPUP);

	int i = db_get_b(0, TypingModule, SET_DISABLED, DEF_DISABLED);
	if (i & 1)
		g_plugin.bPopups = false;
	StartDisabled = i & 2;
	StopDisabled = i & 4;

	ColorMode = db_get_b(0, TypingModule, SET_COLOR_MODE, DEF_COLOR_MODE);
	TimeoutMode = db_get_b(0, TypingModule, SET_TIMEOUT_MODE, DEF_TIMEOUT_MODE);
	Timeout = db_get_b(0, TypingModule, SET_TIMEOUT, DEF_TIMEOUT);
	TimeoutMode2 = db_get_b(0, TypingModule, SET_TIMEOUT_MODE2, DEF_TIMEOUT_MODE2);
	Timeout2 = db_get_b(0, TypingModule, SET_TIMEOUT2, DEF_TIMEOUT2);

	if (!(db_get_dw(0, TypingModule, colorPicker[0].desc, 1) && !db_get_dw(0, TypingModule, colorPicker[0].desc, 0)))
		for (auto &it : colorPicker)
			it.color = db_get_dw(0, TypingModule, it.desc, 0);

	g_plugin.addPopupOption(LPGEN("Typing notifications"), g_plugin.bPopups);

	g_plugin.addSound("TNStart", LPGENW("Instant messages"), LPGENW("Contact started typing"));
	g_plugin.addSound("TNStop", LPGENW("Instant messages"), LPGENW("Contact stopped typing"));
	return 0;
}

int TN_ModuleDeInit()
{
	WindowList_Destroy(hPopupsList);
	db_set_b(0, TypingModule, SET_DISABLED, (uint8_t)(StartDisabled | StopDisabled));
	return 0;
}