#include "headers.h"

#define WNDCLASSNAME _T("W7DwmWndClass")

CDwmWindow::CDwmWindow()
{
	GlobalInitWndClass();

	m_btnInitialized = false;
	m_btnCount = 0;
	for (int i = 0; i < SIZEOF(m_btnInfo); ++i)
	{
		m_btnInfo[i].iId = i;
		m_btnInfo[i].dwMask = THUMBBUTTONMASK(THB_FLAGS);
		m_btnInfo[i].dwFlags = THUMBBUTTONFLAGS(THBF_HIDDEN);
		m_btnData[i] = 0;
	}

	m_hwnd = CreateWindowEx(WS_EX_APPWINDOW|WS_EX_NOACTIVATE, WNDCLASSNAME, NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, NULL, g_hInst, NULL);
	SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this);
	SetWindowPos(m_hwnd, 0, -100000, -100000, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_SHOWWINDOW);

	BOOL val = 1;
	DwmSetWindowAttribute(m_hwnd, DWMWA_HAS_ICONIC_BITMAP, &val, 4);
	DwmSetWindowAttribute(m_hwnd, DWMWA_FORCE_ICONIC_REPRESENTATION, &val, 4);
	dwmInvalidateIconicBitmaps(m_hwnd);
}

HBITMAP CDwmWindow::CreateDwmBitmap(int width, int height)
{
	BITMAPINFO bi;
	bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
	bi.bmiHeader.biWidth = width;
	bi.bmiHeader.biHeight = -height;
	bi.bmiHeader.biPlanes = 1;
	bi.bmiHeader.biBitCount = 32;
	bi.bmiHeader.biCompression = BI_RGB;
	return CreateDIBSection(0, &bi, DIB_RGB_COLORS, NULL, 0, 0);
}

void CDwmWindow::MakeBitmapOpaque(HBITMAP hBmp)
{
	BITMAP bmp;
	GetObject(hBmp, sizeof(bmp), &bmp);
	if (bmp.bmBitsPixel != 32) return;
	if (bmp.bmHeight < 0) bmp.bmHeight *= -1;

	int size = bmp.bmWidth * bmp.bmHeight * 4;
	BYTE *data = new BYTE[size];
	GetBitmapBits(hBmp, size, data);
	for (int i = 3; i < size; i += 4)
		data[i] = 255;
	SetBitmapBits(hBmp, size, data);
	delete [] data;

}

void CDwmWindow::DrawGradient(HDC hdc, int x, int y, int width, int height, RGBQUAD *rgb0, RGBQUAD *rgb1)
{
	int oldMode			= SetBkMode(hdc, OPAQUE);
	COLORREF oldColor	= SetBkColor(hdc, 0);

	RECT rc; SetRect(&rc, x, 0, x+width, 0);
	for (int i=y+height; --i >= y; ) {
		COLORREF color = RGB(
			((height-i-1)*rgb0->rgbRed   + i*rgb1->rgbRed)   / height,
			((height-i-1)*rgb0->rgbGreen + i*rgb1->rgbGreen) / height,
			((height-i-1)*rgb0->rgbBlue  + i*rgb1->rgbBlue)  / height);
		rc.top = rc.bottom = i;
		++rc.bottom;
		SetBkColor(hdc, color);
		ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rc, "", 0, 0);
	}

	SetBkMode(hdc, oldMode);
	SetBkColor(hdc, oldColor);
}

bool CDwmWindow::AddButton(HICON hIcon, TCHAR *text, INT_PTR data, DWORD flags)
{
	if (m_btnCount == SIZEOF(m_btnInfo)) return false;
	m_btnInfo[m_btnCount].dwMask = THUMBBUTTONMASK(THB_ICON|THB_TOOLTIP|THB_FLAGS);
	m_btnInfo[m_btnCount].hIcon = hIcon;
	lstrcpyn(m_btnInfo[m_btnCount].szTip, text, SIZEOF(m_btnInfo[m_btnCount].szTip));
	m_btnInfo[m_btnCount].dwFlags = THUMBBUTTONFLAGS(flags);
	m_btnData[m_btnCount] = data;
	m_btnCount++;
	return true;
}

void CDwmWindow::UpdateButtons(ITaskbarList3 *p)
{
	if (m_btnInitialized)
		p->ThumbBarUpdateButtons(hwnd(), SIZEOF(m_btnInfo), m_btnInfo);
	else
		p->ThumbBarAddButtons(hwnd(), SIZEOF(m_btnInfo), m_btnInfo);

	m_btnCount = 0; // reset this for next iteration
	m_btnInitialized = true;
}

void CDwmWindow::SetTimer(int id, int timeout)
{
	::SetTimer(m_hwnd, id, timeout, NULL);
}

void CDwmWindow::KillTimer(int id)
{
	::KillTimer(m_hwnd, id);
}

void CDwmWindow::InvalidateThumbnail()
{
	dwmInvalidateIconicBitmaps(m_hwnd);
}

void CDwmWindow::SetPreview(HBITMAP hbmp, int x, int y)
{
	POINT pt = { x, y };
	dwmSetIconicLivePreviewBitmap(m_hwnd, hbmp, &pt, 0);
}

void CDwmWindow::SetThumbnail(HBITMAP hbmp)
{
	dwmSetIconicThumbnail(m_hwnd, hbmp, 0);
}

LRESULT CDwmWindow::WndProc(UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
		case WM_ACTIVATE:
		{
			if (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE)
			{
				OnActivate((HWND)wParam);
			}
			break;
		}

		case WM_CLOSE:
		{
			OnClose();
			return FALSE;
		}

		case WM_DWMSENDICONICLIVEPREVIEWBITMAP:
		{
			OnRenderPreview();
			break;
		}

		case WM_DWMSENDICONICTHUMBNAIL:
		{
			int width = HIWORD(lParam);
			int height = LOWORD(lParam);
			OnRenderThumbnail(width, height);
			break;
		}

		case WM_TIMER:
		{
			OnTimer(wParam);
			break;
		}

		case WM_COMMAND:
		{
			if (HIWORD(wParam) == THBN_CLICKED)
				OnToolbar(LOWORD(wParam), m_btnData[LOWORD(wParam)]);
			break;
		}
	}

	return DefWindowProc(m_hwnd, msg, wParam, lParam);
}

void CDwmWindow::GlobalInitWndClass()
{
	static bool bInitialized = false;
	if (bInitialized) return;

	WNDCLASSEX wcl = {0};
	wcl.cbSize = sizeof(wcl);
	wcl.lpfnWndProc = GlobalWndProc;
	wcl.style = 0;
	wcl.cbClsExtra = 0;
	wcl.cbWndExtra = 0;
	wcl.hInstance = g_hInst;
	wcl.hIcon = NULL;
	wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcl.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
	wcl.lpszMenuName = NULL;
	wcl.lpszClassName = WNDCLASSNAME;
	wcl.hIconSm = NULL;
	RegisterClassEx(&wcl);
}

LRESULT CALLBACK CDwmWindow::GlobalWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	CDwmWindow *wnd = (CDwmWindow *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
	if (!wnd) return DefWindowProc(hwnd, msg, wParam, lParam);
	if (msg == WM_DESTROY)
	{
		delete wnd;
		return DefWindowProc(hwnd, msg, wParam, lParam);
	}
	return wnd->WndProc(msg, wParam, lParam);
}