/*
 * Contactlist management functions
 */

#include "skype.h"
#include "skypeapi.h"
#include "debug.h"
#include "pthread.h"
#include "gchat.h"

#include <m_langpack.h>

// Imported Globals
extern HINSTANCE hInst;
extern BOOL bSkypeOut, bIsImoproxy;
extern char protocol, g_szProtoName[];

// Handles
static HGENMENU hMenuCallItem, hMenuCallHangup, hMenuSkypeOutCallItem, hMenuHoldCallItem, hMenuFileTransferItem, hMenuChatInitItem, hMenuBlockContactItem;

// Check if alpha blending icons are supported
// Seems to be not neccessary
/*
BOOL SupportAlphaIcons(void) {
HANDLE hMod;
DLLVERSIONINFO tDVI={0};
BOOL retval=FALSE;
FARPROC pDllGetVersion;

if (!(hMod=LoadLibrary("comctl32.dll"))) return FALSE;
if (pDllGetVersion=GetProcAddress(hMod, "DllGetVersion")) {
tDVI.cbSize=sizeof(tDVI);
if (!pDllGetVersion ((DLLVERSIONINFO *)&tDVI)) {
if (GetDeviceCaps(GetDC(NULL), BITSPIXEL)*GetDeviceCaps(GetDC(NULL), PLANES)>=32 &&
tDVI.dwMajorVersion>=6)
retval=TRUE;
}
}
FreeLibrary(hMod);
return retval;
}
*/

CLISTMENUITEM CallItem(void) {
	CLISTMENUITEM mi = { 0 };

	mi.cbSize = sizeof(mi);
	mi.position = -2000005000;
	mi.flags = CMIF_NOTOFFLINE | CMIF_TCHAR;
	mi.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_CALL));
	mi.pszContactOwner = SKYPE_PROTONAME;
	mi.ptszName = LPGENT("Call (Skype)");
	mi.pszService = SKYPE_CALL;

	return mi;
}

CLISTMENUITEM SkypeOutCallItem(void) {
	CLISTMENUITEM mi = { 0 };

	mi.cbSize = sizeof(mi);
	mi.position = -2000005000;
	mi.flags = CMIF_HIDDEN | CMIF_TCHAR;
	mi.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_CALLSKYPEOUT));
	mi.ptszName = LPGENT("Call using SkypeOut");
	mi.pszService = SKYPEOUT_CALL;

	return mi;
}

CLISTMENUITEM HupItem(void) {
	CLISTMENUITEM mi = { 0 };

	mi.cbSize = sizeof(mi);
	mi.position = -2000005000;
	mi.flags = CMIF_NOTOFFLINE | CMIF_TCHAR;
	mi.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_HANGUP));
	mi.pszContactOwner = SKYPE_PROTONAME;
	mi.ptszName = LPGENT("Hang up call (Skype)");
	mi.pszService = SKYPE_CALLHANGUP;

	return mi;
}

CLISTMENUITEM SkypeOutHupItem(void) {
	CLISTMENUITEM mi = { 0 };

	mi.cbSize = sizeof(mi);
	mi.position = -2000005000;
	mi.flags = CMIF_TCHAR;
	mi.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_HANGUP));
	mi.ptszName = LPGENT("Hang up SkypeOut call");
	mi.pszService = SKYPEOUT_CALL;
	return mi;
}

CLISTMENUITEM HoldCallItem(void) {
	CLISTMENUITEM mi = { 0 };

	mi.cbSize = sizeof(mi);
	mi.position = -2000005000;
	mi.flags = CMIF_HIDDEN | CMIF_NOTOFFLINE | CMIF_TCHAR;
	mi.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_HOLD));
	mi.ptszName = LPGENT("Hold call");
	mi.pszService = SKYPE_HOLDCALL;
	return mi;
}

CLISTMENUITEM ResumeCallItem(void) {
	CLISTMENUITEM mi = { 0 };

	mi.cbSize = sizeof(mi);
	mi.position = -2000005000;
	mi.flags = CMIF_HIDDEN | CMIF_NOTOFFLINE | CMIF_TCHAR;
	mi.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_RESUME));
	mi.ptszName = LPGENT("Resume call");
	mi.pszService = SKYPE_HOLDCALL;
	return mi;
}

CLISTMENUITEM FileTransferItem(void) {
	CLISTMENUITEM mi = { 0 };

	// Stolen from file.c of Miranda core
	mi.cbSize = sizeof(mi);
	mi.position = -2000020000;
	mi.flags = CMIF_HIDDEN | CMIF_NOTOFFLINE | CMIF_TCHAR;
	mi.hIcon = LoadSkinnedIcon(SKINICON_EVENT_FILE);
	mi.ptszName = LPGENT("&File");
	mi.pszContactOwner = SKYPE_PROTONAME;
	mi.pszService = SKYPE_SENDFILE;
	return mi;
}

CLISTMENUITEM ChatInitItem(void) {
	CLISTMENUITEM mi = { 0 };

	mi.cbSize = sizeof(mi);
	mi.position = -2000020000;
	mi.flags = CMIF_HIDDEN | CMIF_NOTOFFLINE | CMIF_TCHAR;
	mi.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_INVITE));
	mi.ptszName = LPGENT("&Open group chat");
	mi.pszContactOwner = SKYPE_PROTONAME;
	mi.pszService = SKYPE_CHATNEW;
	return mi;
}

CLISTMENUITEM BlockContactItem(void) {
	CLISTMENUITEM mi = { 0 };

	mi.cbSize = sizeof(mi);
	mi.position = -2000005000;
	mi.flags = CMIF_HIDDEN | CMIF_TCHAR;
	mi.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_BLOCKCONTACT));
	mi.ptszName = LPGENT("Block contact");
	mi.pszContactOwner = SKYPE_PROTONAME;
	mi.pszService = SKYPE_BLOCKCONTACT;
	return mi;
}

HANDLE add_contextmenu(MCONTACT) {
	CLISTMENUITEM mi = CallItem();
	hMenuCallItem = Menu_AddContactMenuItem(&mi);

	mi = HupItem();
	hMenuCallHangup = Menu_AddContactMenuItem(&mi);

	mi = SkypeOutCallItem();
	hMenuSkypeOutCallItem = Menu_AddContactMenuItem(&mi);

	mi = HoldCallItem();
	hMenuHoldCallItem = Menu_AddContactMenuItem(&mi);

	// We cannot use flag PF1_FILESEND for sending files, as Skype opens its own
	// sendfile-Dialog.
	mi = FileTransferItem();
	hMenuFileTransferItem = Menu_AddContactMenuItem(&mi);

	mi = ChatInitItem();
	hMenuChatInitItem = Menu_AddContactMenuItem(&mi);

	mi = BlockContactItem();
	hMenuBlockContactItem = Menu_AddContactMenuItem(&mi);

	memset(&mi, 0, sizeof(mi));
	mi.cbSize = sizeof(mi);
	mi.position = -2000005000;
	mi.flags = CMIF_TCHAR;
	mi.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_IMPORT));
	mi.pszContactOwner = SKYPE_PROTONAME;
	mi.ptszName = LPGENT("Import Skype history");
	mi.pszService = SKYPE_IMPORTHISTORY;
	return Menu_AddContactMenuItem(&mi);
}

HANDLE add_mainmenu(void) {
	CLISTMENUITEM mi = { 0 };

	mi.cbSize = sizeof(mi);
	mi.position = -2000005000;
	mi.flags = CMIF_TCHAR;
	mi.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ADD));
	mi.pszContactOwner = SKYPE_PROTONAME;
	mi.ptszName = LPGENT("Add Skype contact");
	mi.pszService = SKYPE_ADDUSER;
	return Menu_AddMainMenuItem(&mi);

}

int __cdecl  PrebuildContactMenu(WPARAM wParam, LPARAM) {
	MCONTACT hContact = (MCONTACT) wParam;
	char *szProto = GetContactProto(hContact);
	if (!szProto)
		return 0;

	// Clear hold-Item in case it exists
	CLISTMENUITEM mi = HoldCallItem();
	mi.flags |= CMIM_ALL;
	Menu_ModifyItem(hMenuHoldCallItem, &mi);

	DBVARIANT dbv;
	BOOL callAvailable = FALSE;
	BOOL hangupAvailable = FALSE;
	if (!strcmp(szProto, SKYPE_PROTONAME)) {
		if (!db_get(hContact, SKYPE_PROTONAME, "CallId", &dbv)) {
			if (db_get_b(hContact, SKYPE_PROTONAME, "OnHold", 0))
				mi = ResumeCallItem(); else mi = HoldCallItem();
			mi.flags = CMIM_ALL;
			Menu_ModifyItem(hMenuHoldCallItem, &mi);

			callAvailable = FALSE;
			hangupAvailable = TRUE;

			db_free(&dbv);
		}
		else { callAvailable = TRUE; hangupAvailable = FALSE; }

		if (db_get_b(hContact, SKYPE_PROTONAME, "ChatRoom", 0) != 0) {
			callAvailable = FALSE;
			hangupAvailable = FALSE;
		}

		mi = CallItem();
		mi.flags |= CMIM_ALL | (!callAvailable ? CMIF_HIDDEN : 0);
		Menu_ModifyItem(hMenuCallItem, &mi);

		mi = HupItem();
		mi.flags |= CMIM_ALL | (!hangupAvailable ? CMIF_HIDDEN : 0);
		Menu_ModifyItem(hMenuCallHangup, &mi);

		// Clear SkypeOut menu in case it exists
		mi = SkypeOutCallItem();
		mi.flags |= CMIM_ALL;
		Menu_ModifyItem(hMenuSkypeOutCallItem, &mi);

		// File sending and groupchat-creation works starting with protocol version 5
		if (protocol >= 5) {
			mi = FileTransferItem();
			if (db_get_b(hContact, SKYPE_PROTONAME, "ChatRoom", 0) == 0)
				mi.flags ^= CMIF_HIDDEN;
			mi.flags |= CMIM_FLAGS;
			Menu_ModifyItem(hMenuFileTransferItem, &mi);
		}

		if (protocol >= 5 || bIsImoproxy) {
			mi = ChatInitItem();
			if (db_get_b(NULL, SKYPE_PROTONAME, "UseGroupchat", 0) &&
				db_get_b(hContact, SKYPE_PROTONAME, "ChatRoom", 0) == 0)
				mi.flags ^= CMIF_HIDDEN;
			mi.flags |= CMIM_FLAGS;
			Menu_ModifyItem(hMenuChatInitItem, &mi);
			mi = BlockContactItem();
			mi.flags ^= CMIF_HIDDEN;
			mi.flags |= CMIM_FLAGS | CMIM_NAME;
			if (db_get_b(hContact, SKYPE_PROTONAME, "IsBlocked", 0) == 1)
				mi.ptszName = LPGENT("Unblock contact");
			Menu_ModifyItem(hMenuBlockContactItem, &mi);
		}

	}
	else if (bSkypeOut) {
		if (!db_get(hContact, SKYPE_PROTONAME, "CallId", &dbv)) {
			mi = SkypeOutHupItem();
			db_free(&dbv);
		}
		else {
			mi = SkypeOutCallItem();
			if (!db_get(hContact, "UserInfo", "MyPhone0", &dbv)) {
				db_free(&dbv);
				mi.flags = 0;
			}
		}
		mi.flags |= CMIM_ALL;
		Menu_ModifyItem(hMenuSkypeOutCallItem, &mi);
	}

	return 0;
}

/*
int ClistDblClick(WPARAM wParam, LPARAM lParam) {
char *szProto;

szProto = (char*)CallService( MS_PROTO_GETCONTACTBASEPROTO, wParam, 0 );
if (szProto!=NULL && !strcmp(szProto, SKYPE_PROTONAME) &&
db_get_w((HANDLE)wParam, SKYPE_PROTONAME, "Status", ID_STATUS_OFFLINE)==ID_STATUS_ONTHEPHONE) {
SkypeCall(wParam, 0);
}

return 0;
}
*/

MCONTACT find_contact(char *name)
{
	int tCompareResult;
	DBVARIANT dbv;

	// already on list?
	for (MCONTACT hContact = db_find_first(SKYPE_PROTONAME); hContact != NULL; hContact = db_find_next(hContact,SKYPE_PROTONAME))
	{
		if (db_get_b(hContact, SKYPE_PROTONAME, "ChatRoom", 0) == 0)
		{
			if (db_get_s(hContact, SKYPE_PROTONAME, SKYPE_NAME, &dbv)) continue;
			tCompareResult = strcmp(dbv.pszVal, name);
			db_free(&dbv);
			if (tCompareResult) continue;
			return hContact; // already there, return handle
		}
	}
	return NULL;
}

MCONTACT find_contactT(TCHAR *name)
{
	int tCompareResult;
	DBVARIANT dbv;

	// already on list?
	for (MCONTACT hContact = db_find_first(SKYPE_PROTONAME); hContact != NULL; hContact = db_find_next(hContact,SKYPE_PROTONAME))
	{
		if (db_get_b(hContact, SKYPE_PROTONAME, "ChatRoom", 0) == 0)
		{
			if (db_get_ts(hContact, SKYPE_PROTONAME, SKYPE_NAME, &dbv)) continue;
			tCompareResult = _tcscmp(dbv.ptszVal, name);
			db_free(&dbv);
			if (tCompareResult) continue;
			return hContact; // already there, return handle
		}
	}
	return NULL;
}


MCONTACT add_contact(char *name, DWORD flags)
{
	// already on list?
	MCONTACT hContact = find_contact(name);
	if (hContact) {
		if (!(flags & PALF_TEMPORARY) && db_get_b(hContact, "CList", "NotOnList", 1)) {
			db_unset(hContact, "CList", "NotOnList");
			db_unset(hContact, "CList", "Hidden");
		}
		LOG(("add_contact: Found %s", name));
		return hContact; // already there, return handle
	}
	// no, so add

	LOG(("add_contact: Adding %s", name));
	hContact = (MCONTACT)CallServiceSync(MS_DB_CONTACT_ADD, 0, 0);
	if (hContact) {
		if (CallServiceSync(MS_PROTO_ADDTOCONTACT, hContact, (LPARAM)SKYPE_PROTONAME) != 0) {
			LOG(("add_contact: Ouch! MS_PROTO_ADDTOCONTACT failed for some reason"));
			CallServiceSync(MS_DB_CONTACT_DELETE, hContact, 0);
			return NULL;
		}
		if (name[0]) db_set_s(hContact, SKYPE_PROTONAME, SKYPE_NAME, name);

		if (flags & PALF_TEMPORARY) {
			db_set_b(hContact, "CList", "NotOnList", 1);
			db_set_b(hContact, "CList", "Hidden", 1);
		}
		if (name[0]) {
			SkypeSend("GET USER %s DISPLAYNAME", name);
		}
		else { LOG(("add_contact: Info: The contact added has no name.")); }
	}
	else { LOG(("add_contact: Ouch! MS_DB_CONTACT_ADD failed for some reason")); }
	LOG(("add_contact succeeded"));
	return hContact;
}

void logoff_contacts(BOOL bCleanup) {
	MCONTACT hContact;
	char *szProto;
	DBVARIANT dbv = { 0 };

	LOG(("logoff_contacts: Logging off contacts."));
	for (hContact = db_find_first(); hContact != NULL; hContact = db_find_next(hContact)) {
		szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, hContact, 0);
		if (szProto != NULL && !strcmp(szProto, SKYPE_PROTONAME))
		{
			if (db_get_w(hContact, SKYPE_PROTONAME, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE)
				db_set_w(hContact, SKYPE_PROTONAME, "Status", ID_STATUS_OFFLINE);

			db_unset(hContact, SKYPE_PROTONAME, "CallId");
			if (db_get_b(hContact, SKYPE_PROTONAME, "ChatRoom", 0) == 1)
			{
				if (db_get_ts(hContact, SKYPE_PROTONAME, "ChatRoomID", &dbv)) continue;
				RemChat(dbv.ptszVal);
				db_free(&dbv);
			}
			if (db_get_s(hContact, SKYPE_PROTONAME, "Typing_Stream", &dbv) == 0)
			{
				if (bCleanup) SkypeSend("ALTER APPLICATION libpurple_typing DISCONNECT %s", dbv.pszVal);
				db_free(&dbv);
				db_unset(hContact, SKYPE_PROTONAME, "Typing_Stream");
			}

		}
	}
	if (bCleanup && (protocol >= 5 || bIsImoproxy)) SkypeSend("DELETE APPLICATION libpurple_typing");
}