/*
Plugin of miranda IM(ICQ) for Communicating with users of the baseProtocol.
Copyright (C) 2004 Daniel Savi (dss@brturbo.com)

-> Based on J. Lawler BaseProtocol <-

Added:
 - plugin option window
 - make.bat (vc++)
 - tinyclib http://msdn.microsoft.com/msdnmag/issues/01/01/hood/default.aspx
 - C++ version

Miranda ICQ: the free icq client for MS Windows
Copyright (C) 2000-2  Richard Hughes, Roland Rabien & Tristan Van de Vreede
*/

#include "stdafx.h"

CLIST_INTERFACE *pcli;
HINSTANCE hinstance;

HGENMENU hToggle, hEnableMenu;
BOOL gbVarsServiceExist = FALSE;
INT interval;
int hLangpack;

wchar_t* ptszDefaultMsg[] = {
	LPGENW("I am currently away. I will reply to you when I am back."),
	LPGENW("I am currently very busy and can't spare any time to talk with you. Sorry..."),
	LPGENW("I am not available right now."),
	LPGENW("I am now doing something, I will talk to you later."),
	LPGENW("I am on the phone right now. I will get back to you very soon."),
	LPGENW("I am having meal right now. I will get back to you very soon.")
};

PLUGININFOEX pluginInfoEx = {
	sizeof(PLUGININFOEX),
	__PLUGIN_NAME,
	PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
	__DESCRIPTION,
	__AUTHOR,
	__AUTHOREMAIL,
	__COPYRIGHT,
	__AUTHORWEB,
	UNICODE_AWARE,
	// {46BF191F-8DFB-4656-88B2-4C20BE4CFA44}
	{ 0x46bf191f, 0x8dfb, 0x4656, { 0x88, 0xb2, 0x4c, 0x20, 0xbe, 0x4c, 0xfa, 0x44 } }
};

extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD)
{
	return &pluginInfoEx;
}

BOOL WINAPI DllMain(HINSTANCE hinst, DWORD, LPVOID)
{
	hinstance = hinst;
	return TRUE;
}

INT_PTR ToggleEnable(WPARAM, LPARAM)
{
	BOOL fEnabled = !db_get_b(NULL, protocolname, KEY_ENABLED, 1);
	db_set_b(NULL, protocolname, KEY_ENABLED, fEnabled);

	if (fEnabled)
		Menu_ModifyItem(hEnableMenu, LPGENW("Disable Auto&reply"), iconList[0].hIcolib);
	else
		Menu_ModifyItem(hEnableMenu, LPGENW("Enable Auto&reply"), iconList[1].hIcolib);
	return 0;
}

INT_PTR Toggle(WPARAM hContact, LPARAM)
{
	BOOL on = !db_get_b(hContact, protocolname, "TurnedOn", 0);
	db_set_b(hContact, protocolname, "TurnedOn", on);
	on = !on;

	if (on)
		Menu_ModifyItem(hToggle, LPGENW("Turn off Autoanswer"), iconList[0].hIcolib);
	else
		Menu_ModifyItem(hToggle, LPGENW("Turn on Autoanswer"), iconList[1].hIcolib);
	return 0;
}

INT OnPreBuildContactMenu(WPARAM hContact, LPARAM)
{
	BOOL on = !db_get_b(hContact, protocolname, "TurnedOn", 0);
	if (on)
		Menu_ModifyItem(hToggle, LPGENW("Turn off Autoanswer"), iconList[0].hIcolib);
	else
		Menu_ModifyItem(hToggle, LPGENW("Turn on Autoanswer"), iconList[1].hIcolib);
	return 0;
}

INT CheckDefaults(WPARAM, LPARAM)
{
	interval = db_get_w(NULL, protocolname, KEY_REPEATINTERVAL, 300);

	wchar_t *ptszVal = db_get_wsa(NULL, protocolname, KEY_HEADING);
	if (ptszVal == 0)
		// Heading not set
		db_set_ws(NULL, protocolname, KEY_HEADING, TranslateT("Dear %user%, the owner left the following message:"));
	else
		mir_free(ptszVal);

	for (int c = ID_STATUS_ONLINE; c < ID_STATUS_IDLE; c++) {
		if (c == ID_STATUS_ONLINE || c == ID_STATUS_FREECHAT || c == ID_STATUS_INVISIBLE)
			continue;
		else {
			char szStatus[6] = { 0 };
			mir_snprintf(szStatus, "%d", c);
			ptszVal = db_get_wsa(NULL, protocolname, szStatus);
			if (ptszVal == 0) {
				wchar_t *ptszDefault;
				if (c < ID_STATUS_FREECHAT)
					// This mode does not have a preset message
					ptszDefault = ptszDefaultMsg[c - ID_STATUS_ONLINE - 1];
				else if (c > ID_STATUS_INVISIBLE)
					ptszDefault = ptszDefaultMsg[c - ID_STATUS_ONLINE - 3];
				else
					ptszDefault = 0;
				if (ptszDefault)
					db_set_ws(NULL, protocolname, szStatus, TranslateW(ptszDefault));
			}
			else
				mir_free(ptszVal);
		}
	}
	HookEvent(ME_CLIST_PREBUILDCONTACTMENU, OnPreBuildContactMenu);
	if (ServiceExists(MS_VARS_FORMATSTRING))
		gbVarsServiceExist = TRUE;

	BOOL fEnabled = db_get_b(NULL, protocolname, KEY_ENABLED, 1);
	if (fEnabled)
		Menu_ModifyItem(hEnableMenu, LPGENW("Disable Auto&reply"), iconList[0].hIcolib);
	else
		Menu_ModifyItem(hEnableMenu, LPGENW("Enable Auto&reply"), iconList[1].hIcolib);
	return 0;
}

INT addEvent(WPARAM hContact, LPARAM hDBEvent)
{
	BOOL fEnabled = db_get_b(NULL, protocolname, KEY_ENABLED, 1);
	if (!fEnabled || !hContact || !hDBEvent)
		return FALSE;	/// unspecifyed error

	char* pszProto = GetContactProto(hContact);
	int status = CallProtoService(pszProto, PS_GETSTATUS, 0, 0);
	if (status == ID_STATUS_ONLINE || status == ID_STATUS_FREECHAT || status == ID_STATUS_INVISIBLE)
		return FALSE;

	// detect size of msg
	DBEVENTINFO dbei = {};
	if (db_event_get(hDBEvent, &dbei))
		return 0;

	if ((dbei.eventType != EVENTTYPE_MESSAGE) || (dbei.flags == DBEF_READ)) {
		// we need EVENTTYPE_MESSAGE event..
		return FALSE;
	}
	else {
		// needed event has occured..
		if (!dbei.cbBlob)	/// invalid size
			return FALSE;

		wchar_t *ptszVal = db_get_wsa(hContact, "Protocol", "p");
		if (ptszVal == NULL) // Contact with no protocol ?!!
			return FALSE;
		mir_free(ptszVal);

		if (db_get_b(hContact, "CList", "NotOnList", 0))
			return FALSE;

		if (db_get_b(hContact, protocolname, "TurnedOn", 0))
			return FALSE;

		if (!(dbei.flags & DBEF_SENT)) {
			int timeBetween = time(NULL) - db_get_dw(hContact, protocolname, "LastReplyTS", 0);
			if (timeBetween > interval || db_get_w(hContact, protocolname, "LastStatus", 0) != status) {
				size_t msgLen = 1;
				int isQun = db_get_b(hContact, pszProto, "IsQun", 0);
				if (isQun)
					return FALSE;

				char szStatus[6] = { 0 };
				mir_snprintf(szStatus, "%d", status);
				ptszVal = db_get_wsa(NULL, protocolname, szStatus);
				if (ptszVal) {
					if (*ptszVal) {
						CMStringW ptszTemp;

						wchar_t *ptszNick = db_get_wsa(hContact, pszProto, "Nick");
						if (ptszNick == 0) {
							mir_free(ptszVal);
							return FALSE;
						}

						msgLen += mir_wstrlen(ptszVal);

						wchar_t *ptszHead = db_get_wsa(NULL, protocolname, KEY_HEADING);
						if (ptszHead != NULL) {
							ptszTemp = ptszHead;
							ptszTemp.Replace(L"%user%", ptszNick);
							msgLen += mir_wstrlen(ptszTemp);
							mir_free(ptszHead);
						}

						wchar_t *ptszTemp2 = (wchar_t*)mir_alloc(sizeof(wchar_t) * (msgLen + 5));
						mir_snwprintf(ptszTemp2, msgLen + 5, L"%s\r\n\r\n%s", ptszTemp.c_str(), ptszVal);
						if (ServiceExists(MS_VARS_FORMATSTRING)) {
							ptszTemp = variables_parse(ptszTemp2, 0, hContact);
						}
						else ptszTemp = Utils_ReplaceVarsW(ptszTemp2);

						T2Utf pszUtf(ptszTemp);
						ProtoChainSend(hContact, PSS_MESSAGE, 0, pszUtf);

						dbei.eventType = EVENTTYPE_MESSAGE;
						dbei.flags = DBEF_UTF | DBEF_SENT; //DBEF_READ;
						dbei.szModule = pszProto;
						dbei.timestamp = time(NULL);
						dbei.cbBlob = (int)mir_strlen(pszUtf) + 1;
						dbei.pBlob = (PBYTE)pszUtf;
						db_event_add(hContact, &dbei);

						mir_free(ptszTemp2);
						mir_free(ptszNick);
					}
					mir_free(ptszVal);
				}
			}
		}

		db_set_dw(hContact, protocolname, "LastReplyTS", time(NULL));
		db_set_w(hContact, protocolname, "LastStatus", status);
	}
	return 0;
}

IconItemT iconList[] =
{
	{ LPGENW("Disable Auto&reply"), "Disable Auto&reply", IDI_OFF },
	{ LPGENW("Enable Auto&reply"), "Enable Auto&reply", IDI_ON }
};

extern "C" int __declspec(dllexport)Load(void)
{
	mir_getLP(&pluginInfoEx);
	pcli = Clist_GetInterface();

	CreateServiceFunction(protocolname"/ToggleEnable", ToggleEnable);
	CreateServiceFunction(protocolname"/ToggleAutoanswer", Toggle);

	CMenuItem mi;

	SET_UID(mi, 0xac1c64a, 0x82ca, 0x4845, 0x86, 0x89, 0x59, 0x76, 0x12, 0x74, 0x72, 0x7b);
	mi.position = 500090000;
	mi.name.w = L"";
	mi.pszService = protocolname"/ToggleEnable";
	hEnableMenu = Menu_AddMainMenuItem(&mi);

	SET_UID(mi, 0xb290cccd, 0x4ecc, 0x475e, 0x87, 0xcb, 0x51, 0xf4, 0x3b, 0xc3, 0x44, 0x9c);
	mi.position = -0x7FFFFFFF;
	mi.name.w = L"";
	mi.pszService = protocolname"/ToggleAutoanswer";
	hToggle = Menu_AddContactMenuItem(&mi);

	//add hook
	HookEvent(ME_OPT_INITIALISE, OptInit);
	HookEvent(ME_DB_EVENT_ADDED, addEvent);
	HookEvent(ME_SYSTEM_MODULESLOADED, CheckDefaults);

	Icon_RegisterT(hinstance, L"Simple Auto Replier", iconList, _countof(iconList));

	return 0;
}

extern "C" __declspec(dllexport)int Unload(void)
{
	return 0;
}