// XTPMarkupContext.cpp: implementation of the CXTPMarkupContext class.
//
// This file is a part of the XTREME TOOLKIT PRO MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"

#include "Common/XTPToolTipContext.h"
#include "Common/XTPResourceManager.h"
#include "Common/XTPMarkupRender.h"
#include "Common/XTPImageManager.h"

#include "XTPMarkupObject.h"

#include "XTPMarkupContext.h"

#include "XTPMarkupInputElement.h"
#include "XTPMarkupUIElement.h"
#include "XTPMarkupFrameworkElement.h"
#include "XTPMarkupDecorator.h"
#include "XTPMarkupControl.h"
#include "XTPMarkupPanel.h"
#include "Text/XTPMarkupInline.h"
#include "Text/XTPMarkupSpan.h"
#include "Text/XTPMarkupRun.h"
#include "XTPMarkupBorder.h"
#include "XTPMarkupStackPanel.h"
#include "XTPMarkupGrid.h"
#include "XTPMarkupCanvas.h"
#include "XTPMarkupPage.h"
#include "XTPMarkupShape.h"
#include "XTPMarkupImage.h"
#include "XTPMarkupTextBlock.h"
#include "XTPMarkupButton.h"
#include "XTPMarkupScrollViewer.h"
#include "XTPMarkupResourceDictionary.h"
#include "XTPMarkupThickness.h"
#include "Path/XTPMarkupPath.h"
#include "Path/XTPMarkupPathData.h"

#include "XTPMarkupBuilder.h"
#include "XTPMarkupParser.h"
#include "XTPMarkupDrawingContext.h"
#include "XTPMarkupKeyboardNavigation.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


class CXTPMarkupContext::CXTPMarkupFontArray : public CXTPMarkupTypedSimpleStack<CXTPMarkupFont>
{

};

CXTPMarkupFont::CXTPMarkupFont()
{
	m_pMarkupContext = NULL;
	m_hFont = NULL;
	m_pNextChain = NULL;
}

CXTPMarkupFont::~CXTPMarkupFont()
{
	if (m_pMarkupContext)
	{
		VERIFY(m_pMarkupContext->m_pFonts->Remove(this));
	}
	DeleteObject(m_hFont);
}

//////////////////////////////////////////////////////////////////////////
// CXTPMarkupDelegateMap

class CXTPMarkupDelegateMap
{
public:
	CXTPMarkupDelegateMap();
	~CXTPMarkupDelegateMap();

public:
	void RemoveAll();
	void Add(LPCWSTR lpszDelegate, CXTPMarkupDelegate* pDelegate);
	CXTPMarkupDelegate* Lookup(LPCWSTR lpszDelegate) const;

protected:
	CMap<LPCWSTR, LPCWSTR, CXTPMarkupDelegate*, CXTPMarkupDelegate*> m_mapDelegates;

public:
	LPDISPATCH m_lpHandler;
};


CXTPMarkupDelegateMap::CXTPMarkupDelegateMap()
{
	m_lpHandler = NULL;
}

CXTPMarkupDelegateMap::~CXTPMarkupDelegateMap()
{
	RemoveAll();

	m_lpHandler = NULL;
}

void CXTPMarkupDelegateMap::RemoveAll()
{
	POSITION pos = m_mapDelegates.GetStartPosition();
	while (pos)
	{
		LPCWSTR lpszDelegate;
		CXTPMarkupDelegate* pDelegate;
		m_mapDelegates.GetNextAssoc(pos, lpszDelegate, pDelegate);

		MARKUP_RELEASE(pDelegate);
	}
	m_mapDelegates.RemoveAll();
}

void CXTPMarkupDelegateMap::Add(LPCWSTR lpszDelegate, CXTPMarkupDelegate* pDelegate)
{
	m_mapDelegates.SetAt(lpszDelegate, pDelegate);
}

CXTPMarkupDelegate* CXTPMarkupDelegateMap::Lookup(LPCWSTR lpszDelegate) const
{
	CXTPMarkupDelegate* pDelegate = NULL;
	if (!m_mapDelegates.Lookup(lpszDelegate, pDelegate))
		return NULL;

	return pDelegate;
}

template<> inline BOOL AFXAPI CompareElements(const LPCWSTR* pElement1, const LPCWSTR* pElement2)
{
	return wcscmp(*pElement1, *pElement2) == 0;
}

class CXTPMarkupContext::CInputElementCollection : public CXTPMarkupCollection
{
public:
	CInputElementCollection()
	{
		m_pElementType = MARKUP_TYPE(CXTPMarkupInputElement);
		m_bLogicalParent = FALSE;
	}

public:
	CXTPMarkupInputElement* GetItem(int nIndex) const {
		return (CXTPMarkupInputElement*)m_arrItems[nIndex];
	}
	CXTPMarkupInputElement* GetTailItem() const {
		return (CXTPMarkupInputElement*)m_arrItems[GetCount() - 1];
	}
};

class CXTPMarkupContext::CTooltipContext : public CXTPToolTipContext
{
public:
	CTooltipContext(CXTPMarkupContext* pMarkupContext)
	{
		m_pMarkupContext = pMarkupContext;
	}

	INT_PTR OnToolHitTest(CWnd* /*pWnd*/, CPoint point, TOOLINFO* pToolInfo)
	{
		return m_pMarkupContext->OnToolHitTest(point, pToolInfo);
	}
protected:
	CXTPMarkupContext* m_pMarkupContext;
};

//////////////////////////////////////////////////////////////////////////
// CXTPMarkupContext

CXTPMarkupContext::CXTPMarkupContext()
{
	NONCLIENTMETRICS ncm = { sizeof(NONCLIENTMETRICS) };
	VERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0));
	ncm.lfMessageFont.lfCharSet = XTPResourceManager()->GetFontCharset();

	m_dwRef = 1;
	m_logFont = ncm.lfMessageFont;

	m_clrForeground = 0;
	m_pImageManager = NULL;

	m_pMouseOver = NULL;
	m_pMouseCapture = NULL;
	m_pActiveElement = NULL;
	m_hContextWnd = NULL;

	m_pHandlers = NULL;
	m_pDelegates = NULL;

	m_pFonts = NULL;
	m_pKeyboardNavigation = new CXTPMarkupKeyboardNavigation(this);

	m_pToolTipContext = new CTooltipContext(this);
	m_pToolTipContext->SetStyle(xtpToolTipMarkup);

	m_bEnableGdiPlus = TRUE;


	RegisterClasses();

	CXTPMarkupDrawingContext::Register(TRUE);
}


void CXTPMarkupContext::RegisterClasses()
{
	static BOOL bRegistered = FALSE;
	if (bRegistered)
		return;

	bRegistered = TRUE;

	CXTPMarkupType::RegisterAll();

	CXTPMarkupSetter::RegisterType();
	CXTPMarkupFrameworkElement::RegisterType();
	CXTPMarkupUIElement::RegisterType();
	CXTPMarkupTextElement::RegisterType();
	CXTPMarkupBorder::RegisterType();
	CXTPMarkupCanvas::RegisterType();
	CXTPMarkupSolidColorBrush::RegisterType();
	CXTPMarkupGradientStop::RegisterType();
	CXTPMarkupLinearGradientBrush::RegisterType();
	CXTPMarkupColumnDefinition::RegisterType();
	CXTPMarkupRowDefinition::RegisterType();
	CXTPMarkupGrid::RegisterType();
	CXTPMarkupImage::RegisterType();
	CXTPMarkupPanel::RegisterType();
	CXTPMarkupControl::RegisterType();
	CXTPMarkupContentControl::RegisterType();
	CXTPMarkupButtonBase::RegisterType();
	CXTPMarkupToggleButton::RegisterType();
	CXTPMarkupButton::RegisterType();
	CXTPMarkupFrameworkContentElement::RegisterType();
	CXTPMarkupInline::RegisterType();
	CXTPMarkupRun::RegisterType();
	CXTPMarkupHyperlink::RegisterType();
	CXTPMarkupInputElement::RegisterType();
	CXTPMarkupPage::RegisterType();
	CXTPMarkupShape::RegisterType();
	CXTPMarkupPolygon::RegisterType();
	CXTPMarkupPolyline::RegisterType();
	CXTPMarkupLine::RegisterType();
	CXTPMarkupEllipse::RegisterType();
	CXTPMarkupRectangle::RegisterType();
	CXTPMarkupStackPanel::RegisterType();
	CXTPMarkupWrapPanel::RegisterType();
	CXTPMarkupTextBlock::RegisterType();
	CXTPMarkupScrollViewer::RegisterType();
	CXTPMarkupStyle::RegisterType();
	CXTPMarkupDockPanel::RegisterType();
	CXTPMarkupUniformGrid::RegisterType();

	CXTPMarkupPath::RegisterType();
	CXTPMarkupPathData::RegisterType();
}

CXTPMarkupContext::~CXTPMarkupContext()
{
	CMDTARGET_RELEASE(m_pImageManager);

	m_pMouseOver = NULL;
	MARKUP_RELEASE(m_pKeyboardNavigation);

	ASSERT(m_pFonts == NULL || m_pFonts->IsEmpty());

	SAFE_DELETE(m_pHandlers);
	SAFE_DELETE(m_pDelegates);
	SAFE_DELETE(m_pFonts);

	CMDTARGET_RELEASE(m_pToolTipContext);

	ASSERT(m_dwRef <= 1);

	CXTPMarkupDrawingContext::Register(FALSE);
}

CXTPMarkupObject* CXTPMarkupContext::CreateMarkupObject(CXTPMarkupType* pType)
{
	CXTPMarkupObject* pObject = pType->CreateObject();
	if (!pObject)
		return NULL;

	if (pObject->IsKindOf(MARKUP_TYPE(CXTPMarkupInputElement)))
	{
		((CXTPMarkupInputElement*)pObject)->m_pMarkupContext = this;
		AddRef();
	}

	return (CXTPMarkupObject*)pObject;
}

void CXTPMarkupContext::Cleanup()
{
	m_pMouseOver = NULL;
	m_pActiveElement = NULL;

	if (m_pMouseCapture)
	{
		m_pMouseCapture = NULL;
		ReleaseCapture();
	}
}

void CXTPMarkupContext::FinalizeMarkupObject(CXTPMarkupInputElement* pInputElement)
{
	if (pInputElement == m_pMouseOver)
		m_pMouseOver = NULL;

	if (pInputElement == m_pActiveElement)
		m_pActiveElement = NULL;

	if (pInputElement == m_pMouseCapture)
	{
		m_pMouseCapture = NULL;
		ReleaseCapture();
	}

	pInputElement->m_pMarkupContext = NULL;
	Release();
}

CXTPMarkupUIElement* CXTPMarkupContext::Parse(LPCSTR lpszBuffer)
{
	Cleanup();

	if (!lpszBuffer)
		return NULL;

	CXTPMarkupParser sc;
	sc.SetBuffer(lpszBuffer, lpszBuffer + strlen(lpszBuffer));

	CXTPMarkupBuilder builder(this);
	return builder.Parse(&sc);
}

CXTPMarkupUIElement* CXTPMarkupContext::Parse(LPCWSTR lpszBuffer)
{
	Cleanup();

	if (!lpszBuffer)
		return NULL;

	CXTPMarkupParser sc;
	sc.SetBuffer(lpszBuffer, lpszBuffer + wcslen(lpszBuffer));

	CXTPMarkupBuilder builder(this);
	return builder.Parse(&sc);
}

CString CXTPMarkupContext::ValidateXML(LPCWSTR lpszBuffer)
{
	Cleanup();

	if (!lpszBuffer)
		return _T("No Text To Parse.");

	CXTPMarkupParser sc;
	sc.SetBuffer(lpszBuffer, lpszBuffer + wcslen(lpszBuffer));

	CXTPMarkupBuilder builder(this);
	CXTPMarkupUIElement* pUIElement = builder.Parse(&sc);

	BOOL bError = TRUE;

	if (pUIElement)
		bError = FALSE;

	MARKUP_RELEASE(pUIElement);

	if (bError)
	{
		LPCTSTR lpszLastError = builder.GetLastError();

		LPCTSTR lpszIndex = _tcsstr(lpszLastError, _T(". Line "));
		if (lpszIndex == NULL)
			return lpszLastError;

		((LPTSTR)lpszIndex)[1] = 0;

		CString str;
		str.Format(_T("<TextBlock VerticalAlignment='Center'>%s <Hyperlink>%s</Hyperlink></TextBlock>"), lpszLastError, lpszIndex + 2);

		((LPTSTR)lpszIndex)[1] = ' ';

		return str;
	}
	else
	{
		return _T("Done.");
	}
}

BOOL CXTPMarkupContext::CompareFont(LOGFONT* pLogFont1, LOGFONT* pLogFont2)
{
	if (pLogFont1->lfHeight != pLogFont2->lfHeight)
		return FALSE;

	if (pLogFont1->lfWeight != pLogFont2->lfWeight)
		return FALSE;

	if (pLogFont1->lfItalic != pLogFont2->lfItalic)
		return FALSE;

	if (pLogFont1->lfQuality != pLogFont2->lfQuality)
		return FALSE;

	if (pLogFont1->lfEscapement != pLogFont2->lfEscapement)
		return FALSE;

	if (pLogFont1->lfOrientation != pLogFont2->lfOrientation)
		return FALSE;

	if (_tcscmp(pLogFont1->lfFaceName, pLogFont2->lfFaceName) != 0)
		return FALSE;

	return TRUE;
}

CXTPMarkupFont* CXTPMarkupContext::GetFont(LOGFONT* pLogFont)
{
	if (m_pFonts == NULL)
		m_pFonts = new CXTPMarkupFontArray();

	CXTPMarkupFont* pFont;

	for (pFont = m_pFonts->GetHead(); pFont != NULL; pFont = pFont->m_pNextChain)
	{
		if (CompareFont(&pFont->m_lf, pLogFont))
		{
			pFont->AddRef();
			return pFont;
		}
	}

	pFont = new CXTPMarkupFont();
	m_pFonts->AddTail(pFont);
	pFont->m_lf = *pLogFont;
	pFont->m_hFont = ::CreateFontIndirect(pLogFont);
	pFont->m_pMarkupContext = this;

	return pFont;
}

BOOL CXTPMarkupContext::IsVisualChild(CXTPMarkupObject* pParent, CXTPMarkupObject* pChild) const
{
	while (pChild)
	{
		if (pChild == pParent)
			return TRUE;

		pChild = pChild->GetLogicalParent();
	}
	return FALSE;
}

void CXTPMarkupContext::BuildInputList(CXTPMarkupObject* pUIElement, CInputElementCollection* arrObjects)
{
	CXTPMarkupObject* pParent = pUIElement;
	while (pParent)
	{
		if (pParent->IsKindOf(MARKUP_TYPE(CXTPMarkupInputElement)))
		{
			arrObjects->Add((CXTPMarkupInputElement*)pParent);
			pParent->AddRef();
		}

		pParent = pParent->GetLogicalParent();
	}
}

INT_PTR CXTPMarkupContext::OnToolHitTest(CPoint /*point*/, TOOLINFO* pToolInfo)
{
	CInputElementCollection listMouseOver;
	BuildInputList(m_pMouseOver, &listMouseOver);

	for (int i = 0; i < listMouseOver.GetCount(); i++)
	{
		CXTPMarkupInputElement* pInputElement = listMouseOver.GetItem(i);

		CXTPMarkupObject* pToolTip = pInputElement->GetToolTip();
		if (pToolTip && IsStringObject(pToolTip))
		{
			CXTPToolTipContext::FillInToolInfo(pToolInfo, m_hContextWnd, GetClientBoundingRect(pInputElement),
				(INT_PTR)pInputElement, (LPCWSTR)*((CXTPMarkupString*)pToolTip));
			return pToolInfo->uId;
		}
	}

	return -1;
}

void CXTPMarkupContext::HandleMouseEnter(CXTPMarkupInputElement* pMouseOver, CPoint point)
{
	if (m_pMouseOver == pMouseOver)
		return;

	if (!pMouseOver)
		m_pActiveElement = NULL;

	CInputElementCollection listOldMouseOver;
	CInputElementCollection listNewMouseOver;

	BuildInputList(m_pMouseOver, &listOldMouseOver);
	BuildInputList(pMouseOver, &listNewMouseOver);

	while (listOldMouseOver.GetCount() > 0 && listNewMouseOver.GetCount() > 0 &&
		listOldMouseOver.GetTailItem() == listNewMouseOver.GetTailItem())
	{
		listNewMouseOver.Remove(listNewMouseOver.GetCount() - 1);
		listOldMouseOver.Remove(listOldMouseOver.GetCount() - 1);
	}

	CXTPMarkupMouseEventArgs* eMouseLeaveEventArgs = new CXTPMarkupMouseEventArgs(CXTPMarkupInputElement::m_pMouseLeaveEvent);
	CXTPMarkupMouseEventArgs* eMouseEnterEventArgs = new CXTPMarkupMouseEventArgs(CXTPMarkupInputElement::m_pMouseEnterEvent);

	eMouseLeaveEventArgs->SetSource(m_pMouseOver);
	eMouseLeaveEventArgs->m_hWnd = m_hContextWnd;
	eMouseLeaveEventArgs->m_point = point;

	eMouseEnterEventArgs->SetSource(pMouseOver);
	eMouseEnterEventArgs->m_hWnd = m_hContextWnd;
	eMouseEnterEventArgs->m_point = point;


	m_pMouseOver = pMouseOver;

	int i;
	for (i = 0; i < listOldMouseOver.GetCount(); i++)
	{
		CXTPMarkupInputElement* pInputElement = listOldMouseOver.GetItem(i);

		pInputElement->RaiseEvent(eMouseLeaveEventArgs);
		if (eMouseLeaveEventArgs->IsHandled())
			break;

		pInputElement->OnMouseLeave(eMouseLeaveEventArgs);
		if (eMouseLeaveEventArgs->IsHandled())
			break;
	}

	for (i = 0; i < listNewMouseOver.GetCount(); i++)
	{
		CXTPMarkupInputElement* pInputElement = listNewMouseOver.GetItem(i);

		pInputElement->RaiseEvent(eMouseEnterEventArgs);
		if (eMouseEnterEventArgs->IsHandled())
			break;

		pInputElement->OnMouseEnter(eMouseEnterEventArgs);
		if (eMouseEnterEventArgs->IsHandled())
			break;
	}

	eMouseLeaveEventArgs->Release();
	eMouseEnterEventArgs->Release();
}


void CXTPMarkupContext::HandleMouseMove(CXTPMarkupUIElement* pUIElement, CPoint point)
{
	CXTPMarkupInputElement* pObject = pUIElement->InputHitTest(point);
	if (m_pMouseCapture)
	{
		if ((pObject == NULL) || !IsVisualChild(m_pMouseCapture, pObject))
			pObject = NULL;
		else
			pObject = m_pMouseCapture;
	}

	if (m_pMouseOver != pObject)
	{
		HandleMouseEnter(pObject, point);

		if (m_pMouseOver)
		{
			TRACKMOUSEEVENT tme = { sizeof(TRACKMOUSEEVENT), TME_LEAVE, m_hContextWnd, 0 };
			_TrackMouseEvent (&tme);

		}

		if (!HandleSetCursor())
		{
			SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
		}
	}

	m_pActiveElement = m_pMouseOver ? pUIElement : NULL;

	if (m_pMouseOver)
	{
		CInputElementCollection listNewMouseOver;
		BuildInputList(m_pMouseOver, &listNewMouseOver);

		CXTPMarkupMouseEventArgs* eMouseMoveEventArgs = new CXTPMarkupMouseEventArgs(CXTPMarkupInputElement::m_pMouseMoveEvent);
		eMouseMoveEventArgs->SetSource(m_pMouseOver);
		eMouseMoveEventArgs->m_hWnd = m_hContextWnd;
		eMouseMoveEventArgs->m_point = point;

		for (int i = 0; i < listNewMouseOver.GetCount(); i++)
		{
			CXTPMarkupInputElement* pInputElement = listNewMouseOver.GetItem(i);

			pInputElement->RaiseEvent(eMouseMoveEventArgs);
			if (eMouseMoveEventArgs->IsHandled())
				break;

			pInputElement->OnMouseMove(eMouseMoveEventArgs);
			if (eMouseMoveEventArgs->IsHandled())
				break;
		}

		eMouseMoveEventArgs->Release();
	}
}

BOOL CXTPMarkupContext::HandleSetCursor()
{
	if (m_pMouseOver)
	{
		CInputElementCollection listNewMouseOver;
		BuildInputList(m_pMouseOver, &listNewMouseOver);

		CXTPMarkupQueryCursorEventArgs eQueryCursorEventArgs;
		eQueryCursorEventArgs.SetSource(m_pMouseOver);

		for (int i = 0; i < listNewMouseOver.GetCount(); i++)
		{
			CXTPMarkupInputElement* pInputElement = listNewMouseOver.GetItem(i);

			pInputElement->OnQueryCursor(&eQueryCursorEventArgs);
			if (!eQueryCursorEventArgs.IsHandled())
				continue;

			if (eQueryCursorEventArgs.m_hCursor)
			{
				::SetCursor(eQueryCursorEventArgs.m_hCursor);
				return TRUE;
			}

			return FALSE;
		}
	}
	return FALSE;
}

BOOL CXTPMarkupContext::HandleMouseWheel(int nDelta)
{
	if (m_pMouseOver)
	{
		CInputElementCollection listNewMouseOver;
		BuildInputList(m_pMouseOver, &listNewMouseOver);

		CXTPMarkupMouseWheelEventArgs eMouseWheelEventArgs;
		eMouseWheelEventArgs.m_nDelta = nDelta;
		eMouseWheelEventArgs.SetSource(m_pMouseOver);

		for (int i = 0; i < listNewMouseOver.GetCount(); i++)
		{
			CXTPMarkupInputElement* pInputElement = listNewMouseOver.GetItem(i);

			pInputElement->OnMouseWheel(&eMouseWheelEventArgs);
			if (eMouseWheelEventArgs.IsHandled())
				return TRUE;
		}
	}
	return FALSE;
}

BOOL CXTPMarkupContext::HandleMouseUpDown(UINT message, WPARAM /*wParam*/, LPARAM lParam)
{
	CXTPMarkupInputElement* pMouseOver = m_pMouseOver;
	if (m_pMouseCapture)
		pMouseOver = m_pMouseCapture;

	if (!pMouseOver)
		return FALSE;

	CInputElementCollection listNewMouseOver;
	BuildInputList(pMouseOver, &listNewMouseOver);

	CXTPMarkupMouseButtonEventArgs* eMouseButtonEventArgs = new CXTPMarkupMouseButtonEventArgs(
		message == WM_LBUTTONDOWN  || message == WM_LBUTTONDBLCLK ? CXTPMarkupInputElement::m_pMouseLeftButtonDownEvent :
		message == WM_LBUTTONUP ? CXTPMarkupInputElement::m_pMouseLeftButtonUpEvent :
		message == WM_RBUTTONDOWN ? CXTPMarkupInputElement::m_pMouseRightButtonDownEvent :
		message == WM_RBUTTONUP ? CXTPMarkupInputElement::m_pMouseRightButtonUpEvent : NULL);

	eMouseButtonEventArgs->SetSource(pMouseOver);
	eMouseButtonEventArgs->m_hWnd = m_hContextWnd;
	eMouseButtonEventArgs->m_point = lParam;

	for (int i = 0; i < listNewMouseOver.GetCount(); i++)
	{
		CXTPMarkupInputElement* pInputElement = listNewMouseOver.GetItem(i);

		pInputElement->RaiseEvent(eMouseButtonEventArgs);
		if (eMouseButtonEventArgs->IsHandled())
			break;

		if (message == WM_LBUTTONDOWN || message == WM_LBUTTONDBLCLK)
		{
			pInputElement->OnMouseLeftButtonDown(eMouseButtonEventArgs);
		}
		else if (message == WM_LBUTTONUP)
		{
			pInputElement->OnMouseLeftButtonUp(eMouseButtonEventArgs);
		}
		else if (message == WM_RBUTTONDOWN)
		{
			pInputElement->OnMouseRightButtonDown(eMouseButtonEventArgs);
		}
		else if (message == WM_RBUTTONUP)
		{
			pInputElement->OnMouseRightButtonUp(eMouseButtonEventArgs);
		}

		if (eMouseButtonEventArgs->IsHandled())
			break;
	}

	BOOL bHandled = eMouseButtonEventArgs->IsHandled();

	eMouseButtonEventArgs->Release();


	return bHandled;
}

void CXTPMarkupContext::CaptureMouse(CXTPMarkupInputElement* pUIElement)
{
	if (m_pMouseCapture == pUIElement)
		return;

	::SetCapture(m_hContextWnd);
	m_pMouseCapture = pUIElement;
}

void CXTPMarkupContext::ReleaseMouseCapture(CXTPMarkupInputElement* /*pUIElement*/)
{
	m_pMouseCapture = NULL;
	::ReleaseCapture();
}

BOOL CXTPMarkupContext::OnWndMsg(CXTPMarkupUIElement* pUIElement, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	if (!m_hContextWnd)
		return FALSE;

	if (!pUIElement)
	{
		if (m_pActiveElement)
		{
			HandleMouseEnter(NULL, CPoint(-1, -1));
		}
		return FALSE;
	}

	if (message == WM_MOUSEMOVE)
	{
		HandleMouseMove(pUIElement, CPoint(lParam));
	}

	if (message == WM_DESTROY || message == WM_MOUSELEAVE)
	{
		HandleMouseEnter(NULL, CPoint(-1, -1));
	}

	if ((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) || (message == WM_MOUSELEAVE))
	{
		m_pToolTipContext->FilterToolTipMessage(CWnd::FromHandle(m_hContextWnd), message, wParam, lParam);
	}

	if (message == WM_SETCURSOR)
	{
		if (HandleSetCursor())
		{
			*pResult = TRUE;
			return TRUE;
		}
	}

	if (message == WM_MOUSEWHEEL)
	{
		if (HandleMouseWheel((short) HIWORD(wParam)))
		{
			*pResult = TRUE;
			return TRUE;
		}
	}

	if (message == WM_LBUTTONDOWN || message == WM_RBUTTONDOWN || message == WM_LBUTTONUP || message == WM_RBUTTONUP || message == WM_LBUTTONDBLCLK)
	{
		if (HandleMouseUpDown(message, wParam, lParam))
			return TRUE;
	}

	if (message == WM_CAPTURECHANGED && m_pMouseCapture)
	{
		CXTPMarkupMouseEventArgs* eLostMouseCaptureEventArgs = new CXTPMarkupMouseEventArgs(CXTPMarkupInputElement::m_pLostMouseCaptureEvent);
		eLostMouseCaptureEventArgs->SetSource(m_pMouseCapture);

		CXTPMarkupInputElement* pInputElement = m_pMouseCapture;

		pInputElement->RaiseEvent(eLostMouseCaptureEventArgs);

		if (!eLostMouseCaptureEventArgs->IsHandled())
		{
			pInputElement->OnLostMouseCapture(eLostMouseCaptureEventArgs);
		}
		eLostMouseCaptureEventArgs->Release();

		m_pMouseCapture = NULL;
	}

	if (message == WM_KEYDOWN || message == WM_SETFOCUS || message == WM_KILLFOCUS)
	{
		if (m_pKeyboardNavigation->OnWndMsg(message, wParam, lParam, pResult))
			return TRUE;
	}



	return FALSE;
}

void CXTPMarkupContext::RaiseEvent(CXTPMarkupObject* pSource, CXTPMarkupRoutedEventArgs* pEventArgs)
{
	if (m_pHandlers) m_pHandlers->Raise(pSource, pEventArgs);
}

void CXTPMarkupContext::AddHandler(CXTPMarkupRoutedEvent* pEvent, CXTPMarkupDelegate* pDelegate)
{
	if (m_pHandlers == NULL)
		m_pHandlers = new CXTPMarkupEventHandlerMap();

	m_pHandlers->Add(pEvent, pDelegate);
}

void CXTPMarkupContext::SetDelegate(LPWSTR lpszHandler, CXTPMarkupDelegate* pDelegate)
{
	if (m_pDelegates == NULL)
		m_pDelegates = new CXTPMarkupDelegateMap();

	m_pDelegates->Add(lpszHandler, pDelegate);
}

CXTPMarkupDelegate* CXTPMarkupContext::LookupDelegate(LPCWSTR lpszDelegate) const
{
	if (m_pDelegates == NULL)
		return NULL;

	CXTPMarkupDelegate* pDelegate = m_pDelegates->Lookup(lpszDelegate);


	return pDelegate;
}

CRect CXTPMarkupContext::GetClientBoundingRect(CXTPMarkupInputElement* pInputElement) const
{
	CRect rc(0, 0, 0, 0);

	if (!pInputElement)
		return rc;

	CXTPMarkupVisual* pVisual = NULL;
	if (pInputElement->IsKindOf(MARKUP_TYPE(CXTPMarkupVisual)))
	{
		pVisual = (CXTPMarkupVisual*)pInputElement;
		rc = pVisual->GetBoundRect();
	}
	else if (pInputElement->IsKindOf(MARKUP_TYPE(CXTPMarkupFrameworkContentElement)))
	{
		pVisual = ((CXTPMarkupFrameworkContentElement*)pInputElement)->GetParent();
		rc = ((CXTPMarkupFrameworkContentElement*)pInputElement)->GetBoundRect();
	}

	if (!pVisual)
		return rc;

	while (pVisual != 0)
	{
		rc.OffsetRect(pVisual->GetVisualOffset());
		pVisual = pVisual->GetVisualParent();
	}

	return rc;
}


void CXTPMarkupContext::OnInvalidateVisual(CXTPMarkupUIElement* pUIElement)
{
	if (m_hContextWnd)
	{
		InvalidateRect(m_hContextWnd, GetClientBoundingRect(pUIElement), FALSE);
		::SendMessage(m_hContextWnd, XTP_WM_MARKUPREDRAW, 0, 0);
	}
}

void CXTPMarkupContext::OnInvalidateArrange(CXTPMarkupUIElement* /*pUIElement*/)
{
	if (m_hContextWnd)
	{
		InvalidateRect(m_hContextWnd, NULL, FALSE);
		::SendMessage(m_hContextWnd, XTP_WM_MARKUPREDRAW, 0, 0);
	}
}

void CXTPMarkupContext::AddRef()
{
	InterlockedIncrement(&m_dwRef);
}

void CXTPMarkupContext::Release()
{
	if (m_dwRef == 0)
		return;

	LONG lResult = InterlockedDecrement(&m_dwRef);
	if (lResult == 0)
	{
		delete this;
	}
}

void CXTPMarkupContext::SetImageManager(CXTPImageManager* pImageManager)
{
	CMDTARGET_RELEASE(m_pImageManager);

	m_pImageManager = pImageManager;
}

CXTPImageManager* CXTPMarkupContext::GetImageManager() const
{
	if (m_pImageManager)
		return m_pImageManager;

	return XTPImageManager();
}