/*-------------------------------------------------------------------------
 * drawElements Quality Program Tester Core
 * ----------------------------------------
 *
 * Copyright 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *//*!
 * \file
 * \brief Generic Win32 window class.
 *//*--------------------------------------------------------------------*/

#include "tcuWin32Window.hpp"

namespace tcu
{
namespace win32
{

static LRESULT CALLBACK windowProcCallback (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	Window* window = reinterpret_cast<Window*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
	if (window)
		return window->windowProc(uMsg, wParam, lParam);
	else
		return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

Window::Window (HINSTANCE instance, int width, int height)
	: m_window	(DE_NULL)
{
	try
	{
		static const char	s_className[]	= "dEQP Test Process Class";
		static const char	s_windowName[]	= "dEQP Test Process";

		{
			WNDCLASS wndClass;
			memset(&wndClass, 0, sizeof(wndClass));
			wndClass.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
			wndClass.lpfnWndProc	= windowProcCallback;
			wndClass.cbClsExtra		= 0;
			wndClass.cbWndExtra		= 0;
			wndClass.hInstance		= instance;
			wndClass.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
			wndClass.hCursor		= LoadCursor(NULL, IDC_ARROW);
			wndClass.hbrBackground	= CreateSolidBrush(RGB(0, 0, 0));
			wndClass.lpszMenuName	= NULL;
			wndClass.lpszClassName	= s_className;

			RegisterClass(&wndClass);
		}

		m_window = CreateWindow(s_className, s_windowName,
								WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW,
								CW_USEDEFAULT, CW_USEDEFAULT,
								width, height,
								NULL, NULL, instance, NULL);

		if (!m_window)
			TCU_THROW(ResourceError, "Failed to create Win32 window");

		// Store this as userdata
		SetWindowLongPtr(m_window, GWLP_USERDATA, (LONG_PTR)this);

		setSize(width, height);
	}
	catch (...)
	{
		if (m_window)
			DestroyWindow(m_window);

		throw;
	}
}

Window::~Window (void)
{
	if (m_window)
	{
		// Clear this pointer from windowproc
		SetWindowLongPtr(m_window, GWLP_USERDATA, 0);
	}

	DestroyWindow(m_window);
}

void Window::setVisible (bool visible)
{
	ShowWindow(m_window, visible ? SW_SHOW : SW_HIDE);
}

void Window::setSize (int width, int height)
{
	RECT rc;

	rc.left		= 0;
	rc.top		= 0;
	rc.right	= width;
	rc.bottom	= height;

	if (!AdjustWindowRect(&rc, GetWindowLong(m_window, GWL_STYLE), GetMenu(m_window) != NULL))
		TCU_THROW(TestError, "AdjustWindowRect() failed");

	if (!SetWindowPos(m_window, NULL, 0, 0,
					  rc.right - rc.left, rc.bottom - rc.top,
					  SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOZORDER))
		TCU_THROW(TestError, "SetWindowPos() failed");
}

IVec2 Window::getSize (void) const
{
	RECT rc;
	if (!GetClientRect(m_window, &rc))
		TCU_THROW(TestError, "GetClientRect() failed");

	return IVec2(rc.right - rc.left,
				 rc.bottom - rc.top);
}

void Window::processEvents (void)
{
	MSG msg;
	while (PeekMessage(&msg, m_window, 0, 0, PM_REMOVE))
		DispatchMessage(&msg);
}

LRESULT Window::windowProc (UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
		// \todo [2014-03-12 pyry] Handle WM_SIZE?

		case WM_DESTROY:
			PostQuitMessage(0);
			return 0;

		case WM_KEYDOWN:
			if (wParam == VK_ESCAPE)
			{
				PostQuitMessage(0);
				return 0;
			}
			// fall-through

		default:
			return DefWindowProc(m_window, uMsg, wParam, lParam);
	}
}

} // win32
} // tcu