#include "main.h"
#include "./ratingMenuCustomizer.h"
#include "./ifc_skinhelper.h"
#include "./ifc_skinnedrating.h"

#include "../Plugins/General/gen_ml/ml_ipc_0313.h"

#define RATING_MINSPACECX		16

RatingMenuCustomizer::RatingMenuCustomizer(HMENU hMenu, ifc_skinnedrating *skinnedRating) 
	: ref(1), menu(hMenu), skin(skinnedRating)
{
	if (NULL != skin) 
		skin->AddRef();
}

RatingMenuCustomizer::~RatingMenuCustomizer()
{
	if (NULL != skin)
		skin->Release();
}

HRESULT RatingMenuCustomizer::CreateInstance(HMENU hMenu, ifc_skinnedrating *skinnedRating, RatingMenuCustomizer **instance)
{
	if (NULL == instance) return E_POINTER;
	*instance = NULL;
	
	if (NULL == hMenu || NULL == skinnedRating) return E_INVALIDARG;
	
	*instance = new RatingMenuCustomizer(hMenu, skinnedRating);
	if (NULL == *instance) return E_OUTOFMEMORY;

	return S_OK;
}

size_t RatingMenuCustomizer::AddRef()
{
	return InterlockedIncrement((LONG*)&ref);
}

size_t RatingMenuCustomizer::Release()
{
	if (0 == ref)
		return ref;
	
	LONG r = InterlockedDecrement((LONG*)&ref);
	if (0 == r)
		delete(this);
	
	return r;
}

int RatingMenuCustomizer::QueryInterface(GUID interface_guid, void **object)
{
	if (NULL == object) return E_POINTER;

	if (IsEqualIID(interface_guid, IFC_MenuCustomizer))
		*object = static_cast<ifc_menucustomizer*>(this);
	else
	{
		*object = NULL;
		return E_NOINTERFACE;
	}

	if (NULL == *object)
		return E_UNEXPECTED;

	AddRef();
	return S_OK;
}


INT RatingMenuCustomizer::CustomDraw(HMENU menuInstance, INT action, HDC hdc, LPARAM param)
{
	if (menuInstance != menu) 
		return FALSE;

	switch(action)
	{
		case MLMENU_ACTION_MEASUREITEM:	return MeasureRating(hdc, (MEASUREITEMSTRUCT*)param);
		case MLMENU_ACTION_DRAWITEM:		return MLMENU_WANT_DRAWPART;
		case MLMENU_ACTION_DRAWBACK:		break;
		case MLMENU_ACTION_DRAWICON:		break;
		case MLMENU_ACTION_DRAWTEXT:		return DrawRating(hdc, (DRAWITEMSTRUCT*)param);
	}

	return FALSE;
}

HRESULT RatingMenuCustomizer::GetValue(INT itemId, INT *valueOut)
{
	if (NULL == menu) return E_UNEXPECTED;

	WCHAR szBuffer[32] = {0};
	INT cchBuffer = GetMenuStringW(menu, itemId, szBuffer, ARRAYSIZE(szBuffer), MF_BYCOMMAND);
	if (cchBuffer < 1 || cchBuffer > 5) 
        return E_INVALIDARG;
	
	for (INT i = 1; i < cchBuffer; i++)
	{
		if (szBuffer[i -1] != szBuffer[i])
			return E_INVALIDARG;
	}

	if (NULL != valueOut)
		*valueOut = cchBuffer;

	return S_OK;
}

INT RatingMenuCustomizer::MeasureRating(HDC hdc, MEASUREITEMSTRUCT *pmis)
{
	RECT rect;
	if (NULL == skin || NULL == hdc || 
		FAILED(GetValue(pmis->itemID, NULL)) || 
		FAILED(skin->CalcMinRect(5, &rect)))
	{
		return FALSE;
	}
	
	pmis->itemHeight = rect.bottom - rect.top + 6;
	
	TEXTMETRIC tm;
	if (GetTextMetrics(hdc, &tm) && 
		(UINT)(tm.tmHeight + 2) > pmis->itemHeight)
	{
		pmis->itemHeight = tm.tmHeight + 2;
	}
				
	INT spaceCX = (pmis->itemHeight > RATING_MINSPACECX) ? pmis->itemHeight : RATING_MINSPACECX;
	pmis->itemWidth = rect.right - rect.left + (2 * spaceCX) - (GetSystemMetrics(SM_CXMENUCHECK) - 1);

	return TRUE;
}

INT RatingMenuCustomizer::DrawRating(HDC hdc, DRAWITEMSTRUCT *pdis)
{
	INT value;
	if (NULL == skin || NULL == hdc || FAILED(GetValue(pdis->itemID, &value)))
		return FALSE;

	INT spaceCX = ((pdis->rcItem.bottom - pdis->rcItem.top) > RATING_MINSPACECX) ? 
					(pdis->rcItem.bottom - pdis->rcItem.top) : 
					RATING_MINSPACECX;

	RECT rect;
	CopyRect(&rect, &pdis->rcItem);
	rect.left += spaceCX;
	
	UINT menuState = GetMenuState(menu, pdis->itemID, MF_BYCOMMAND);
	UINT trackingValue = (0 == ((MF_DISABLED | MF_GRAYED) & menuState)) ? value : 0;
	
	return SUCCEEDED(skin->Draw(hdc, 5, value, trackingValue, &rect, RDS_LEFT | RDS_VCENTER | RDS_HOT));
}

#define CBCLASS RatingMenuCustomizer
START_DISPATCH;
  CB(API_CUSTOMDRAW, CustomDraw);
END_DISPATCH;
#undef CBCLASS