#include "global.h"
#include "cseparator.h"

CSeparator::~CSeparator()
{
}

void CSeparator::DrawXorBar(HDC hdc, DWORD x, DWORD y, DWORD width, DWORD height)
{
	static WORD dotPatternBmp[8] = { 0x00aa, 0x0055, 0x00aa, 0x0055, 
                                    0x00aa, 0x0055, 0x00aa, 0x0055};
	HBITMAP hbm;
	HBRUSH  hbr, hbrushOld;

	hbm = ::CreateBitmap(8, 8, 1, 1, dotPatternBmp);

	hbr = ::CreatePatternBrush(hbm);

	::SetBrushOrgEx(hdc, x, y, 0);
	hbrushOld = (HBRUSH)::SelectObject(hdc, hbr);

	::PatBlt(hdc, x, y, width, height, PATINVERT);

	::SelectObject(hdc, hbrushOld);

	::DeleteObject(hbr);
	::DeleteObject(hbm);
}

LRESULT CALLBACK CSeparator::WindowProcHor(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp)
{
	switch (msg)
	{
	case WM_LBUTTONDOWN:
		{
			::GetCursorPos(&oldPos);
			HDC dc = ::GetDC(0);
			RECT rc; ::GetWindowRect(hwnd, &rc);
			delta = rc.top - oldPos.y;
			DrawXorBar(dc, rc.left, rc.top, rc.right-rc.left, SEPARATOR_THICK);
			::ReleaseDC(hwnd, dc);
			::SetCapture(hwnd);
		}
		break;
	case WM_MOUSEMOVE:
		if (wp & MK_LBUTTON) 
		{
			DWORD min, max; getMinMax(&min, &max);
			/*min += SEPARATOR_THICK;*/ max -= SEPARATOR_THICK;
			RECT rc; ::GetWindowRect(hwnd, &rc);
			HDC dc = ::GetDC(0);
			DrawXorBar(dc, rc.left, oldPos.y+delta, rc.right-rc.left, SEPARATOR_THICK);
			::GetCursorPos(&oldPos);
			if (oldPos.y+delta < (int)min)
			{
				oldPos.y = min; delta = 0;
			}
			if (oldPos.y+delta > (int)max)
			{
				oldPos.y = max; delta = 0;
			}
			DrawXorBar(dc, rc.left, oldPos.y+delta, rc.right-rc.left, SEPARATOR_THICK);
			::ReleaseDC(hwnd, dc);
		}
		break;
	case WM_LBUTTONUP:
		{
			::ReleaseCapture();
			RECT rc; ::GetWindowRect(hwnd, &rc);
			//zmaz
			HDC dc = ::GetDC(0);
			DrawXorBar(dc, rc.left, oldPos.y+delta, rc.right-rc.left, SEPARATOR_THICK);
			::ReleaseDC(hwnd, dc);
			//posun separator na novu poziciu
			POINT p; p.x = rc.left; p.y = oldPos.y+delta; ::ScreenToClient(::GetParent(hwnd), &p);
			::SetWindowPos(hwnd, 0, p.x, p.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
			DWORD width = rc.right-rc.left;
			rc.left = p.x; rc.right = rc.left + width;
			rc.top = p.y; rc.bottom = rc.top + SEPARATOR_THICK;
			sizedCallback(&rc);
		}
		break;
 	}
	return ::DefWindowProc(hwnd,msg,wp,lp);
}

LRESULT CALLBACK CSeparator::WindowProcVer(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp)
{
	switch (msg)
	{
	case WM_LBUTTONDOWN:
		{
			::GetCursorPos(&oldPos);
			HDC dc = ::GetDC(0);
			RECT rc; ::GetWindowRect(hwnd, &rc);
			delta = rc.left - oldPos.x;
			DrawXorBar(dc, rc.left, rc.top, SEPARATOR_THICK, rc.bottom-rc.top);
			::ReleaseDC(hwnd, dc);
			::SetCapture(hwnd);
		}
		break;
	case WM_MOUSEMOVE:
		if (wp & MK_LBUTTON) 
		{
			DWORD min, max; getMinMax(&min, &max);
			/*min += SEPARATOR_THICK;*/ max -= SEPARATOR_THICK;
			RECT rc; ::GetWindowRect(hwnd, &rc);
			HDC dc = ::GetDC(0);
			DrawXorBar(dc, oldPos.x+delta, rc.top, SEPARATOR_THICK, rc.bottom-rc.top);
			::GetCursorPos(&oldPos);
			if (oldPos.x+delta < (int)min)
			{
				oldPos.x = min; delta = 0;
			}
			if (oldPos.x+delta > (int)max)
			{
				oldPos.x = max; delta = 0;
			}
			DrawXorBar(dc, oldPos.x+delta, rc.top, SEPARATOR_THICK, rc.bottom-rc.top);
			::ReleaseDC(hwnd, dc);
		}
		break;
	case WM_LBUTTONUP:
		{
			::ReleaseCapture();
			RECT rc; ::GetWindowRect(hwnd, &rc);
			//zmaz
			HDC dc = ::GetDC(0);
			DrawXorBar(dc, oldPos.x+delta, rc.top, SEPARATOR_THICK, rc.bottom-rc.top);
			::ReleaseDC(hwnd, dc);
			//posun separator na novu poziciu
			POINT p; p.x = oldPos.x+delta; p.y = rc.top; ::ScreenToClient(::GetParent(hwnd), &p);
			::SetWindowPos(hwnd, 0, p.x, p.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
			DWORD height = rc.bottom-rc.top;
			rc.left = p.x; rc.right = rc.left + SEPARATOR_THICK;
			rc.top = p.y; rc.bottom = rc.top + height;
			sizedCallback(&rc);
		}
		break;
 	}
	return ::DefWindowProc(hwnd,msg,wp,lp);
}

LRESULT CALLBACK CSeparator::StaticWindowProcHor(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp)
{
	DWORD p = ::GetWindowLong(hwnd,GWL_USERDATA);
	return ((CSeparator*)p)->WindowProcHor(hwnd,msg,wp,lp);
}

LRESULT CALLBACK CSeparator::StaticWindowProcVer(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp)
{
	DWORD p = ::GetWindowLong(hwnd,GWL_USERDATA);
	return ((CSeparator*)p)->WindowProcVer(hwnd,msg,wp,lp);
}

CSeparator::CSeparator(DWORD sepType, HWND parent, DWORD posX, DWORD posY, DWORD size,
					   void sized(RECT*), void getminmax(DWORD*,DWORD*) )
{
	static char classnamehor[] = "cseparatorhorinlog";
	static char classnamever[] = "cseparatorverinlog";

	WNDCLASS wc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);//(HBRUSH)::CreateSolidBrush(0x0000FF00);
	wc.hIcon = NULL;
	wc.hInstance = app.hInstance;
	wc.lpszMenuName = 0;
	wc.style = 0;

	wc.hCursor = ::LoadCursor(0, IDC_SIZENS);
	wc.lpfnWndProc = (WNDPROC)CSeparator::StaticWindowProcHor;
	wc.lpszClassName = classnamehor;
	::RegisterClass(&wc);

	wc.hCursor = ::LoadCursor(0, IDC_SIZEWE);
	wc.lpfnWndProc = (WNDPROC)CSeparator::StaticWindowProcVer;
	wc.lpszClassName = classnamever;
	::RegisterClass(&wc);

	switch (sepType)
	{
	case SEPARATOR_HORIZONTAL:
		hwnd = ::CreateWindowEx(0, classnamehor, NULL, WS_CHILD|WS_VISIBLE, posX, posY,
			size, SEPARATOR_THICK, parent, NULL, app.hInstance, 0);
		break;
	case SEPARATOR_VERTICAL:
		hwnd = ::CreateWindowEx(0, classnamever, NULL, WS_CHILD|WS_VISIBLE, posX, posY,
			SEPARATOR_THICK, size, parent, NULL, app.hInstance, 0);
		break;
	}

	type = (BYTE)sepType;
	hwndParent = parent;

	//asociuj okno s jeho instanciou
	::SetWindowLong(hwnd,GWL_USERDATA,(DWORD)this);

	//type = (BYTE)sepType;

	sizedCallback = sized;
	getMinMax = getminmax;

	RECT rc;
	GetParentCoordinates(&rc); 
	sizedCallback(&rc);
}

void CSeparator::GetParentCoordinates(RECT *rc)
{
	POINT p; ::GetWindowRect(hwnd, rc);
	p.x = rc->left; p.y = rc->top; ::ScreenToClient(hwndParent, &p); rc->left = p.x; rc->top = p.y;
	p.x = rc->right; p.y = rc->bottom; ::ScreenToClient(hwndParent, &p); rc->right = p.x; rc->bottom = p.y;
}

void CSeparator::SetPosition(DWORD posX, DWORD posY, DWORD size)
{
	switch (type)
	{
	case SEPARATOR_HORIZONTAL:
		::SetWindowPos(hwnd, 0, posX, posY, size, SEPARATOR_THICK, SWP_NOZORDER);
		break;
	case SEPARATOR_VERTICAL:
		::SetWindowPos(hwnd, 0, posX, posY, SEPARATOR_THICK, size, SWP_NOZORDER);
		break;
	}
	RECT rc;
	GetParentCoordinates(&rc);
	sizedCallback(&rc);
}

HWND CSeparator::GetHandle()
{
	return hwnd;
}