#include "main.h"
#include "./stockobjects.h"
#include "./colors.h"


typedef struct MlStockObjects
{
	CRITICAL_SECTION lock;
	HDC cachedDc;
	HFONT skinFont;
	HFONT systemFont;
	HBRUSH brushes[BRUSH_MAX - BRUSH_MIN + 1];
	HPEN pens[PEN_MAX - PEN_MIN + 1];
} MlStockObjects;

static MlStockObjects stockObjects;

static void 
MlStockObjects_ResetEx(MlStockObjects *self)
{
	INT index;
	if (NULL != self->cachedDc) 
	{
		DeleteDC(self->cachedDc); 
		self->cachedDc = NULL;
	}

	if (NULL != self->skinFont) 
	{
		DeleteObject(self->skinFont); 
		self->skinFont = NULL;
	}

	if (NULL != self->systemFont)
	{
		DeleteObject(self->systemFont);
		self->systemFont = NULL;
	}
	
	for (index = 0; index < ARRAYSIZE(self->brushes); index++) 
	{ 
		if (NULL != self->brushes[index]) 
			DeleteObject(self->brushes[index]); 
	}
	ZeroMemory(self->brushes, sizeof(self->brushes));

	for (index = 0; index < ARRAYSIZE(self->pens); index++) 
	{ 
		if (NULL != self->pens[index]) 
			DeleteObject(self->pens[index]); 
	}
	ZeroMemory(self->pens, sizeof(self->pens));

}

static BYTE 
MlStockObjects_GetSysFontQuality()
{
	BOOL smoothingEnabled;
	if (FALSE == SystemParametersInfoW(SPI_GETFONTSMOOTHING, 0, &smoothingEnabled, 0) ||
		FALSE == smoothingEnabled)
	{
		return DEFAULT_QUALITY;
	}
    
	UINT smootingType;
    if (FALSE == SystemParametersInfoW(SPI_GETFONTSMOOTHINGTYPE, 0, &smootingType, 0))
		return DEFAULT_QUALITY;
	    
	if (FE_FONTSMOOTHINGCLEARTYPE == smootingType)
			return CLEARTYPE_QUALITY;

	return ANTIALIASED_QUALITY;
}

static HDC 
MlStockObjects_GetCachedDc(MlStockObjects *self)
{
	if (NULL == self->cachedDc) 
	{
		HDC baseDC = GetDCEx(g_hwnd, NULL, DCX_WINDOW | DCX_CACHE | DCX_NORESETATTRS);
		self->cachedDc = CreateCompatibleDC(baseDC);
		ReleaseDC(g_hwnd, baseDC);
	}
	return self->cachedDc;
}

static HFONT 
MlStockObjects_GetSkinFont(MlStockObjects *self)
{		
	if (NULL == self->skinFont &&
		NULL != g_config && 
		0 != g_config->ReadInt(L"plfont_everywhere", 1))
	{
		INT height = (INT)SendMessageW(plugin.hwndParent, WM_WA_IPC, 3, IPC_GET_GENSKINBITMAP);
		DWORD charset = (DWORD)SendMessageW(plugin.hwndParent, WM_WA_IPC, 2, IPC_GET_GENSKINBITMAP);
		char *fontname = (char*)SendMessageW(plugin.hwndParent, WM_WA_IPC, 1, IPC_GET_GENSKINBITMAP);
		self->skinFont = CreateFontA(-height, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, charset, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DRAFT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontname);
	}

	return self->skinFont;
}


static HFONT
MlStockObjects_GetSystemFont(MlStockObjects *self)
{		
	if (NULL == self->systemFont)
	{
		LOGFONTW lf;
	
		if (FALSE == SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0))
			return NULL;
	
		lf.lfQuality = MlStockObjects_GetSysFontQuality();
		self->systemFont = CreateFontIndirectW(&lf);
	}

	return  self->systemFont;
}

static HBRUSH 
MlStockObjects_GetBrush(MlStockObjects *self, UINT type)
{	
	if (NULL == self->brushes[type - BRUSH_MIN]) 
	{
		INT color;
		switch(type)
		{
			case WNDBCK_BRUSH:		color = WADLG_WNDBG; break;
			case ITEMBCK_BRUSH:		color = WADLG_ITEMBG; break;
			case HILITE_BRUSH:		color = WADLG_HILITE; break;
			case ITEMTEXT_BRUSH:	color = WADLG_ITEMFG; break;
			default:				return NULL;
		}
		self->brushes[type - BRUSH_MIN] = CreateSolidBrush(WADlg_getColor(color));
	}
	return self->brushes[type - BRUSH_MIN];
}

static HPEN 
MlStockObjects_GetPen(MlStockObjects *self, UINT type)
{	
	if (NULL == self->pens[type - PEN_MIN]) 
	{
		COLORREF rgb;
		switch(type)
		{
			case HILITE_PEN:		rgb = WADlg_getColor(WADLG_HILITE); break;
			case HEADERTOP_PEN:		rgb = WADlg_getColor(WADLG_LISTHEADER_FRAME_TOPCOLOR); break;
			case HEADERMIDDLE_PEN:	rgb = WADlg_getColor(WADLG_LISTHEADER_FRAME_MIDDLECOLOR); break;
			case HEADERBOTTOM_PEN:	rgb = WADlg_getColor(WADLG_LISTHEADER_FRAME_BOTTOMCOLOR); break;
			case WNDBCK_PEN:		rgb = WADlg_getColor(WADLG_WNDBG); break;
			case MENUBORDER_PEN:	MLGetSkinColor(MLSO_MENU, MP_FRAME, 0, &rgb); break;
			case TOOLTIPBORDER_PEN:	MLGetSkinColor(MLSO_TOOLTIP, TTP_FRAME, 0, &rgb); break;
			case ITEMBCK_PEN:		rgb = WADlg_getColor(WADLG_ITEMBG); break;
			case ITEMTEXT_PEN:		rgb = WADlg_getColor(WADLG_ITEMFG); break;
			default:				return NULL;
		}
		self->pens[type - PEN_MIN] = CreatePen(PS_SOLID, 0, rgb);
	}

	return self->pens[type - PEN_MIN];
}

static HANDLE 
MlStockObjects_GetEx(MlStockObjects *self, UINT type)
{
	HANDLE handle;
	EnterCriticalSection(&self->lock);

	if (CACHED_DC == type)
		handle = MlStockObjects_GetCachedDc(self);
	else if (SKIN_FONT == type) 
		handle = MlStockObjects_GetSkinFont(self);
	else if (DEFAULT_FONT == type) 
		handle = MlStockObjects_GetSystemFont(self);
	else if (BRUSH_MIN <= type && BRUSH_MAX >= type) 
		handle = MlStockObjects_GetBrush(self, type);
	else if (PEN_MIN <= type && PEN_MAX >= type) 
		handle = MlStockObjects_GetPen(self, type);
	else
		handle = NULL;

	LeaveCriticalSection(&self->lock);

	return handle;
}


void
MlStockObjects_Init()
{
	ZeroMemory(&stockObjects, sizeof(MlStockObjects));
	InitializeCriticalSection(&stockObjects.lock);
}

void
MlStockObjects_Free()
{
	MlStockObjects_ResetEx(&stockObjects);
	DeleteCriticalSection(&stockObjects.lock);
}

HANDLE 
MlStockObjects_Get(UINT type)
{
	return MlStockObjects_GetEx(&stockObjects, type);
}

void
MlStockObjects_Reset()
{
	MlStockObjects_ResetEx(&stockObjects);
}