//	Darkstar Engine  (c) UnderWorld Interactive Studio (all coding by Svarog    2007-2008)
//
//      Данный файл является частью Darkstar Engine. Любое использование кода файла
//      без согласия компании, является нарушением закона об авторском праве (в слу-
//      чае если не оговорено обратное).
//
//      Имя файла: application_window.cpp
//      Краткое описание: окно приложения
//

#include <Darkstar/Graphic System/Window/application_window.hpp>
#include <Darkstar/Graphic System/Direct3D/graphicDriver.hpp>

using namespace gs;	

WindowSettings::WindowSettings()
{
	x = 0;
	y = 0;
	is_fullscreen = false;
};

ApplicationWindow::ApplicationWindow()
{
	is_exist = false;
	hInstance = GetModuleHandle(NULL);
	boost::function2<void, int, int> new_function = boost::bind(&ApplicationWindow::setNewSize, this, _1, _2);
	GraphicDriver::ptr()->addMessageListenerOnResize(new_function);
};

ApplicationWindow::~ApplicationWindow()
{
	destroyWindow();
};

bool ApplicationWindow::createWindow(const unsigned int x, const unsigned int y, const unsigned int width, const unsigned int height, const std::string name)
{
	WindowSettings ws;
	ws.x = x;
	ws.y = y;
	ws.name = name;
	ws.width = width;
	ws.height = height;
	return createWindow(ws);
};

bool ApplicationWindow::createWindow(const WindowSettings& ws)
{
	WNDCLASSEX wnclass;
	wnclass.cbSize = sizeof(WNDCLASSEX);
	wnclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;
	wnclass.lpfnWndProc = window_proc;
	wnclass.cbClsExtra = 0;
	wnclass.cbWndExtra = 0;
	wnclass.hInstance = hInstance;
	wnclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wnclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	wnclass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wnclass.lpszMenuName = NULL;
	wnclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
	wnclass.lpszClassName = "Darkstar";

	if(!RegisterClassEx(&wnclass))
		return false;
	DWORD extflags = 0;
	DWORD flags = WS_OVERLAPPEDWINDOW;
	hwnd = CreateWindowEx(extflags, "Darkstar", ws.name.c_str(), flags, ws.x, ws.y, ws.width, ws.height, NULL, NULL, hInstance, this);
	if(!hwnd)
		return false;
	ShowWindow(hwnd, SW_SHOW);
	UpdateWindow(hwnd);
	SetFocus(hwnd);
	hdc = GetDC(hwnd);
	winset = ws;
	if(!ws.is_fullscreen)
	{
		RECT rect;
		GetClientRect(hwnd, &rect);
		winset.width = rect.right - rect.left;
		winset.height = rect.bottom - rect.top;
		winset.x = rect.left;
		winset.y = rect.top;
	};
	is_exist = true;
	return true;
};

bool ApplicationWindow::activateWindow()
{
	if(!SetFocus(hwnd))
		return false;
	return true;
};

bool ApplicationWindow::destroyWindow()
{
	if(!is_exist)
		return true;
	ReleaseDC(hwnd, hdc);
	DestroyWindow(hwnd);
	UnregisterClass("Darkstar", hInstance);
	is_exist = false;
	return true;
};

bool ApplicationWindow::handle()
{
	MSG msg;
	while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	};
	return true;
};

LRESULT CALLBACK ApplicationWindow::window_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
// warning C4311: 'reinterpret_cast' : pointer truncation from 'gs::WindowXP *' to 'LONG'	
#pragma warning(disable: 4311)
// warning C4312: 'reinterpret_cast' : conversion from 'LONG' to 'gs::WindowXP *' of greater size
#pragma warning(disable: 4312)
	LONG l = GetWindowLong(hwnd, GWL_USERDATA);
	ApplicationWindow* w = reinterpret_cast<ApplicationWindow*>(l);
	switch(message)
	{
	case WM_CREATE:
		{
			CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lparam);
			w = reinterpret_cast<ApplicationWindow*>(cs->lpCreateParams);
			SetWindowLong(hwnd, GWL_USERDATA, reinterpret_cast<LONG>(w));
			return 0;
		};
	case WM_CLOSE:
		{
			if(hwnd != NULL)
				w->destroyWindow();
			return DefWindowProc(hwnd, message, wparam, lparam);
		};
	case WM_DESTROY:
		{
			PostQuitMessage(0);
			return 0;
		};
	case WM_SIZE:
		{
			if(wparam == SIZE_RESTORED || wparam == SIZE_MAXIMIZED)
				gs::GraphicDriver::ptr()->resizeBuffers(LOWORD(lparam), HIWORD(lparam));
		};
	case WM_KEYDOWN:
	case WM_KEYUP:
		break;
	};
	return DefWindowProc(hwnd, message, wparam, lparam);
};

unsigned int ApplicationWindow::getX() const
{
	return winset.x;
};

unsigned int ApplicationWindow::getY() const
{
	return winset.y;
};

unsigned int ApplicationWindow::getWidth() const
{
	return winset.width;
};

unsigned int ApplicationWindow::getHeight() const
{
	return winset.height;
};

bool ApplicationWindow::getIsExist() const
{
	return is_exist;
};

HWND ApplicationWindow::getHWND() const
{
	return hwnd;
};

bool ApplicationWindow::getIsFullScreen() const
{
	return winset.is_fullscreen;
};

void ApplicationWindow::setNewSize(const unsigned int new_width, const unsigned int new_height)
{
	winset.width = new_width;
	winset.height = new_height;
};




