#include "commonheaders.h"

#define DEFAULT_BKCOLOUR      GetSysColor(COLOR_3DFACE)
#define DEFAULT_USEBITMAP     0
#define DEFAULT_BKBMPUSE      CLB_STRETCH
#define DEFAULT_SELBKCOLOUR   GetSysColor(COLOR_HIGHLIGHT)


extern HINSTANCE g_hInst;

char **bkgrList = NULL;
int bkgrCount = 0;
HANDLE hEventBkgrChanged;

#define M_BKGR_UPDATE	(WM_USER+10)
#define M_BKGR_SETSTATE	(WM_USER+11)
#define M_BKGR_GETSTATE	(WM_USER+12)

#define M_BKGR_BACKCOLOR	0x01
#define M_BKGR_SELECTCOLOR	0x02
#define M_BKGR_ALLOWBITMAPS	0x04
#define M_BKGR_STRETCH		0x08
#define M_BKGR_TILE			0x10

#define ARRAY_SIZE(arr)	(sizeof(arr)/sizeof(arr[0]))
static const int bitmapRelatedControls[] = {
	IDC_FILENAME,IDC_BROWSE,IDC_STRETCHH,IDC_STRETCHV,IDC_TILEH,IDC_TILEV,
	IDC_SCROLL,IDC_PROPORTIONAL,IDC_TILEVROWH
};
struct BkgrItem
{
	BYTE changed;
	BYTE useBitmap;
	COLORREF bkColor, selColor;
	char filename[MAX_PATH];
	WORD flags;
};
struct BkgrData
{
	struct BkgrItem *item;
	int indx;
	int count;
};
static INT_PTR CALLBACK DlgProcBkgOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
	struct BkgrData *dat = (struct BkgrData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
	switch (msg)
	{
		case WM_INITDIALOG:
		{
			int indx;
			HWND hList = GetDlgItem(hwndDlg, IDC_BKGRLIST);
			TranslateDialogDefault(hwndDlg);

			dat = (struct BkgrData*)mir_alloc(sizeof(struct BkgrData));
			SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat);
			dat->count = bkgrCount;
			dat->item = (struct BkgrItem*)mir_alloc(sizeof(struct BkgrItem)*dat->count);
			dat->indx = CB_ERR;
			for (indx = 0; indx < dat->count; indx++)
			{
				char *module = bkgrList[indx] + strlen(bkgrList[indx]) + 1;
				int jndx;

				dat->item[indx].changed = FALSE;
				dat->item[indx].useBitmap = DBGetContactSettingByte(NULL,module, "UseBitmap", DEFAULT_USEBITMAP);
				dat->item[indx].bkColor = DBGetContactSettingDword(NULL,module, "BkColour", DEFAULT_BKCOLOUR);
				dat->item[indx].selColor = DBGetContactSettingDword(NULL,module, "SelBkColour", DEFAULT_SELBKCOLOUR);
				{	
					DBVARIANT dbv;
					if (!DBGetContactSettingString(NULL,module,"BkBitmap",&dbv))
					{
						int retval = CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)dbv.pszVal, (LPARAM)dat->item[indx].filename);
						if (!retval || retval == CALLSERVICE_NOTFOUND)
							lstrcpynA(dat->item[indx].filename, dbv.pszVal, MAX_PATH);
						mir_free(dbv.pszVal);
					}
					else
						*dat->item[indx].filename = 0;
				}
				dat->item[indx].flags = DBGetContactSettingWord(NULL,module,"BkBmpUse", DEFAULT_BKBMPUSE);
				jndx = SendMessageA(hList, CB_ADDSTRING, 0, (LPARAM)Translate(bkgrList[indx]));
				SendMessage(hList, CB_SETITEMDATA, jndx, indx);
			}
			SendMessage(hList, CB_SETCURSEL, 0, 0);
			PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_BKGRLIST, CBN_SELCHANGE), 0);
			{
				HRESULT (STDAPICALLTYPE *MySHAutoComplete)(HWND,DWORD);
				MySHAutoComplete = (HRESULT (STDAPICALLTYPE*)(HWND,DWORD))GetProcAddress(GetModuleHandleA("shlwapi"),"SHAutoComplete");
				if (MySHAutoComplete) MySHAutoComplete(GetDlgItem(hwndDlg,IDC_FILENAME),1);
			}
			return TRUE;
		}
		case WM_DESTROY:
			if (dat)
			{
				if (dat->item) mir_free(dat->item);
				mir_free(dat);
			}
		
			return TRUE;

		case M_BKGR_GETSTATE:
		{
			int indx = wParam;
			if (indx == CB_ERR || indx >= dat->count) break;
			indx = SendDlgItemMessage(hwndDlg, IDC_BKGRLIST, CB_GETITEMDATA, indx, 0);

			dat->item[indx].useBitmap = IsDlgButtonChecked(hwndDlg,IDC_BITMAP);
			dat->item[indx].bkColor = SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_GETCOLOUR,0,0);
			dat->item[indx].selColor = SendDlgItemMessage(hwndDlg, IDC_SELCOLOUR, CPM_GETCOLOUR,0,0);
			GetDlgItemTextA(hwndDlg, IDC_FILENAME, dat->item[indx].filename, sizeof(dat->item[indx].filename));
			{
				WORD flags = 0;
				if (IsDlgButtonChecked(hwndDlg,IDC_STRETCHH)) flags |= CLB_STRETCHH;
				if (IsDlgButtonChecked(hwndDlg,IDC_STRETCHV)) flags |= CLB_STRETCHV;
				if (IsDlgButtonChecked(hwndDlg,IDC_TILEH)) flags |= CLBF_TILEH;
				if (IsDlgButtonChecked(hwndDlg,IDC_TILEV)) flags |= CLBF_TILEV;
				if (IsDlgButtonChecked(hwndDlg,IDC_SCROLL)) flags |= CLBF_SCROLL;
				if (IsDlgButtonChecked(hwndDlg,IDC_PROPORTIONAL)) flags |= CLBF_PROPORTIONAL;
				if (IsDlgButtonChecked(hwndDlg,IDC_TILEVROWH)) flags |= CLBF_TILEVTOROWHEIGHT;
				dat->item[indx].flags = flags;
			}	
			break;
		}
		case M_BKGR_SETSTATE:
		{
			int indx = wParam;
			int flags = dat->item[indx].flags;
			if (indx == CB_ERR || indx >= dat->count) break;
			indx = SendDlgItemMessage(hwndDlg, IDC_BKGRLIST, CB_GETITEMDATA, indx, 0);

			CheckDlgButton(hwndDlg, IDC_BITMAP, dat->item[indx].useBitmap?BST_CHECKED:BST_UNCHECKED);

			SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_SETDEFAULTCOLOUR, 0, DEFAULT_BKCOLOUR);
			SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_SETCOLOUR, 0, dat->item[indx].bkColor);
			SendDlgItemMessage(hwndDlg, IDC_SELCOLOUR, CPM_SETDEFAULTCOLOUR, 0, DEFAULT_SELBKCOLOUR);
			SendDlgItemMessage(hwndDlg, IDC_SELCOLOUR, CPM_SETCOLOUR, 0, dat->item[indx].selColor);
			SetDlgItemTextA(hwndDlg, IDC_FILENAME, dat->item[indx].filename);	

			CheckDlgButton(hwndDlg,IDC_STRETCHH, flags&CLB_STRETCHH?BST_CHECKED:BST_UNCHECKED);
			CheckDlgButton(hwndDlg,IDC_STRETCHV,flags&CLB_STRETCHV?BST_CHECKED:BST_UNCHECKED);
			CheckDlgButton(hwndDlg,IDC_TILEH,flags&CLBF_TILEH?BST_CHECKED:BST_UNCHECKED);
			CheckDlgButton(hwndDlg,IDC_TILEV,flags&CLBF_TILEV?BST_CHECKED:BST_UNCHECKED);
			CheckDlgButton(hwndDlg,IDC_SCROLL,flags&CLBF_SCROLL?BST_CHECKED:BST_UNCHECKED);
			CheckDlgButton(hwndDlg,IDC_PROPORTIONAL,flags&CLBF_PROPORTIONAL?BST_CHECKED:BST_UNCHECKED);
			CheckDlgButton(hwndDlg,IDC_TILEVROWH,flags&CLBF_TILEVTOROWHEIGHT?BST_CHECKED:BST_UNCHECKED);

			SendMessage(hwndDlg, M_BKGR_UPDATE, 0,0);
			break;
		}
		case M_BKGR_UPDATE:
		{
			int isChecked = IsDlgButtonChecked(hwndDlg,IDC_BITMAP);
			int indx;
			for (indx = 0; indx < ARRAY_SIZE(bitmapRelatedControls); indx++)
				EnableWindow(GetDlgItem(hwndDlg, bitmapRelatedControls[indx]),isChecked);
			break;
		}
		case WM_COMMAND:
			if (LOWORD(wParam) == IDC_BROWSE) {
				char str[MAX_PATH];
				OPENFILENAMEA ofn = {0};
				char filter[512];

				GetDlgItemTextA(hwndDlg,IDC_FILENAME, str, sizeof(str));
				ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
				ofn.hwndOwner = hwndDlg;
				ofn.hInstance = NULL;
				CallService(MS_UTILS_GETBITMAPFILTERSTRINGS, sizeof(filter), (LPARAM)filter);
				ofn.lpstrFilter = filter;
				ofn.lpstrFile = str;
				ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
				ofn.nMaxFile = sizeof(str);
				ofn.nMaxFileTitle = MAX_PATH;
				ofn.lpstrDefExt = "bmp";
				if (!GetOpenFileNameA(&ofn)) break;
				SetDlgItemTextA(hwndDlg, IDC_FILENAME, str);
			}
			else if (LOWORD(wParam) == IDC_FILENAME && HIWORD(wParam) != EN_CHANGE) 
				break;

			if (LOWORD(wParam) == IDC_BITMAP)
				SendMessage(hwndDlg, M_BKGR_UPDATE, 0,0);
			if (LOWORD(wParam) == IDC_FILENAME && (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus()))
				return 0;
			if (LOWORD(wParam) == IDC_BKGRLIST) {
				if (HIWORD(wParam) == CBN_SELCHANGE) {
					SendMessage(hwndDlg, M_BKGR_GETSTATE, dat->indx, 0);
					SendMessage(hwndDlg, M_BKGR_SETSTATE, dat->indx = SendDlgItemMessage(hwndDlg, IDC_BKGRLIST, CB_GETCURSEL, 0,0), 0);
				}
				return 0;
			}
			{
				int indx = SendDlgItemMessage(hwndDlg, IDC_BKGRLIST, CB_GETCURSEL, 0,0);
				if (indx != CB_ERR && indx < dat->count) {
					indx = SendDlgItemMessage(hwndDlg, IDC_BKGRLIST, CB_GETITEMDATA, indx, 0);					
					dat->item[indx].changed = TRUE;
				
				}							
				SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0,0);
			}
			break;
		case WM_NOTIFY:
			switch(((LPNMHDR)lParam)->idFrom)
			{
				case 0:
					switch (((LPNMHDR)lParam)->code)
					{
						case PSN_APPLY:
						{
							int indx;
							SendMessage(hwndDlg, M_BKGR_GETSTATE, SendDlgItemMessage(hwndDlg, IDC_BKGRLIST, CB_GETCURSEL, 0,0), 0);
							for (indx = 0; indx < dat->count; indx++)
							if (dat->item[indx].changed)
							{
								char *module = bkgrList[indx] + strlen(bkgrList[indx]) + 1;
								DBWriteContactSettingByte(NULL, module, "UseBitmap", (BYTE)dat->item[indx].useBitmap);
								{	
									COLORREF col;

									if ((col = dat->item[indx].bkColor) == DEFAULT_BKCOLOUR)
										DBDeleteContactSetting(NULL, module, "BkColour");
									else
										DBWriteContactSettingDword(NULL, module, "BkColour", col);

									if ((col = dat->item[indx].selColor) == DEFAULT_SELBKCOLOUR)
										DBDeleteContactSetting(NULL, module, "SelBkColour");
									else
										DBWriteContactSettingDword(NULL, module, "SelBkColour", col);
								}
								{
									char str[MAX_PATH];
									int retval = CallService(MS_UTILS_PATHTOABSOLUTE,
										(WPARAM)dat->item[indx].filename,
										(LPARAM)str);
									if (!retval || retval == CALLSERVICE_NOTFOUND)
										DBWriteContactSettingString(NULL, module, "BkBitmap", dat->item[indx].filename);
									else
										DBWriteContactSettingString(NULL, module, "BkBitmap", str);
								}
								DBWriteContactSettingWord(NULL, module, "BkBmpUse", dat->item[indx].flags);
								dat->item[indx].changed = FALSE;
								NotifyEventHooks(hEventBkgrChanged, (WPARAM)module, 0);
							}
							return TRUE;
						}
					}
					break;
			}
			break;
	}
	return FALSE;
}

static INT_PTR BkgrCfg_Register(WPARAM wParam,LPARAM lParam)
{
	char *szSetting = (char *)wParam;
	char *value, *tok;
	size_t len = strlen(szSetting) + 1;

	value = (char *)mir_alloc(len + 4); // add room for flags (DWORD)
	memcpy(value, szSetting, len);
	tok = strchr(value, '/');
	if (tok == NULL) {
		mir_free(value);
		return 1;
	}
	*tok = 0;
	*(DWORD*)(value + len) = lParam;

	bkgrList = (char **)mir_realloc(bkgrList, sizeof(char*)*(bkgrCount+1));
	bkgrList[bkgrCount] = value;
	bkgrCount++;
	
	return 0;
}

int OnOptionsInit(WPARAM wParam,LPARAM lParam)
{
	OPTIONSDIALOGPAGE odp = { 0 };
	odp.cbSize = sizeof(odp);
	odp.hInstance = g_hInst;
	odp.pszGroup = LPGEN("Customize");
	odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_CLCBKG2);
	odp.pszTitle = LPGEN("Backgrounds");
	odp.pfnDlgProc = DlgProcBkgOpts;
	odp.flags = ODPF_BOLDGROUPS;
	Options_AddPage(wParam, &odp);

	return 0;
}

int BGModuleLoad()
{	
	HookEvent(ME_OPT_INITIALISE, OnOptionsInit);

	CreateServiceFunction(MS_BACKGROUNDCONFIG_REGISTER, BkgrCfg_Register);

	hEventBkgrChanged = CreateHookableEvent(ME_BACKGROUNDCONFIG_CHANGED);
	return 0;
}

int BGModuleUnload(void)
{
	if (bkgrList != NULL)
	{
		int indx;
		for (indx = 0; indx < bkgrCount; indx++)
			if (bkgrList[indx] != NULL)
				mir_free(bkgrList[indx]);
		mir_free(bkgrList);
	}
	DestroyHookableEvent(hEventBkgrChanged);

	return 0;
}