/*
Scriver

Copyright 2000-2009 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 "statusicon.h"

struct StatusIconListNode {
	StatusIconData sid;
	struct StatusIconListNode *next;
};

HANDLE hHookIconPressedEvt;
static struct StatusIconListNode *status_icon_list = 0;
static int status_icon_list_size = 0;

static INT_PTR AddStatusIcon(WPARAM wParam, LPARAM lParam) {
	StatusIconData *sid = (StatusIconData *)lParam;
	struct StatusIconListNode *siln = (struct StatusIconListNode *)mir_alloc(sizeof(struct StatusIconListNode));

	siln->sid.cbSize = sid->cbSize;
	siln->sid.szModule = mir_strdup(sid->szModule);
	siln->sid.dwId = sid->dwId;
	siln->sid.hIcon = sid->hIcon;
	siln->sid.hIconDisabled = sid->hIconDisabled;
	siln->sid.flags = sid->flags;
	if(sid->szTooltip) siln->sid.szTooltip = mir_strdup(sid->szTooltip);
	else siln->sid.szTooltip = 0;

	siln->next = status_icon_list;
	status_icon_list = siln;
	status_icon_list_size++;

	WindowList_Broadcast(g_dat->hParentWindowList, DM_STATUSICONCHANGE, 0, 0);
	return 0;
}

INT_PTR AddStickyStatusIcon(WPARAM wParam, LPARAM lParam) {
	StatusIconData *sid = (StatusIconData *)lParam;
	struct StatusIconListNode *siln = (struct StatusIconListNode *)mir_alloc(sizeof(struct StatusIconListNode));
	struct StatusIconListNode *siln2 = status_icon_list;

	siln->sid.cbSize = sid->cbSize;
	siln->sid.szModule = mir_strdup(sid->szModule);
	siln->sid.dwId = sid->dwId;
	siln->sid.hIcon = sid->hIcon;
	siln->sid.hIconDisabled = sid->hIconDisabled;
	siln->sid.flags = sid->flags;
	if(sid->szTooltip) siln->sid.szTooltip = mir_strdup(sid->szTooltip);
	else siln->sid.szTooltip = 0;
	siln->next = NULL;

	while(siln2 && siln2->next) {
		siln2 = siln2->next;
	}
	if (siln2) {
		siln2->next = siln;
	} else {
		status_icon_list = siln;
	}

	status_icon_list_size++;

	WindowList_Broadcast(g_dat->hParentWindowList, DM_STATUSICONCHANGE, 0, 0);
	return 0;
}

static INT_PTR RemoveStatusIcon(WPARAM wParam, LPARAM lParam) {
	StatusIconData *sid = (StatusIconData *)lParam;
	struct StatusIconListNode *current = status_icon_list, *prev = 0;

	while(current) {
		if(strcmp(current->sid.szModule, sid->szModule) == 0 && current->sid.dwId == sid->dwId) {
			if(prev) prev->next = current->next;
			else status_icon_list = current->next;

			status_icon_list_size--;

			mir_free(current->sid.szModule);
			ReleaseIconSmart(current->sid.hIcon);
			ReleaseIconSmart(current->sid.hIconDisabled);
			mir_free(current->sid.szTooltip);
			mir_free(current);
			WindowList_Broadcast(g_dat->hParentWindowList, DM_STATUSICONCHANGE, 0, 0);
			return 0;
		}

		prev = current;
		current = current->next;
	}

	return 1;
}

static void RemoveAllStatusIcons(void) {
	struct StatusIconListNode *current;

	while(status_icon_list) {
		current = status_icon_list;
		status_icon_list = status_icon_list->next;
		status_icon_list_size--;

		mir_free(current->sid.szModule);
		DestroyIcon(current->sid.hIcon);
		if(current->sid.hIconDisabled) DestroyIcon(current->sid.hIconDisabled);
		if(current->sid.szTooltip) mir_free(current->sid.szTooltip);
		mir_free(current);
	}

	WindowList_Broadcast(g_dat->hParentWindowList, DM_STATUSICONCHANGE, 0, 0);
}

INT_PTR ModifyStatusIcon(WPARAM wParam, LPARAM lParam) {
	HANDLE hContact = (HANDLE)wParam;

	StatusIconData *sid = (StatusIconData *)lParam;
	struct StatusIconListNode *current = status_icon_list;

	while(current) {
		if(strcmp(current->sid.szModule, sid->szModule) == 0 && current->sid.dwId == sid->dwId) {
			if (!hContact) {
				current->sid.flags = sid->flags;
				if(sid->hIcon) {
					ReleaseIconSmart(current->sid.hIcon);
					current->sid.hIcon = sid->hIcon;
				}
				if(sid->hIconDisabled) {
					ReleaseIconSmart(current->sid.hIconDisabled);
					current->sid.hIconDisabled = sid->hIconDisabled;
				}
				if(sid->szTooltip) {
					if(current->sid.szTooltip) mir_free(current->sid.szTooltip);
					current->sid.szTooltip = mir_strdup(sid->szTooltip);
				}

				WindowList_Broadcast(g_dat->hParentWindowList, DM_STATUSICONCHANGE, 0, 0);
			} else {
				char buff[256];
				HWND hwnd;
				sprintf(buff, "SRMMStatusIconFlags%d", (int)sid->dwId);
				DBWriteContactSettingByte(hContact, sid->szModule, buff, (BYTE)sid->flags);
				hwnd = WindowList_Find(g_dat->hMessageWindowList, hContact);
				if (hwnd == NULL) {
					hwnd = SM_FindWindowByContact(hContact);
				}
				if (hwnd != NULL) {
					PostMessage(GetParent(hwnd), DM_STATUSICONCHANGE, 0, 0);
				}
			}
			return 0;
		}

		current = current->next;
	}

	return 1;
}

void DrawStatusIcons(HANDLE hContact, HDC hDC, RECT r, int gap) {
	struct StatusIconListNode *current = status_icon_list;
	HICON hIcon;
	char buff[256];
	int flags;
	int x = r.left;
	while(current) {
		sprintf(buff, "SRMMStatusIconFlags%d", (int)current->sid.dwId);
		flags = DBGetContactSettingByte(hContact, current->sid.szModule, buff, current->sid.flags);
		if (!(flags & MBF_HIDDEN)) {
			if ((flags & MBF_DISABLED) && current->sid.hIconDisabled) hIcon = current->sid.hIconDisabled;
			else hIcon = current->sid.hIcon;

			SetBkMode(hDC, TRANSPARENT);
			DrawIconEx(hDC, x, (r.top + r.bottom - GetSystemMetrics(SM_CYSMICON)) >> 1, hIcon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0, NULL, DI_NORMAL);

			x += GetSystemMetrics(SM_CYSMICON) + gap;
		}
		current = current->next;
	}
}

void CheckStatusIconClick(HANDLE hContact, HWND hwndFrom, POINT pt, RECT r, int gap, int click_flags) {
	StatusIconClickData sicd;
	struct StatusIconListNode *current = status_icon_list;
	unsigned int iconNum = (pt.x - r.left) / (GetSystemMetrics(SM_CXSMICON) + gap) + 1;
	int flags;
	char buff[256];

	while(current) {
		sprintf(buff, "SRMMStatusIconFlags%d", (int)current->sid.dwId);
		flags = DBGetContactSettingByte(hContact, current->sid.szModule, buff, current->sid.flags);
		if (!(flags & MBF_HIDDEN)) iconNum--;
		if (iconNum == 0) break;
		current = current->next;
	}

	if(current) {
		ClientToScreen(hwndFrom, &pt);
		sicd.cbSize = sizeof(StatusIconClickData);
		sicd.clickLocation = pt;
		sicd.dwId = current->sid.dwId;
		sicd.szModule = current->sid.szModule;
		sicd.flags = click_flags;
		NotifyEventHooks(hHookIconPressedEvt, (WPARAM)hContact, (LPARAM)&sicd);
	}
}


HANDLE hServiceIcon[3];
int InitStatusIcons() {
	hServiceIcon[0] = CreateServiceFunction(MS_MSG_ADDICON, AddStatusIcon);
	hServiceIcon[1] = CreateServiceFunction(MS_MSG_REMOVEICON, RemoveStatusIcon);
	hServiceIcon[2] = CreateServiceFunction(MS_MSG_MODIFYICON, ModifyStatusIcon);
	hHookIconPressedEvt = CreateHookableEvent(ME_MSG_ICONPRESSED);
	return 0;
}

int DeinitStatusIcons() {
	int i;
	DestroyHookableEvent(hHookIconPressedEvt);
	for(i = 0; i < 3; i++) DestroyServiceFunction(hServiceIcon[i]);
	RemoveAllStatusIcons();
	return 0;
}

INT_PTR GetStatusIconsCount(HANDLE hContact) {
	char buff[256];
	int count = 0;
	int flags;
	struct StatusIconListNode *current = status_icon_list;
	while(current) {
		sprintf(buff, "SRMMStatusIconFlags%d", (int)current->sid.dwId);
		flags = DBGetContactSettingByte(hContact, current->sid.szModule, buff, current->sid.flags);
		if (!(flags & MBF_HIDDEN)) {
			count ++;
		}
		current = current->next;
	}
	return count;
//	return status_icon_list_size;
}