/*
	NewXstatusNotify YM - Plugin for Miranda IM
	Copyright (c) 2001-2004 Luca Santarelli
	Copyright (c) 2005-2007 Vasilich
	Copyright (c) 2007-2011 yaho

	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 "common.h"
#include "options.h"
#include "indsnd.h"
#include "utils.h"

extern STATUS StatusList[];
extern OPTIONS opt;
extern HINSTANCE hInst;

void PreviewSound(HWND hList)
{
	TCHAR buff[MAX_PATH], stzSoundPath[MAX_PATH];

	LVITEM lvi = {0};
	lvi.mask = LVIF_PARAM;
	lvi.iItem = ListView_GetNextItem(hList, -1, LVNI_SELECTED);
	ListView_GetItem(hList, &lvi);

	int hlpStatus = lvi.lParam;
	
	ListView_GetItemText(hList, lvi.iItem, 1, buff, SIZEOF(buff));
	if (_tcscmp(buff, TranslateT(DEFAULT_SOUND)) == 0)
	{
		if (hlpStatus == ID_STATUS_FROMOFFLINE) 
			SkinPlaySound("UserFromOffline");
		else 
			SkinPlaySound(StatusList[Index(hlpStatus)].lpzSkinSoundName);
	}
	else 
	{ 
		CallService(MS_UTILS_PATHTOABSOLUTET, (WPARAM)buff, (LPARAM)stzSoundPath);
		PlaySound(stzSoundPath, NULL, SND_ASYNC | SND_FILENAME);
	}
}

BOOL RemoveSoundFromList(HWND hList)
{
	int iSel = ListView_GetSelectionMark(hList);
	if (iSel != -1)
	{
		iSel = -1;
		while ((iSel = ListView_GetNextItem(hList, iSel, LVNI_SELECTED)) != -1)
			ListView_SetItemText(hList, iSel, 1, TranslateT(DEFAULT_SOUND));
		return TRUE;
	}

	return FALSE;
}

TCHAR *SelectSound(HWND hwndDlg, TCHAR *buff) 
{
	OPENFILENAME ofn = {0};

	HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST);
	ListView_GetItemText(hList, ListView_GetNextItem(hList,- 1, LVNI_SELECTED), 1, buff, SIZEOF(buff));

	ofn.lStructSize = sizeof(ofn);
	ofn.hwndOwner = GetParent(hwndDlg);
	ofn.hInstance = hInst;
	TCHAR filter[MAX_PATH];
	mir_sntprintf(filter, SIZEOF(filter), _T("%s (*.wav)%c*.WAV%c%s (*.*)%c*%c"), TranslateT("Wave Files"), 0, 0, TranslateT("All Files"), 0, 0);
	ofn.lpstrFilter = filter;
	ofn.lpstrFile = buff;
	ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_EXPLORER | OFN_NOCHANGEDIR;
	ofn.nMaxFile = MAX_PATH;
	ofn.nMaxFileTitle = MAX_PATH;
	ofn.lpstrDefExt = _T("wav");
	if (GetOpenFileName(&ofn))
		return buff;
	
	return NULL;
}

HIMAGELIST GetStatusIconsImgList(char *szProto) 
{
	HIMAGELIST hList = NULL;
	if (szProto)
	{
		hList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16 | ILC_MASK, STATUS_COUNT, 0);
		if (hList != NULL) 
		{
			for (int i = ID_STATUS_MIN; i <= ID_STATUS_MAX; i++)
				ImageList_AddIcon(hList, LoadSkinnedProtoIcon(szProto, StatusList[Index(i)].ID));
			ImageList_AddIcon(hList, LoadSkinnedIcon(SKINICON_OTHER_USERONLINE));
		}
	}

	return hList;
}

INT_PTR CALLBACK DlgProcSoundUIPage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) 
{
	static HANDLE hContact = NULL;
	switch (msg) 
	{
		case WM_INITDIALOG: 
		{		
			TranslateDialogDefault(hwndDlg);

			hContact = (HANDLE)lParam;
			char *szProto = GetContactProto(hContact);
			HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST);
			
			ListView_SetImageList(hList, GetStatusIconsImgList(szProto), LVSIL_SMALL);
			ListView_SetExtendedListViewStyleEx(hList, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);

			RECT rc = {0};
			GetClientRect(hList, &rc);

			LV_COLUMN lvc = {0};
			lvc.mask = LVCF_WIDTH | LVCF_TEXT;
			lvc.cx = STATUS_COLUMN;
			lvc.pszText = TranslateT("Status");
			ListView_InsertColumn(hList, 0, &lvc);

			lvc.cx = rc.right - STATUS_COLUMN - GetSystemMetrics(SM_CXVSCROLL);
			lvc.pszText = TranslateT("Sound for the status");
			ListView_InsertColumn(hList, 1, &lvc);

			if (szProto)
			{
				DBVARIANT dbv;
				TCHAR buff[MAX_PATH];

				for (int i = ID_STATUS_MAX; i >= ID_STATUS_MIN; i--) 
				{   
					int flags = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_2, 0);
					if (flags == 0) 
						flags = PF2_ONLINE|PF2_INVISIBLE|PF2_SHORTAWAY|PF2_LONGAWAY|PF2_LIGHTDND|PF2_HEAVYDND|PF2_FREECHAT|PF2_OUTTOLUNCH|PF2_ONTHEPHONE;
					
					if ((flags & Proto_Status2Flag(i)) || i == ID_STATUS_OFFLINE)
					{
						LV_ITEM lvi = {0};
						lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
						lvi.iItem = 0;
						lvi.iSubItem = 0;
						lvi.iImage = Index(i);
						lvi.lParam = (LPARAM)i;
						lvi.pszText = TranslateTS(StatusList[Index(i)].lpzStandardText);
						lvi.iItem = ListView_InsertItem(hList, &lvi);

						if (!db_get_ts(hContact, MODULE, StatusList[Index(i)].lpzSkinSoundName, &dbv)) 
						{
							_tcscpy(buff, dbv.ptszVal);
							db_free(&dbv);
						}
						else
							_tcscpy(buff, TranslateT(DEFAULT_SOUND));

						ListView_SetItemText(hList, lvi.iItem, 1, buff);
					}
				}

				LV_ITEM lvi = {0};
				lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
				lvi.iItem = 0;
				lvi.iSubItem = 0;
				lvi.iImage = Index(ID_STATUS_MAX) + 1; // additional icon
				lvi.lParam = (LPARAM)ID_STATUS_FROMOFFLINE;
				lvi.pszText = TranslateT("From offline");
				lvi.iItem = ListView_InsertItem(hList, &lvi);

				if (!db_get_ts(hContact, MODULE, "UserFromOffline", &dbv)) 
				{
					_tcscpy(buff, dbv.ptszVal);
					db_free(&dbv);
				}
				else
					_tcscpy(buff, TranslateT(DEFAULT_SOUND));

				ListView_SetItemText(hList, lvi.iItem, 1, buff);
			}

			CheckDlgButton(hwndDlg, IDC_CHECK_NOTIFYSOUNDS, db_get_b(hContact, MODULE, "EnableSounds", 1));
			CheckDlgButton(hwndDlg, IDC_CHECK_NOTIFYPOPUPS, db_get_b(hContact, MODULE, "EnablePopups", 1));			
			
			ShowWindow(GetDlgItem(hwndDlg, IDC_INDSNDLIST), opt.UseIndSnd ? SW_SHOW : SW_HIDE);
			ShowWindow(GetDlgItem(hwndDlg, IDC_TEXT_ENABLE_IS), opt.UseIndSnd ? SW_HIDE : SW_SHOW);
			ShowWindow(GetDlgItem(hwndDlg, IDC_CHANGE), opt.UseIndSnd ? SW_SHOW : SW_HIDE);
			ShowWindow(GetDlgItem(hwndDlg, IDC_PREVIEW), opt.UseIndSnd ? SW_SHOW : SW_HIDE);
			ShowWindow(GetDlgItem(hwndDlg, IDC_DELETE), opt.UseIndSnd ? SW_SHOW : SW_HIDE);

			return TRUE;
		}
		case WM_COMMAND: 
		{
			switch (LOWORD(wParam)) 
			{
				case IDC_PREVIEW: 
				{
					HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST);
					if (ListView_GetSelectionMark(hList) != -1) 
						PreviewSound(hList);
					break;
				}
				case IDC_CHANGE:
				{
					HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST);
					int iSel = ListView_GetNextItem(GetDlgItem(hwndDlg, IDC_INDSNDLIST), -1, LVNI_SELECTED);
					if (iSel != -1)
					{
						TCHAR stzFilePath[MAX_PATH];
						if (SelectSound(hwndDlg, stzFilePath) != NULL)
						{
							iSel = -1;
							while ((iSel = ListView_GetNextItem(hList, iSel, LVNI_SELECTED)) != -1)
								ListView_SetItemText(hList, iSel, 1, stzFilePath);

							SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
						}
					}
					break;
				}
				case IDC_DELETE:
				{
					HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST);
					if (ListView_GetSelectionMark(hList) != -1) 
					{
						if (RemoveSoundFromList(GetDlgItem(hwndDlg, IDC_INDSNDLIST)))
							SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
					}
					break;
				}
				case IDC_CHECK_NOTIFYSOUNDS:
				{
					db_set_b(hContact, MODULE, "EnableSounds", IsDlgButtonChecked(hwndDlg, IDC_CHECK_NOTIFYSOUNDS) ? 1 : 0);
					break;
				}
				case IDC_CHECK_NOTIFYPOPUPS:
				{
					db_set_b(hContact, MODULE, "EnablePopups", IsDlgButtonChecked(hwndDlg, IDC_CHECK_NOTIFYPOPUPS) ? 1 : 0);
					break;
				}
			} 
			break;
		}
		case WM_NOTIFY:
		{
			LPNMHDR pParam = (LPNMHDR)lParam;
			if (pParam->code == PSN_APPLY) 
			{
				TCHAR buff[MAX_PATH];
				HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST);

				LVITEM lvi = {0};
				lvi.mask = LVIF_PARAM;
				//Cycle through the list reading the text associated to each status.
				for (lvi.iItem = ListView_GetItemCount(hList) - 1; lvi.iItem >= 0; lvi.iItem--) 
				{
					ListView_GetItem(hList, &lvi);
					ListView_GetItemText(hList, lvi.iItem, 1, buff, SIZEOF(buff));

					if (!_tcscmp(buff, TranslateT(DEFAULT_SOUND))) 
					{
						if (lvi.lParam == ID_STATUS_FROMOFFLINE)
							db_unset(hContact, MODULE, "UserFromOffline");
						else 
							db_unset(hContact, MODULE, StatusList[Index(lvi.lParam)].lpzSkinSoundName);
					}
					else 
					{
						TCHAR stzSoundPath[MAX_PATH] = { 0 };
						CallService(MS_UTILS_PATHTORELATIVET, (WPARAM)buff, (LPARAM)stzSoundPath);
						if (lvi.lParam == ID_STATUS_FROMOFFLINE)
							db_set_ws(hContact, MODULE, "UserFromOffline", stzSoundPath);
						else
							db_set_ws(hContact, MODULE, StatusList[Index(lvi.lParam)].lpzSkinSoundName, stzSoundPath);
					}
				}

				return TRUE;
			}

			int hlpControlID = (int)wParam;
			switch (hlpControlID) 
			{
				case IDC_INDSNDLIST: 	
				{
					if (pParam->code == NM_DBLCLK) 
					{
						TCHAR stzFilePath[MAX_PATH];
						if (SelectSound(hwndDlg, stzFilePath) != NULL)
						{
							int iSel = -1;
							HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST);
							while ((iSel = ListView_GetNextItem(hList, iSel, LVNI_SELECTED)) != -1)
								ListView_SetItemText(hList, iSel, 1, stzFilePath);

							SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
						}
						return TRUE;
					}
					else if (pParam->code == LVN_KEYDOWN) 
					{
						LPNMLVKEYDOWN pnkd = (LPNMLVKEYDOWN)lParam;
						if (pnkd->wVKey == VK_DELETE)
							RemoveSoundFromList(GetDlgItem(hwndDlg, IDC_INDSNDLIST));
					}

					break;
				}
			}
			break;
		}
	}
	return FALSE;
}

int UserInfoInitialise(WPARAM wParam, LPARAM lParam)
{
	if (lParam == NULL)
		return 0;

	OPTIONSDIALOGPAGE odp = {0};
	odp.cbSize = sizeof(odp);
	odp.position = 100000000;
	odp.hInstance = hInst;
	odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_SOUNDS);
	odp.pszTitle = LPGEN("Status Notify");
	odp.pfnDlgProc = DlgProcSoundUIPage;
	UserInfo_AddPage(wParam, &odp);
	
	return 0;
}

void ResetListOptions(HWND hwndList) 
{
	SendMessage(hwndList, CLM_SETBKBITMAP, 0, 0);
	SendMessage(hwndList, CLM_SETBKCOLOR, GetSysColor(COLOR_WINDOW), 0);
	SendMessage(hwndList, CLM_SETGREYOUTFLAGS, 0, 0);
	SendMessage(hwndList, CLM_SETLEFTMARGIN, 4, 0);
	SendMessage(hwndList, CLM_SETINDENT, 10, 0);

	for (int i = 0; i <= FONTID_MAX; i++)
		SendMessage(hwndList, CLM_SETTEXTCOLOR, i, GetSysColor(COLOR_WINDOWTEXT));

	SetWindowLongPtr(hwndList, GWL_STYLE, GetWindowLongPtr(hwndList,GWL_STYLE) | CLS_SHOWHIDDEN);
}

__inline int GetExtraImage(HWND hwndList, HANDLE hItem, int column)
{
	return SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(column, 0));
}

__inline void SetExtraImage(HWND hwndList, HANDLE hItem, int column, int imageID)
{
	SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(column, imageID));
}

void SetAllContactsIcons(HWND hwndList)
{
	BYTE EnableSounds, EnablePopups, EnableXStatus, EnableLogging;
	HANDLE hContact = db_find_first();
	while (hContact)
	{
		HANDLE hItem = (HANDLE)SendMessage(hwndList, CLM_FINDCONTACT, (WPARAM)hContact, 0);
		if (hItem)
		{
			char *szProto = GetContactProto(hContact);
			if (szProto) 
			{
				EnableSounds = db_get_b(hContact, MODULE, "EnableSounds", 1);
				EnablePopups = db_get_b(hContact, MODULE, "EnablePopups", 1);
				EnableXStatus = db_get_b(hContact, MODULE, "EnableXStatusNotify", 1);
				EnableLogging = db_get_b(hContact, MODULE, "EnableLogging", 1);
			}
			else
				EnableSounds = EnablePopups = EnableXStatus = EnableLogging = 0;

			SetExtraImage(hwndList, hItem, EXTRA_IMAGE_SOUND, EnableSounds ? EXTRA_IMAGE_SOUND : EXTRA_IMAGE_DOT);
			SetExtraImage(hwndList, hItem, EXTRA_IMAGE_POPUP, EnablePopups? EXTRA_IMAGE_POPUP : EXTRA_IMAGE_DOT);
			SetExtraImage(hwndList, hItem, EXTRA_IMAGE_XSTATUS, EnableXStatus ? EXTRA_IMAGE_XSTATUS : EXTRA_IMAGE_DOT);
			SetExtraImage(hwndList, hItem, EXTRA_IMAGE_LOGGING, EnableLogging ? EXTRA_IMAGE_LOGGING : EXTRA_IMAGE_DOT);
			SetExtraImage(hwndList, hItem, EXTRA_IMAGE_DISABLEALL, EXTRA_IMAGE_DISABLEALL);
			SetExtraImage(hwndList, hItem, EXTRA_IMAGE_ENABLEALL, EXTRA_IMAGE_ENABLEALL);
		}

		hContact = db_find_next(hContact);
	}
}

void SetGroupsIcons(HWND hwndList, HANDLE hFirstItem, HANDLE hParentItem, int *groupChildCount)
{
	int iconOn[6] = {1,1,1,1,1,1};
	int childCount[6] = {0};
	HANDLE hItem;

	int typeOfFirst = SendMessage(hwndList, CLM_GETITEMTYPE, (WPARAM)hFirstItem, 0);
	if (typeOfFirst == CLCIT_GROUP) 
		hItem = hFirstItem;
	else 
		hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTGROUP, (LPARAM)hFirstItem);

	while (hItem) 
	{
		HANDLE hChildItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem);
		if (hChildItem) 
			SetGroupsIcons(hwndList, hChildItem, hItem, childCount);

		for (int i = 0; i < SIZEOF(iconOn); i++)
		{
			if (iconOn[i] && GetExtraImage(hwndList, hItem, i) == EXTRA_IMAGE_DOT) 
				iconOn[i] = 0;
		}

		hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTGROUP, (LPARAM)hItem);
	}

	//check contacts
	if (typeOfFirst == CLCIT_CONTACT) 
		hItem = hFirstItem;
	else 
		hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTCONTACT, (LPARAM)hFirstItem);

	while(hItem) 
	{
		for (int i = 0; i < SIZEOF(iconOn); i++) 
		{
			int image = GetExtraImage(hwndList, hItem, i);
			if (iconOn[i] && image == EXTRA_IMAGE_DOT) 
				iconOn[i] = 0;

			if (image != EMPTY_EXTRA_ICON) 
				childCount[i]++;
		}

		hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTCONTACT, (LPARAM)hItem);
	}

	//set icons
	for(int i = 0; i < SIZEOF(iconOn); i++) 
	{
		SetExtraImage(hwndList, hParentItem, i, childCount[i] ? (iconOn[i] ? i : EXTRA_IMAGE_DOT) : EMPTY_EXTRA_ICON);
		if (groupChildCount) 
			groupChildCount[i] += childCount[i];
	}
}

void SetAllChildrenIcons(HWND hwndList, HANDLE hFirstItem, int column, int image)
{
	HANDLE hItem, hChildItem;

	int typeOfFirst = SendMessage(hwndList, CLM_GETITEMTYPE, (WPARAM)hFirstItem, 0);
	if (typeOfFirst == CLCIT_GROUP) 
		hItem = hFirstItem;
	else 
		hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTGROUP, (LPARAM)hFirstItem);

	while(hItem) 
	{
		hChildItem = (HANDLE)SendMessage(hwndList ,CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem);
		if (hChildItem) 
			SetAllChildrenIcons(hwndList, hChildItem, column, image);

		hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTGROUP, (LPARAM)hItem);
	}

	if (typeOfFirst == CLCIT_CONTACT) 
		hItem = hFirstItem;
	else 
		hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTCONTACT, (LPARAM)hFirstItem);

	while(hItem) 
	{
		int oldIcon = GetExtraImage(hwndList, hItem, column);
		if (oldIcon != EMPTY_EXTRA_ICON && oldIcon != image) 
			SetExtraImage(hwndList, hItem, column, image);

		hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTCONTACT, (LPARAM)hItem);
	}
}

INT_PTR CALLBACK DlgProcFiltering(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) 
{
	static HANDLE hItemAll;
	switch (msg) 
	{
		case WM_INITDIALOG: 
		{
			TranslateDialogDefault(hwndDlg);

			HIMAGELIST hImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16 | ILC_MASK, 3, 3);

			ImageList_AddIcon(hImageList, LoadIcon(hInst,MAKEINTRESOURCE(IDI_SOUND)));
			SendDlgItemMessage(hwndDlg,IDC_SOUNDICON,STM_SETICON, (WPARAM)ImageList_GetIcon(hImageList, EXTRA_IMAGE_SOUND, ILD_NORMAL), 0);
			ImageList_AddIcon(hImageList, LoadIcon(hInst, MAKEINTRESOURCE(IDI_POPUP)));
			SendDlgItemMessage(hwndDlg, IDC_POPUPICON, STM_SETICON, (WPARAM)ImageList_GetIcon(hImageList, EXTRA_IMAGE_POPUP, ILD_NORMAL), 0);
			ImageList_AddIcon(hImageList, LoadIcon(hInst,MAKEINTRESOURCE(IDI_XSTATUS)));
			SendDlgItemMessage(hwndDlg, IDC_XSTATUSICON, STM_SETICON, (WPARAM)ImageList_GetIcon(hImageList, EXTRA_IMAGE_XSTATUS, ILD_NORMAL), 0);
			ImageList_AddIcon(hImageList, LoadIcon(hInst,MAKEINTRESOURCE(IDI_LOGGING)));
			SendDlgItemMessage(hwndDlg, IDC_LOGGINGICON, STM_SETICON, (WPARAM)ImageList_GetIcon(hImageList, EXTRA_IMAGE_LOGGING, ILD_NORMAL), 0);
			ImageList_AddIcon(hImageList, LoadIcon(hInst,MAKEINTRESOURCE(IDI_DISABLEALL)));
			SendDlgItemMessage(hwndDlg, IDC_DISABLEALLICON, STM_SETICON, (WPARAM)ImageList_GetIcon(hImageList, EXTRA_IMAGE_DISABLEALL, ILD_NORMAL), 0);
			ImageList_AddIcon(hImageList, LoadIcon(hInst,MAKEINTRESOURCE(IDI_ENABLEALL)));
			SendDlgItemMessage(hwndDlg, IDC_ENABLEALLICON, STM_SETICON, (WPARAM)ImageList_GetIcon(hImageList, EXTRA_IMAGE_ENABLEALL, ILD_NORMAL), 0);

			ImageList_AddIcon(hImageList, LoadSkinnedIcon(SKINICON_OTHER_SMALLDOT));

			SendDlgItemMessage(hwndDlg, IDC_INDSNDLIST, CLM_SETEXTRAIMAGELIST, 0, (LPARAM)hImageList);
			SendDlgItemMessage(hwndDlg, IDC_INDSNDLIST, CLM_SETEXTRACOLUMNS, 6, 0);

			HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST);
			ResetListOptions(hList);

			CLCINFOITEM cii = {0};
			cii.cbSize = sizeof(cii);
			cii.flags = CLCIIF_GROUPFONT;
			cii.pszText = TranslateT("** All contacts **");
			hItemAll = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_INDSNDLIST, CLM_ADDINFOITEM, 0, (LPARAM)&cii);

			return TRUE;
		}
		case WM_SETFOCUS:
		{
			SetFocus(GetDlgItem(hwndDlg, IDC_INDSNDLIST));
			break;
		}
		case WM_NOTIFY:
		{
			HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST);
			switch(((LPNMHDR)lParam)->idFrom) 
			{
				case IDC_INDSNDLIST:
				switch (((LPNMHDR)lParam)->code)
				{
					case CLN_NEWCONTACT:
					case CLN_LISTREBUILT:
						SetAllContactsIcons(hList);
						//fall through
					case CLN_CONTACTMOVED:
						SetGroupsIcons(hList, (HANDLE)SendMessage(hList, CLM_GETNEXTITEM, CLGN_ROOT, 0), hItemAll, NULL);
						break;
					case CLN_OPTIONSCHANGED:
						ResetListOptions(hList);
						break;
					case NM_CLICK: 
					{
						NMCLISTCONTROL *nm = (NMCLISTCONTROL*)lParam;
						DWORD hitFlags;

						// Make sure we have an extra column
						if (nm->iColumn == -1) break;

						// Find clicked item
						HANDLE hItem = (HANDLE)SendMessage(hList, CLM_HITTEST, (WPARAM)&hitFlags, MAKELPARAM(nm->pt.x, nm->pt.y));
						if (hItem == NULL) break;
						if (!(hitFlags & CLCHT_ONITEMEXTRA)) break;

						int itemType = SendMessage(hList, CLM_GETITEMTYPE, (WPARAM)hItem, 0);

						// Get image in clicked column 
						int image = GetExtraImage(hList, hItem, nm->iColumn);
						if (image == EXTRA_IMAGE_DOT) 
							image = nm->iColumn;
						else if (image >= EXTRA_IMAGE_SOUND && image <= EXTRA_IMAGE_LOGGING) 
							image = EXTRA_IMAGE_DOT;

						// Get item type (contact, group, etc...)
						if (itemType == CLCIT_CONTACT)
						{
							if (image == EXTRA_IMAGE_DISABLEALL)
							{
								for (int i = 0; i < 4; i++) 
									SetExtraImage(hList, hItem, i, EXTRA_IMAGE_DOT);
							}
							else if (image == EXTRA_IMAGE_ENABLEALL)
							{
								for (int i = 0; i < 4; i++) 
									SetExtraImage(hList, hItem, i, i);
							}
							else
							{
								SetExtraImage(hList, hItem, nm->iColumn, image);
							}
						}
						else if (itemType == CLCIT_INFO || itemType == CLCIT_GROUP)
						{
							if (itemType == CLCIT_GROUP)
								hItem = (HANDLE)SendMessage(hList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem);

							if (hItem)
							{
								if (image == EXTRA_IMAGE_DISABLEALL)
								{
									for (int i = 0; i < 4; i++)
										SetAllChildrenIcons(hList, hItem, i, EXTRA_IMAGE_DOT);
								}
								else if (image == EXTRA_IMAGE_ENABLEALL)
								{
									for (int i = 0; i < 4; i++)
										SetAllChildrenIcons(hList, hItem, i, i);
								}
								else 
								{
									SetAllChildrenIcons(hList, hItem, nm->iColumn, image);
								}
							}
						}

						// Update the all/none icons
						SetGroupsIcons(hList, (HANDLE)SendMessage(hList, CLM_GETNEXTITEM, CLGN_ROOT, 0), hItemAll, NULL);
						// Activate Apply button
						SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
						break;
					}
				}
				break;
				case 0:
				switch (((LPNMHDR)lParam)->code)
				{
					case PSN_APPLY: 
					{
						HANDLE hContact = db_find_first();
						do 
						{
							HANDLE hItem = (HANDLE)SendMessage(hList, CLM_FINDCONTACT, (WPARAM)hContact, 0);
							if (hItem)
							{
								if (GetExtraImage(hList, hItem, EXTRA_IMAGE_SOUND) == EXTRA_IMAGE_SOUND) 
									db_unset(hContact, MODULE, "EnableSounds");
								else 
									db_set_b(hContact, MODULE, "EnableSounds", 0);

								if (GetExtraImage(hList, hItem, EXTRA_IMAGE_POPUP) == EXTRA_IMAGE_POPUP) 
									db_unset(hContact, MODULE, "EnablePopups");
								else 
									db_set_b(hContact, MODULE, "EnablePopups", 0);

								if (GetExtraImage(hList, hItem, EXTRA_IMAGE_XSTATUS) == EXTRA_IMAGE_XSTATUS) 
									db_unset(hContact, MODULE, "EnableXStatusNotify");
								else
									db_set_b(hContact, MODULE, "EnableXStatusNotify", 0);

								if (GetExtraImage(hList, hItem, EXTRA_IMAGE_LOGGING) == EXTRA_IMAGE_LOGGING) 
									db_unset(hContact, MODULE, "EnableLogging");
								else
									db_set_b(hContact, MODULE, "EnableLogging", 0);

							}
						} while(hContact = db_find_next(hContact));

						return TRUE;
					}
				}
				break;
			}
			break;
		}
		case WM_DESTROY: 
		{
			HIMAGELIST hImageList = (HIMAGELIST)SendMessage(GetDlgItem(hwndDlg, IDC_INDSNDLIST), CLM_GETEXTRAIMAGELIST, 0, 0);
			for (int i = 0; i < ImageList_GetImageCount(hImageList); i++)
				DestroyIcon(ImageList_GetIcon(hImageList, i, ILD_NORMAL));
			ImageList_Destroy(hImageList);
			break;
		}
	}
	return FALSE;
}