/*

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

Copyright 2000-2003 Miranda ICQ/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"
#include "m_clui.h"
#include "clist.h"

extern HANDLE hContactIconChangedEvent;
extern int GetContactCachedStatus(HANDLE hContact);
extern char *GetContactCachedProtocol(HANDLE hContact);

int sortByStatus;
static int sortByProto;
static int sortNoOfflineBottom;
struct {
	int status,order;
} statusModeOrder[]={
	{ID_STATUS_OFFLINE,500},
	{ID_STATUS_ONLINE,0},
	{ID_STATUS_AWAY,200},
	{ID_STATUS_DND,400},
	{ID_STATUS_NA,450},
	{ID_STATUS_OCCUPIED,100},
	{ID_STATUS_FREECHAT,50},
	{ID_STATUS_INVISIBLE,20},
	{ID_STATUS_ONTHEPHONE,150},
	{ID_STATUS_OUTTOLUNCH,425}};

static int GetContactStatus(HANDLE hContact)
{
	/*
	
	char *szProto;

	szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
	if(szProto==NULL) return ID_STATUS_OFFLINE;
	return DBGetContactSettingWord(hContact,szProto,"Status",ID_STATUS_OFFLINE);
	*/
	return (GetContactCachedStatus(hContact));
}

void ChangeContactIcon(HANDLE hContact,int iIcon,int add)
{
	//clui MS_CLUI_CONTACTADDED MS_CLUI_CONTACTSETICON this methods is null
	//CallService(add?MS_CLUI_CONTACTADDED:MS_CLUI_CONTACTSETICON,(WPARAM)hContact,iIcon);
	NotifyEventHooks(hContactIconChangedEvent,(WPARAM)hContact,iIcon);
}

static int GetStatusModeOrdering(int statusMode)
{
	int i;
	for(i=0; i< SIZEOF(statusModeOrder); i++)
		if(statusModeOrder[i].status==statusMode) return statusModeOrder[i].order;
	return 1000;
}

void LoadContactTree(void)
{
	HANDLE hContact;
	int i,hideOffline,status,tick;
	pdisplayNameCacheEntry cacheEntry;
		


	tick=GetTickCount();
	CallService(MS_CLUI_LISTBEGINREBUILD,0,0);
	for(i=1;;i++) {
		if((char*)CallService(MS_CLIST_GROUPGETNAME2,i,(LPARAM)(int*)NULL)==NULL) break;
		CallService(MS_CLUI_GROUPADDED,i,0);
	}

	hideOffline=DBGetContactSettingByte(NULL,"CList","HideOffline",SETTING_HIDEOFFLINE_DEFAULT);
	hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);

	while(hContact!=NULL) {
		cacheEntry=GetContactFullCacheEntry(hContact);
		if (cacheEntry==NULL)
		{
			MessageBoxA(0,"Fail To Get CacheEntry for hContact","!!!!!",0);
			break;
		}
		status=cacheEntry->status;
		if((!hideOffline || status!=ID_STATUS_OFFLINE) && !cacheEntry->Hidden)
			ChangeContactIcon(hContact,ExtIconFromStatusMode(hContact,(char*)cacheEntry->szProto,status),1);
		hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0);
	}
	sortByStatus=DBGetContactSettingByte(NULL,"CList","SortByStatus",SETTING_SORTBYSTATUS_DEFAULT);
	sortByProto=DBGetContactSettingByte(NULL,"CList","SortByProto",SETTING_SORTBYPROTO_DEFAULT);
	sortNoOfflineBottom=DBGetContactSettingByte(NULL,"CList","NoOfflineBottom",SETTING_NOOFFLINEBOTTOM_DEFAULT);

	CallService(MS_CLUI_SORTLIST,0,0);
	CallService(MS_CLUI_LISTENDREBUILD,0,0);
	
	tick=GetTickCount()-tick;
	{
	char buf[255];
	//sprintf(buf,"%s %s took %i ms",__FILE__,__LINE__,tick);
	sprintf(buf,"LoadContactTree %d \r\n",tick);

	OutputDebugStringA(buf);
	}
}

#define SAFESTRING(a) a?a:""

int CompareContacts( const struct ClcContact *contact1, const struct ClcContact *contact2 )
{
	HANDLE a = contact1->hContact, b = contact2->hContact;
	TCHAR *namea,*nameb;
	int statusa,statusb;
	char *szProto1,*szProto2;
	int rc;

	GetContactInfosForSort(a,&szProto1,&namea,&statusa);
	GetContactInfosForSort(b,&szProto2,&nameb,&statusb);

	if (sortByProto) {

		/* deal with statuses, online contacts have to go above offline */
		if (sortNoOfflineBottom==0) 
			if((statusa==ID_STATUS_OFFLINE)!=(statusb==ID_STATUS_OFFLINE)) {
			return 2*(statusa==ID_STATUS_OFFLINE)-1;
		}
		/* both are online, now check protocols */
		rc=strcmp(SAFESTRING(szProto1),SAFESTRING(szProto2)); /* strcmp() doesn't like NULL so feed in "" as needed */
		if (rc != 0 && (szProto1 != NULL && szProto2 != NULL)) return rc;
		/* protocols are the same, order by display name */
	} 

	if(sortByStatus) {
		int ordera,orderb;
		ordera=GetStatusModeOrdering(statusa);
		orderb=GetStatusModeOrdering(statusb);
		if(ordera!=orderb) return ordera-orderb;
	}
	else {
		//one is offline: offline goes below online
		if (sortNoOfflineBottom==0)
			{
			if((statusa==ID_STATUS_OFFLINE)!=(statusb==ID_STATUS_OFFLINE)) {
				return 2*(statusa==ID_STATUS_OFFLINE)-1;
			}
		}
	}

	//otherwise just compare names
	return _tcsicmp(namea,nameb);
}

#undef SAFESTRING

static UINT_PTR resortTimerId=0;
static VOID CALLBACK SortContactsTimer(HWND hwnd,UINT message,UINT_PTR idEvent,DWORD dwTime)
{
	KillTimer(NULL,resortTimerId);
	resortTimerId=0;
	CallService(MS_CLUI_SORTLIST,0,0);
}

void SortContacts(void)
{
	//avoid doing lots of resorts in quick succession
	sortByStatus=DBGetContactSettingByte(NULL,"CList","SortByStatus",SETTING_SORTBYSTATUS_DEFAULT);
	sortByProto=DBGetContactSettingByte(NULL,"CList","SortByProto",SETTING_SORTBYPROTO_DEFAULT);
	if(resortTimerId) KillTimer(NULL,resortTimerId);
	resortTimerId=SetTimer(NULL,0,50,SortContactsTimer);
}

INT_PTR ContactChangeGroup(WPARAM wParam,LPARAM lParam)
{
	CallService(MS_CLUI_CONTACTDELETED,wParam,0);
	if((HANDLE)lParam==NULL)
		DBDeleteContactSetting((HANDLE)wParam,"CList","Group");
	else
		DBWriteContactSettingString((HANDLE)wParam,"CList","Group",(char*)CallService(MS_CLIST_GROUPGETNAME2,lParam,(LPARAM)(int*)NULL));
	CallService(MS_CLUI_CONTACTADDED,wParam,ExtIconFromStatusMode((HANDLE)wParam,(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0),GetContactStatus((HANDLE)wParam)));
	return 0;
}