// 8 september 2015
#include "uipriv_windows.hpp"
#include "area.hpp"

// TODO handle WM_DESTROY/WM_NCDESTROY
// TODO same for other Direct2D stuff
static LRESULT CALLBACK areaWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	uiArea *a;
	CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
	RECT client;
	WINDOWPOS *wp = (WINDOWPOS *) lParam;
	LRESULT lResult;

	a = (uiArea *) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
	if (a == NULL) {
		if (uMsg == WM_CREATE) {
			a = (uiArea *) (cs->lpCreateParams);
			// assign a->hwnd here so we can use it immediately
			a->hwnd = hwnd;
			SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) a);
		}
		// fall through to DefWindowProcW() anyway
		return DefWindowProcW(hwnd, uMsg, wParam, lParam);
	}

	// always recreate the render target if necessary
	if (a->rt == NULL)
		a->rt = makeHWNDRenderTarget(a->hwnd);

	if (areaDoDraw(a, uMsg, wParam, lParam, &lResult, FALSE) != FALSE)
		return lResult;

	if (uMsg == WM_WINDOWPOSCHANGED) {
		if ((wp->flags & SWP_NOSIZE) != 0)
			return DefWindowProcW(hwnd, uMsg, wParam, lParam);
		uiWindowsEnsureGetClientRect(a->hwnd, &client);
		areaDrawOnResize(a, &client);
		areaScrollOnResize(a, &client);
		return 0;
	}

	if (areaDoScroll(a, uMsg, wParam, lParam, &lResult) != FALSE)
		return lResult;
	if (areaDoEvents(a, uMsg, wParam, lParam, &lResult) != FALSE)
		return lResult;

	// nothing done
	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

// control implementation

uiWindowsControlAllDefaults(uiArea)

static void uiAreaMinimumSize(uiWindowsControl *c, int *width, int *height)
{
	// TODO
	*width = 0;
	*height = 0;
}

ATOM registerAreaClass(HICON hDefaultIcon, HCURSOR hDefaultCursor)
{
	WNDCLASSW wc;

	ZeroMemory(&wc, sizeof (WNDCLASSW));
	wc.lpszClassName = areaClass;
	wc.lpfnWndProc = areaWndProc;
	wc.hInstance = hInstance;
	wc.hIcon = hDefaultIcon;
	wc.hCursor = hDefaultCursor;
	wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
	// this is just to be safe; see the InvalidateRect() call in the WM_WINDOWPOSCHANGED handler for more details
	wc.style = CS_HREDRAW | CS_VREDRAW;
	return RegisterClassW(&wc);
}

void unregisterArea(void)
{
	if (UnregisterClassW(areaClass, hInstance) == 0)
		logLastError(L"error unregistering uiArea window class");
}

void uiAreaSetSize(uiArea *a, int width, int height)
{
	a->scrollWidth = width;
	a->scrollHeight = height;
	areaUpdateScroll(a);
}

void uiAreaQueueRedrawAll(uiArea *a)
{
	// don't erase the background; we do that ourselves in doPaint()
	invalidateRect(a->hwnd, NULL, FALSE);
}

void uiAreaScrollTo(uiArea *a, double x, double y, double width, double height)
{
	// TODO
}

void uiAreaBeginUserWindowMove(uiArea *a)
{
	HWND toplevel;

	// TODO restrict execution
	ReleaseCapture();		// TODO use properly and reset internal data structures
	toplevel = parentToplevel(a->hwnd);
	if (toplevel == NULL) {
		// TODO
		return;
	}
	// see http://stackoverflow.com/questions/40249940/how-do-i-initiate-a-user-mouse-driven-move-or-resize-for-custom-window-borders-o#40250654
	SendMessageW(toplevel, WM_SYSCOMMAND,
		SC_MOVE | 2, 0);
}

void uiAreaBeginUserWindowResize(uiArea *a, uiWindowResizeEdge edge)
{
	HWND toplevel;
	WPARAM wParam;

	// TODO restrict execution
	ReleaseCapture();		// TODO use properly and reset internal data structures
	toplevel = parentToplevel(a->hwnd);
	if (toplevel == NULL) {
		// TODO
		return;
	}
	// see http://stackoverflow.com/questions/40249940/how-do-i-initiate-a-user-mouse-driven-move-or-resize-for-custom-window-borders-o#40250654
	wParam = SC_SIZE;
	switch (edge) {
	case uiWindowResizeEdgeLeft:
		wParam |= 1;
		break;
	case uiWindowResizeEdgeTop:
		wParam |= 3;
		break;
	case uiWindowResizeEdgeRight:
		wParam |= 2;
		break;
	case uiWindowResizeEdgeBottom:
		wParam |= 6;
		break;
	case uiWindowResizeEdgeTopLeft:
		wParam |= 4;
		break;
	case uiWindowResizeEdgeTopRight:
		wParam |= 5;
		break;
	case uiWindowResizeEdgeBottomLeft:
		wParam |= 7;
		break;
	case uiWindowResizeEdgeBottomRight:
		wParam |= 8;
		break;
	}
	SendMessageW(toplevel, WM_SYSCOMMAND,
		wParam, 0);
}

uiArea *uiNewArea(uiAreaHandler *ah)
{
	uiArea *a;

	uiWindowsNewControl(uiArea, a);

	a->ah = ah;
	a->scrolling = FALSE;
	uiprivClickCounterReset(&(a->cc));

	// a->hwnd is assigned in areaWndProc()
	uiWindowsEnsureCreateControlHWND(0,
		areaClass, L"",
		0,
		hInstance, a,
		FALSE);

	return a;
}

uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height)
{
	uiArea *a;

	uiWindowsNewControl(uiArea, a);

	a->ah = ah;
	a->scrolling = TRUE;
	a->scrollWidth = width;
	a->scrollHeight = height;
	uiprivClickCounterReset(&(a->cc));

	// a->hwnd is assigned in areaWndProc()
	uiWindowsEnsureCreateControlHWND(0,
		areaClass, L"",
		WS_HSCROLL | WS_VSCROLL,
		hInstance, a,
		FALSE);

	// set initial scrolling parameters
	areaUpdateScroll(a);

	return a;
}
