#include "precomp.h"
#include "splitbar2.h"
#include "resource.h"

/* static */ int CSplitBar2::ms_dxpSplitBar = 0;  // width of a standard split bar window // GetSystemMetrics(SM_CXSIZEFRAME);

/* static */ void CSplitBar2::_UpdateSplitBar(void)
{
	ms_dxpSplitBar = GetSystemMetrics(SM_CXSIZEFRAME);
}

/*  C  S P L I T  B A R  */
/*-------------------------------------------------------------------------
    %%Function: CSplitBar2
    
-------------------------------------------------------------------------*/
CSplitBar2::CSplitBar2(void)
: m_hwndBuddy (NULL)
, m_hwndParent(NULL)
, m_pfnAdjust(NULL)
, m_Context(NULL)
, m_hdcDrag(NULL)
, m_fCaptured(FALSE)
{

    DBGENTRY(CSplitBar2::CSplitBar2);

    _UpdateSplitBar();

    DBGEXIT(CSplitBar2::CSplitBar2);
}


CSplitBar2::~CSplitBar2()
{
    DBGENTRY(CSplitBar2::~CSplitBar2);
	
    if( ::IsWindow( m_hWnd ) )
    {
        DestroyWindow();
    }

    DBGEXIT(CSplitBar2::~CSplitBar2);
}



HRESULT CSplitBar2::Create(HWND hwndBuddy, PFN_ADJUST pfnAdjust, LPARAM Context)
{
    DBGENTRY(CSplitBar2::Create);
    HRESULT hr = S_OK;

    if( hwndBuddy && pfnAdjust )
    {
        m_hwndBuddy = hwndBuddy;
        m_hwndParent = ::GetParent(hwndBuddy);
        m_pfnAdjust = pfnAdjust;
        m_Context = Context;

        RECT rc;
        SetRect( &rc, 0, 0, ms_dxpSplitBar, 0 );    
        
        if( !CWindowImpl<CSplitBar2>::Create( m_hwndParent, rc ) )
        {
            hr = HRESULT_FROM_WIN32(GetLastError());
        }
    }
    else
    {
        hr = E_INVALIDARG;

    }

    DBGEXIT_HR(CSplitBar2::Create,hr);
    return hr;
}


LRESULT CSplitBar2::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    
    
    DBGENTRY(CSplitBar2::OnLButtonDown);        

	POINT pt;
	pt.x = LOWORD(lParam);
	pt.y = HIWORD(lParam); 

	_TrackDrag(pt);

    DBGEXIT(CSplitBar2::OnLButtonDown);

	return 0;

}


/*  C O N S T R A I N  D R A G  P O I N T  */
/*-------------------------------------------------------------------------
    %%Function: _ConstrainDragPoint
    
-------------------------------------------------------------------------*/
int CSplitBar2::_ConstrainDragPoint(short x)
{

    DBGENTRY(CSplitBar2::_ConstrainDragPoint);


	// Factor out the drag offset (to make calculations easier)
	int dx = x - m_dxDragOffset;

	// Don't allow the panes to go below their minimum size
	if (dx < m_dxMin)
	{
		dx = m_dxMin;
	}
	else if (dx > m_dxMax)
	{
		dx = m_dxMax;
	}


    DBGEXIT(CSplitBar2::_ConstrainDragPoint);

	// Factor the drag offset back in
	return (m_dxDragOffset + dx);
}


/*  D R A W  B A R  */
/*-------------------------------------------------------------------------
    %%Function: _DrawBar
    
-------------------------------------------------------------------------*/
void CSplitBar2::_DrawBar(void)
{
    DBGENTRY(CSplitBar2::_DrawBar);

	RECT rc;
    
    RECT ClientRect;
    GetClientRect( &ClientRect );

	// Rectangle is a larger to make it easier to see.
	rc.top = ClientRect.top;
	rc.bottom = ClientRect.bottom;
	rc.left = m_xCurr - (m_dxDragOffset + 1); //ClientRect.left + 
	rc.right = rc.left + ms_dxpSplitBar + 1;
	::MapWindowPoints(m_hwndParent, GetDesktopWindow(), (POINT *) &rc, 2);

	::InvertRect(m_hdcDrag, &rc);

    DBGEXIT(CSplitBar2::_DrawBar);
}


/*  F  I N I T  D R A G  L O O P  */
/*-------------------------------------------------------------------------
    %%Function: FInitDragLoop

    Initialize the mouse down drag loop.
    Return FALSE if there was a problem.
-------------------------------------------------------------------------*/
BOOL CSplitBar2::FInitDragLoop(POINT pt)
{
    
    DBGENTRY(CSplitBar2::FInitDragLoop);

	if (NULL != ::GetCapture())
	{
		ERROR_OUT(("InitDragLoop: Unable to capture"));
		return FALSE;
	}

	// handle pending WM_PAINT messages
	MSG msg;
	while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_NOREMOVE))
	{
		if (!GetMessage(&msg, NULL, WM_PAINT, WM_PAINT))
			return FALSE;
		DispatchMessage(&msg);
	}

	HWND hwndDesktop = GetDesktopWindow();
	DWORD dwFlags = ::LockWindowUpdate(hwndDesktop) ? DCX_WINDOW|DCX_CACHE|DCX_LOCKWINDOWUPDATE : DCX_WINDOW|DCX_CACHE;

	ASSERT(m_hdcDrag == NULL);
	m_hdcDrag = ::GetDCEx(hwndDesktop, NULL, dwFlags);
	ASSERT(m_hdcDrag != NULL);

	ASSERT(!m_fCaptured);
	SetCapture();
	ASSERT(m_hWnd == GetCapture());
	m_fCaptured = TRUE;

	m_dxDragOffset = pt.x;
	m_xCurr = pt.x;
	_DrawBar();

	RECT rc;
	// determine the drag extent
	::GetClientRect(m_hwndBuddy, &rc);
	::MapWindowPoints(m_hwndBuddy, m_hwndParent, (POINT *) &rc, 1);
	m_dxMin = rc.left + (32 + (3*2));
	
	::GetClientRect( ::GetParent( m_hwndParent ) , &rc);
	m_dxMax = RectWidth(rc) - (ms_dxpSplitBar + 176);

	if (m_dxMax < m_dxMin)
		m_dxMax = m_dxMin;

	TRACE_OUT(("captured mouse at (%d,%d) (min=%d, max=%d)", pt.x, pt.y, m_dxMin, m_dxMax));

    DBGEXIT(CSplitBar2::FInitDragLoop);

	return TRUE;
}


/*  O N  D R A G  M O V E  */
/*-------------------------------------------------------------------------
    %%Function: OnDragMove
    
-------------------------------------------------------------------------*/
void CSplitBar2::OnDragMove(POINT pt)
{

    DBGENTRY(CSplitBar2::OnDragMove);

	ASSERT(m_fCaptured);

	::ScreenToClient(m_hwndParent, &pt);
	int x = _ConstrainDragPoint((short)pt.x);
	if (x != m_xCurr)
	{
		_DrawBar();
		m_xCurr = x;
		_DrawBar();
	}

    DBGEXIT(CSplitBar2::OnDragMove);
}


/*  O N  D R A G  E N D  */
/*-------------------------------------------------------------------------
    %%Function: OnDragEnd
    
-------------------------------------------------------------------------*/
void CSplitBar2::OnDragEnd(POINT pt)
{

    DBGENTRY(CSplitBar2::OnDragEnd);

	CancelDragLoop();

    RECT ClientRect;
    GetClientRect( &ClientRect );

	::ScreenToClient(m_hwndParent, &pt);
	int x = _ConstrainDragPoint((short)pt.x);
	if (0 != x)
	{
		// Call the adjustment function
        if(m_pfnAdjust)
        {
            m_pfnAdjust(x - (ClientRect.left + m_dxDragOffset), m_Context);
        }

//		ForceWindowResize();
	}

    DBGEXIT(CSplitBar2::OnDragEnd);
}


/*  C A N C E L  D R A G  L O O P  */
/*-------------------------------------------------------------------------
    %%Function: CancelDragLoop
    
-------------------------------------------------------------------------*/
void CSplitBar2::CancelDragLoop(void)
{

    DBGENTRY(CSplitBar2::CancelDragLoop);

	if (m_fCaptured)
    {
	    TRACE_OUT(("Canceling drag loop..."));

	    // Release the capture
	    ReleaseCapture();
	    m_fCaptured = FALSE;

	    // Erase the bar
	    _DrawBar();

	    // unlock window updates
	    LockWindowUpdate(NULL);
	    if (m_hdcDrag != NULL)
	    {
		    ::ReleaseDC(GetDesktopWindow(), m_hdcDrag);
		    m_hdcDrag = NULL;
	    }
    }
    
    DBGEXIT(CSplitBar2::CancelDragLoop);
}


void CSplitBar2::_TrackDrag(POINT pt)
{

    DBGENTRY(CSplitBar2::_TrackDrag);

	// set capture to the window which received this message
	if (FInitDragLoop(pt))
	{
	    // get messages until capture lost or cancelled/accepted
	    while (GetCapture() == m_hWnd)
	    {
		    MSG msg;
		    if (!::GetMessage(&msg, NULL, 0, 0))
		    {
			    PostQuitMessage(msg.wParam);
			    break;
		    }

		    if (WM_MOUSEMOVE == msg.message)
		    {
			    OnDragMove(msg.pt);
			    continue;
		    }

		    if (WM_LBUTTONUP == msg.message)
		    {
			    OnDragEnd(msg.pt);
			    break;
		    }

		    if ((WM_KEYDOWN == msg.message) || 
			    (WM_RBUTTONDOWN == msg.message))
		    {
			    break;
		    }

		    // dispatch all other messages
		    DispatchMessage(&msg);
	    }

	    CancelDragLoop();
	}
    else
    {
		WARNING_OUT(("Unable to Initialize drag loop?"));
    }

    DBGEXIT(CSplitBar2::_TrackDrag);
}



/* static */ CWndClassInfo& CSplitBar2::GetWndClassInfo()
{

    DBGENTRY(CSplitBar2::GetWndClassInfo);

	static CWndClassInfo wc =
	{
		{ 
            sizeof(WNDCLASSEX), // cbSize
            NULL,               // style
            StartWindowProc,    // WndProc
            0,                  // cbClsExtra
            0,                  // cbWndExtra
            0,                  // hInstance
            0,                  // hIcon
            NULL,               // hCursor
            reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1),  // hBackground
            0,                          // lpszMenuName
            _T("ConfSplitBarClass2"),   // lpszClassName
            0                           // hIconSm
        },
		NULL, 
        NULL, 
        MAKEINTRESOURCE(IDC_SPLITV), // hCursor, 
        FALSE, 
        0, 
        _T("")
	};

    DBGEXIT(CSplitBar2::GetWndClassInfo);

	return wc;
}