// OXShdWnd.cpp : implementation file
//

#include "stdafx.h"
#include "OXShdWnd.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


const int m_giFirst = 5;
const int m_giSecond = 5;

/////////////////////////////////////////////////////////////////////////////
// COXShdWnd

COXShdWnd::COXShdWnd()
{
	m_pCastingWindow = NULL;
}

COXShdWnd::~COXShdWnd()
{
}


BEGIN_MESSAGE_MAP(COXShdWnd, CWnd)
	//{{AFX_MSG_MAP(COXShdWnd)
	ON_WM_WINDOWPOSCHANGED()
	ON_WM_ERASEBKGND()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// COXShdWnd message handlers

//DEL void COXShdWnd::OnPaint() 
//DEL {
//DEL 	CPaintDC dc(this); // device context for painting
//DEL 	
//DEL 	CRect rect;
//DEL 	GetWindowRect(rect);
//DEL 
//DEL 	DrawShadow(dc.m_hDC, rect, NULL);
//DEL }

COLORREF COXShdWnd::DarkenColor(long lScale, COLORREF lColor)
{ 
	long R = MulDiv(GetRValue(lColor), (255 - lScale), 255);
	long G = MulDiv(GetGValue(lColor), (255 - lScale), 255);
	long B = MulDiv(GetBValue(lColor), (255 - lScale), 255);

	return RGB(R, G, B); 
}

// Wrapper function for ::GetPixel(...) that facilitates the shadow buffering
COLORREF COXShdWnd::GetShadowPixel(HDC hDC, int iXPos, int iYPos, bool bUseSavedShadow)
{
	if (bUseSavedShadow)
		return 0; // we don't need this pixel

	return ::GetPixel(hDC, iXPos, iYPos);
};

// Wrapper function for ::SetPixelV(...) that facilitates the shadow buffering
void COXShdWnd::SetShadowPixel(HDC hDC, int iXPos, int iYPos, COLORREF clr, bool bSaveShadow, bool bUseSavedShadow, OXSHADOWARRAY* pShadowArray, int& iIndex)
{
	if (bUseSavedShadow)
		::SetPixelV(hDC, iXPos, iYPos, pShadowArray->GetAt(iIndex++));
	else
		::SetPixelV(hDC, iXPos, iYPos, clr);

	if (bSaveShadow)
		pShadowArray->Add(clr);

//	AddPixelToMap(iXPos, iYPos, clr);
};

// Draws a menu shadow for the given rectangle
void COXShdWnd::DrawShadow(HDC hDC, LPRECT lpRect, OXSHADOWARRAY* pShadowArray)
{

	int iArrayIndex = 0;
	bool bSaveShadow, bUseSavedShadow;
	if (pShadowArray == NULL)
	{
		// We don't need to use the shadow array
		bSaveShadow = false;
		bUseSavedShadow = false;
	}
	else if (pShadowArray->GetSize() == 0)
	{
		// Save the shadow in the array
		bSaveShadow = true;
		bUseSavedShadow = false;
	}
	else
	{
		// Use the shadow from the array
		bSaveShadow = false;
		bUseSavedShadow = true;
	}

	CRect rectWindow(lpRect);

	// Draw the shadow - get the pixels from the desktop, darken them
	// and place them on the popup window
	HDC hDesktopDC = ::GetWindowDC(::GetDesktopWindow());

	// copy desktop to mem DC and work with that for Get/Set pixel (Vista bug)
	CDC* pDC = CDC::FromHandle(hDesktopDC);

	CDC dcMem;
	dcMem.CreateCompatibleDC(pDC);
	CBitmap bitmap;
	bitmap.CreateCompatibleBitmap(pDC, rectWindow.Width(), rectWindow.Height());
	CBitmap *pOldBitmap = dcMem.SelectObject(&bitmap);
	
	// working with a mem bitmap at 0,0 for GetPixel
	dcMem.BitBlt(0,0, rectWindow.Width(), rectWindow.Height(), pDC, rectWindow.left, rectWindow.top, SRCCOPY);

	int x, y;
	CPoint pt;
	COLORREF clr;

	int iLeft = 4;	
	int iTop =  4;
	int iRight = rectWindow.Width();
	int iBottom = rectWindow.Height();

	// Right shadow 
	for (x = 1; x <= 4; x++)
	{ 
		// Copy the top right pixels
		for (y = 1; y <= 4; y++)
		{
			pt.x = iRight - x;
			pt.y = iTop + y - 4 - 1;
			clr = GetShadowPixel(dcMem.m_hDC, pt.x, pt.y, bUseSavedShadow);
			SetShadowPixel(hDC, pt.x, pt.y, clr, bSaveShadow, bUseSavedShadow, pShadowArray, iArrayIndex);
		}

		// Top right corner
		for (y = 4; y >= 1; y--)
		{
			pt.x = iRight - x;
			pt.y = iTop + y - 1;
			clr = GetShadowPixel(dcMem.m_hDC, pt.x, pt.y, bUseSavedShadow);
			SetShadowPixel(hDC, pt.x, pt.y, DarkenColor(3 * x * y, clr), bSaveShadow, bUseSavedShadow, pShadowArray, iArrayIndex);
		}

		// Vertical line
		for (y = iTop + 4; y <= iBottom - 4 - 1; y++)
		{
			pt.x = iRight - x;
			pt.y = y;
			clr = GetShadowPixel(dcMem.m_hDC, pt.x, pt.y, bUseSavedShadow);
			SetShadowPixel(hDC, pt.x, pt.y, DarkenColor(15 * x, clr), bSaveShadow, bUseSavedShadow, pShadowArray, iArrayIndex);
		}

		// Bottom right corner
		for (y = 1; y <= 4; y++)
		{
			pt.x = iRight - x;
			pt.y = iBottom - y;
			clr = GetShadowPixel(dcMem.m_hDC,  pt.x, pt.y, bUseSavedShadow);
			SetShadowPixel(hDC, pt.x, pt.y, DarkenColor(3 * x * y,  clr), bSaveShadow, bUseSavedShadow, pShadowArray, iArrayIndex);
		}
	} 

	// Bottom shadow
	for (y = 1; y <= 4; y++)
	{
		// Copy the bottom left pixels
		for (x = 1; x <= 4; x++)
		{
			pt.x = iLeft - x;
			pt.y = iBottom - y;
			clr = GetShadowPixel(dcMem.m_hDC, pt.x, pt.y, bUseSavedShadow);
			SetShadowPixel(hDC, pt.x, pt.y, clr, bSaveShadow, bUseSavedShadow, pShadowArray, iArrayIndex);
		}

		// Bottom left corner
		for (x = 1; x <= 4; x++)
		{
			pt.x = iLeft - x + 4;
			pt.y = iBottom - y;
			clr = GetShadowPixel(dcMem.m_hDC, pt.x, pt.y, bUseSavedShadow);
			SetShadowPixel(hDC, pt.x, pt.y, DarkenColor(3 * (5 - x) * y, clr), bSaveShadow, bUseSavedShadow, pShadowArray, iArrayIndex);
		}
		
		// Horizontal line
		for (x = iLeft + 4; x <= iRight - 5; x++)
		{
			pt.x = x;
			pt.y = iBottom - y;
			clr = GetShadowPixel(dcMem.m_hDC, pt.x, pt.y, bUseSavedShadow);
			SetShadowPixel(hDC, pt.x, pt.y, DarkenColor(15 * y, clr), bSaveShadow, bUseSavedShadow, pShadowArray, iArrayIndex);
		}
	} 
	// done with bitmap here
	dcMem.SelectObject(pOldBitmap);


	::ReleaseDC(0, hDesktopDC);


}

void COXShdWnd::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos) 
{
	CWnd::OnWindowPosChanged(lpwndpos);
	
	// TODO: Add your message handler code here
//Invalidate();

	
}

BOOL COXShdWnd::OnEraseBkgnd(CDC* pDC) 
{
    // handle pending WM_PAINT messages
    MSG msg;
    while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_NOREMOVE))
	{
//		if (!GetMessage(&msg, NULL, WM_PAINT, WM_PAINT))
//			return FALSE;
		ASSERT(msg.message == WM_PAINT);
        DispatchMessage(&msg);
	}

	CRect rect;
	GetWindowRect(rect);

	DrawShadow(pDC->m_hDC, rect, NULL);

//	if (m_pCastingWindow != NULL)
//		::SetWindowPos(m_hWnd, m_pCastingWindow->m_hWnd, 0, 0, 0, 0, 
//			SWP_NOSENDCHANGING | SWP_NOMOVE | SWP_NOSIZE);

	return FALSE;
}


void COXShdWnd::SetCastingWindow(CWnd* pWnd)
{
	m_pCastingWindow = pWnd;
}
