/*

Miranda NG: the free IM client for Microsoft* Windows*

Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org),
Copyright (c) 2000-12 Miranda IM project,
all portions of this codebase are copyrighted to the people
listed in contributors.txt.

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 2
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "commonheaders.h"

static HANDLE hEventDefaultChanged, hEventEnabled;
static bool g_bEnabled;

void InitMetaContacts()
{
	hEventDefaultChanged = CreateHookableEvent(ME_MC_DEFAULTTCHANGED);
	hEventEnabled = CreateHookableEvent(ME_MC_ENABLED);
}

DBCachedContact* CheckMeta(MCONTACT hMeta)
{
	if (!g_bEnabled)
		return NULL;

	DBCachedContact *cc = currDb->m_cache->GetCachedContact(hMeta);
	return (cc == NULL || cc->nSubs == -1) ? NULL : cc;
}

int Meta_GetContactNumber(DBCachedContact *cc, MCONTACT hContact)
{
	if (g_bEnabled)
		for (int i = 0; i < cc->nSubs; i++)
			if (cc->pSubs[i] == hContact)
				return i;

	return -1;
}

MCONTACT Meta_GetContactHandle(DBCachedContact *cc, int contact_number)
{
	if (contact_number >= cc->nSubs || contact_number < 0 || !g_bEnabled)
		return 0;

	return cc->pSubs[contact_number];
}

/////////////////////////////////////////////////////////////////////////////////////////
// metacontacts

MIR_CORE_DLL(BOOL) db_mc_isEnabled(void)
{
	return g_bEnabled;
}

MIR_CORE_DLL(void) db_mc_enable(BOOL bEnabled)
{
	g_bEnabled = bEnabled != 0;

	NotifyEventHooks(hEventEnabled, g_bEnabled, 0);
}

MIR_CORE_DLL(BOOL) db_mc_isMeta(MCONTACT hContact)
{
	if (currDb == NULL || !g_bEnabled) return FALSE;

	DBCachedContact *cc = currDb->m_cache->GetCachedContact(hContact);
	return (cc == NULL) ? FALSE : cc->nSubs != -1;
}

MIR_CORE_DLL(BOOL) db_mc_isSub(MCONTACT hContact)
{
	if (currDb == NULL || !g_bEnabled) return FALSE;

	DBCachedContact *cc = currDb->m_cache->GetCachedContact(hContact);
	return (cc == NULL) ? FALSE : cc->parentID != 0;
}

//returns a handle to the default contact, or null on failure
MIR_CORE_DLL(MCONTACT) db_mc_getDefault(MCONTACT hMetaContact)
{
	DBCachedContact *cc = CheckMeta(hMetaContact);
	if (cc == NULL)
		return 0;

	return (cc->nDefault != -1) ? Meta_GetContactHandle(cc, cc->nDefault) : 0;
}

//returns the default contact number, or -1 on failure
MIR_CORE_DLL(int) db_mc_getDefaultNum(MCONTACT hMetaContact)
{
	DBCachedContact *cc = CheckMeta(hMetaContact);
	return (cc == NULL) ? -1 : cc->nDefault;
}

//returns the number of subcontacts, or -1 on failure
MIR_CORE_DLL(int) db_mc_getSubCount(MCONTACT hMetaContact)
{
	DBCachedContact *cc = CheckMeta(hMetaContact);
	return (cc == NULL) ? -1 : cc->nSubs;
}

// returns parent hContact for a subcontact or NULL if it's not a sub
MIR_CORE_DLL(MCONTACT) db_mc_getMeta(MCONTACT hSubContact)
{
	if (currDb == NULL) return NULL;

	DBCachedContact *cc = currDb->m_cache->GetCachedContact(hSubContact);
	return (cc == NULL) ? NULL : cc->parentID;
}

// returns parent hContact for a subcontact or hContact itself if it's not a sub
MIR_CORE_DLL(MCONTACT) db_mc_tryMeta(MCONTACT hContact)
{
	if (currDb == NULL) return hContact;

	DBCachedContact *cc = currDb->m_cache->GetCachedContact(hContact);
	if (cc == NULL) return hContact;

	return (cc->IsSub()) ? cc->parentID : hContact;
}

// returns a subcontact with the given index
MIR_CORE_DLL(MCONTACT) db_mc_getSub(MCONTACT hMetaContact, int iNum)
{
	DBCachedContact *cc = CheckMeta(hMetaContact);
	return (cc == NULL) ? 0 : Meta_GetContactHandle(cc, iNum);
}

//sets the default contact, using the subcontact's handle
MIR_CORE_DLL(int) db_mc_setDefault(MCONTACT hMetaContact, MCONTACT hSub, BOOL bWriteDb)
{
	DBCachedContact *cc = CheckMeta(hMetaContact);
	if (cc == NULL)
		return 1;

	int contact_number = Meta_GetContactNumber(cc, hSub);
	if (contact_number == -1) 
		return 1;

	if (cc->nDefault != contact_number) {
		cc->nDefault = contact_number;
		if (bWriteDb)
			currDb->MetaSetDefault(cc);

		NotifyEventHooks(hEventDefaultChanged, hMetaContact, hSub);
	}
	return 0;
}

//sets the default contact, using the subcontact's number
MIR_CORE_DLL(int) db_mc_setDefaultNum(MCONTACT hMetaContact, int iNum, BOOL bWriteDb)
{
	DBCachedContact *cc = CheckMeta(hMetaContact);
	if (cc == NULL)
		return 1;
	if (iNum >= cc->nSubs || iNum < 0)
		return 1;

	if (cc->nDefault != iNum) {
		cc->nDefault = iNum;
		if (bWriteDb)
			currDb->MetaSetDefault(cc);

		NotifyEventHooks(hEventDefaultChanged, hMetaContact, Meta_GetContactHandle(cc, iNum));
	}
	return 0;
}

extern "C" MIR_CORE_DLL(void) db_mc_notifyDefChange(WPARAM wParam, LPARAM lParam)
{
	NotifyEventHooks(hEventDefaultChanged, wParam, lParam);
}