#include "stdafx.h"
#include "Lava.h"
#include "NcContainer.h"

#include "MsgHelp.h"


/***************************************************************************\
*****************************************************************************
*
* API Implementation
*
*****************************************************************************
\***************************************************************************/

//------------------------------------------------------------------------------
NcContainer * 
GetNcContainer(DuVisual * pgad)
{
    DuContainer * pcon = pgad->GetContainer();
    AssertReadPtr(pcon);

    NcContainer * pconHWND = CastNcContainer(pcon);
    return pconHWND;
}


/***************************************************************************\
*
* GdCreateNcRootGadget (Public)
*
* GdCreateNcRootGadget() creates a new RootGadget for an existing HWND's
* non-client area.
*
\***************************************************************************/

HRESULT
GdCreateNcRootGadget(
    IN  HWND hwndContainer,             // Window to be hosted inside
    IN  CREATE_INFO * pci,              // Creation information
    OUT DuRootGadget ** ppgadNew)         // New Root Gadget
{
    HRESULT hr;

    //
    // Build a new container and top gadget
    //

    NcContainer * pconNew;
    hr = NcContainer::Build(hwndContainer, &pconNew);
    if (FAILED(hr)) {
        return hr;
    }

    hr = DuRootGadget::Build(pconNew, FALSE, pci, ppgadNew);
    if (FAILED(hr)) {
        pconNew->xwUnlock();
        return hr;
    }

    //
    // Don't setup an initial brush when using Non-Client
    //

    return S_OK;
}


/***************************************************************************\
*****************************************************************************
*
* class NcContainer
*
*****************************************************************************
\***************************************************************************/

//------------------------------------------------------------------------------
NcContainer::NcContainer()
{
    m_hwndOwner = NULL;
}


//------------------------------------------------------------------------------
NcContainer::~NcContainer()
{
    //
    // Need to destroy the gadget tree before this class is destructed since
    // it may need to make calls to the container during its destruction.  If 
    // we don't do this here, it may end up calling pure-virtual's on the base
    // class.
    //

    xwDestroyGadget();
}


//------------------------------------------------------------------------------
HRESULT
NcContainer::Build(HWND hwnd, NcContainer ** ppconNew)
{
    // Check parameters
    if (!ValidateHWnd(hwnd)) {
        return E_INVALIDARG;
    }

    // Create a new container
    NcContainer * pconNew = ClientNew(NcContainer);
    if (pconNew == NULL) {
        return E_OUTOFMEMORY;
    }

    pconNew->m_hwndOwner    = hwnd;

    RECT rcWin;
    GetWindowRect(hwnd, &rcWin);
    pconNew->m_sizePxl.cx   = rcWin.right - rcWin.left;
    pconNew->m_sizePxl.cy   = rcWin.bottom - rcWin.top;

    *ppconNew = pconNew;
    return S_OK;
}


//------------------------------------------------------------------------------
void
NcContainer::OnInvalidate(const RECT * prcInvalidContainerPxl)
{
    UNREFERENCED_PARAMETER(prcInvalidContainerPxl);
}


//------------------------------------------------------------------------------
void
NcContainer::OnGetRect(RECT * prcDesktopPxl)
{
    GetWindowRect(m_hwndOwner, prcDesktopPxl);
}


//------------------------------------------------------------------------------
void        
NcContainer::OnStartCapture()
{
    
}


//------------------------------------------------------------------------------
void        
NcContainer::OnEndCapture()
{
    
}


//------------------------------------------------------------------------------
BOOL
NcContainer::OnTrackMouseLeave()
{
    return FALSE;
}


//------------------------------------------------------------------------------
void        
NcContainer::OnSetFocus()
{
    if (GetFocus() != m_hwndOwner) {
        //
        // Setting focus is a little more complicated than pure HWND's.  This is
        // because Gadgets greatly simplify several things
        //
        // 1. SetFocus
        // 2. Setup caret, if any
        //

        Trace("NcContainer::OnSetFocus()\n");
        SetFocus(m_hwndOwner);
    }
}


//------------------------------------------------------------------------------
void        
NcContainer::OnRescanMouse(POINT * pptContainerPxl)
{
//    Trace("%p OnRescanMouse\n", GetTickCount());

    POINT ptCursor;
    if (!GetCursorPos(&ptCursor)) {
        ptCursor.x  = -20000;
        ptCursor.y  = -20000;
    }

    ScreenToClient(m_hwndOwner, &ptCursor);
    *pptContainerPxl = ptCursor;
}


//------------------------------------------------------------------------------
BOOL        
NcContainer::xdHandleMessage(UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT * pr, UINT nMsgFlags)
{
    UNREFERENCED_PARAMETER(nMsgFlags);

    if (m_pgadRoot == NULL) {
        return FALSE;  // If don't have a root, there is nothing to handle.
    }

    POINT ptContainerPxl;

    *pr = 0;

    Trace("NcContainer::HandleMessage: msg: 0x%x\n", nMsg);

    switch (nMsg)
    {
    case WM_NCLBUTTONDOWN:
    case WM_NCRBUTTONDOWN:
    case WM_NCMBUTTONDOWN:
    case WM_NCLBUTTONDBLCLK:
    case WM_NCRBUTTONDBLCLK:
    case WM_NCMBUTTONDBLCLK:
    case WM_NCLBUTTONUP:
    case WM_NCRBUTTONUP:
    case WM_NCMBUTTONUP:
        ptContainerPxl.x = GET_X_LPARAM(lParam);
        ptContainerPxl.y = GET_Y_LPARAM(lParam);

        if ((GetCapture() == m_hwndOwner) && 
            (ChildWindowFromPointEx(m_hwndOwner, ptContainerPxl, CWP_SKIPINVISIBLE) != m_hwndOwner)) {
           
            ReleaseCapture();
        }

        {
            GMSG_MOUSECLICK msg;
            nMsg += WM_LBUTTONDOWN - WM_NCLBUTTONDOWN;

            GdConvertMouseClickMessage(&msg, nMsg, wParam);

            ContextLock cl;
            if (cl.LockNL(ContextLock::edDefer)) {
                return m_pgadRoot->xdHandleMouseMessage(&msg, ptContainerPxl);
            }
            break;
        }

    case WM_NCMOUSEMOVE:
        ptContainerPxl.x = GET_X_LPARAM(lParam);
        ptContainerPxl.y = GET_Y_LPARAM(lParam);

        if ((GetCapture() == m_hwndOwner) && 
            (ChildWindowFromPointEx(m_hwndOwner, ptContainerPxl, CWP_SKIPINVISIBLE) != m_hwndOwner)) {
           
            ReleaseCapture();
        }

        {
            GMSG_MOUSE msg;
            nMsg += WM_LBUTTONDOWN - WM_NCLBUTTONDOWN;

            GdConvertMouseMessage(&msg, nMsg, wParam);

            ContextLock cl;
            if (cl.LockNL(ContextLock::edDefer)) {
                return m_pgadRoot->xdHandleMouseMessage(&msg, ptContainerPxl);
            }
            break;
        }

    case WM_CAPTURECHANGED:
        if (m_hwndOwner != (HWND) lParam) {
            ContextLock cl;
            if (cl.LockNL(ContextLock::edDefer)) {
                m_pgadRoot->xdHandleMouseLostCapture();
            }
        }
        break;

    case WM_SETFOCUS:
        {
            ContextLock cl;
            if (cl.LockNL(ContextLock::edDefer)) {
                return m_pgadRoot->xdHandleKeyboardFocus(GSC_SET);
            }
            break;
        }

    case WM_KILLFOCUS:
        {
            ContextLock cl;
            if (cl.LockNL(ContextLock::edDefer)) {
                return m_pgadRoot->xdHandleKeyboardFocus(GSC_LOST);
            }
            break;
        }

    case WM_CHAR:
    case WM_KEYDOWN:
    case WM_KEYUP:
    case WM_SYSCHAR:
    case WM_SYSKEYDOWN:
    case WM_SYSKEYUP:
        {
            Trace("NcContainer::xdHandleMessage(Keyboard=0x%x)\n", nMsg);
        }
        break;

    case WM_NCACTIVATE:
        {
            ContextLock cl;
            if (cl.LockNL(ContextLock::edDefer)) {
                m_pgadRoot->xdHandleActivate(wParam ? GSC_LOST : GSC_SET);
            }
            break;
        }
        // Fall through to WM_NCPAINT

    case WM_NCPAINT:
        if ((!m_fManualDraw) && (m_pgadRoot != NULL)) {
//            HDC hdc = GetDCEx(m_hwndOwner, (HRGN) wParam, DCX_WINDOW | DCX_INTERSECTRGN);
            HDC hdc = GetWindowDC(m_hwndOwner);
            RECT rcInvalid;
            {
                ContextLock cl;
                if (cl.LockNL(ContextLock::edNone)) {
                    m_pgadRoot->GetLogRect(&rcInvalid, SGR_CLIENT);
                    m_pgadRoot->xrDrawTree(NULL, hdc, &rcInvalid, 0);
                }
            }
            ReleaseDC(m_hwndOwner, hdc);
            return TRUE;
        }
        break;

    case WM_WINDOWPOSCHANGED:
        {
            WINDOWPOS * pwp = (WINDOWPOS *) lParam;
            if (!TestFlag(pwp->flags, SWP_NOSIZE)) {
                RECT rcWin;
                GetWindowRect(m_hwndOwner, &rcWin);
                ContextLock cl;
                if (cl.LockNL(ContextLock::edDefer)) {
                    VerifyHR(m_pgadRoot->xdSetLogRect(0, 0, rcWin.right - rcWin.left, rcWin.bottom - rcWin.top, SGR_SIZE));
                }
                break;
            }
        }
        break;

    case WM_GETROOTGADGET:
        if (m_pgadRoot != NULL) {
            *pr = (LRESULT) m_pgadRoot->GetHandle();
            return TRUE;
        }
        break;
    }

    return FALSE;
}