// XTPReportSubListControl.cpp : implementation of the CXTPReportSubListControl class.
//
// This file is a part of the XTREME REPORTCONTROL 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/XTPDrawHelpers.h"
#include "Common/XTPMarkupRender.h"
#include "Common/XTPCustomHeap.h"
#include "Common/XTPSystemHelpers.h"
#include "Common/XTPSmartPtrInternalT.h"
#include "Common/XTPColorManager.h"

#include "XTPReportDefines.h"
#include "XTPReportControl.h"
#include "XTPReportColumn.h"
#include "XTPReportColumns.h"
#include "XTPReportDragDrop.h"
#include "XTPReportSubListControl.h"
#include "XTPReportHeader.h"
#include "XTPReportPaintManager.h"

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

IMPLEMENT_DYNAMIC(CXTPReportSubListControl, CListBox)
/////////////////////////////////////////////////////////////////////////////
// CXTPReportSubListControl

CXTPReportSubListControl::CXTPReportSubListControl()
{
	m_pReportCtrl = NULL;
	m_pDragWnd = NULL;
	m_bSortAscending = FALSE;
	m_nDropIndex = 0;
}

CXTPReportSubListControl::~CXTPReportSubListControl()
{
}


BEGIN_MESSAGE_MAP(CXTPReportSubListControl, CListBox)
	//{{AFX_MSG_MAP(CXTPReportSubListControl)
	ON_WM_ERASEBKGND()
	ON_WM_LBUTTONDOWN()
	ON_WM_PAINT()
	ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CXTPReportSubListControl attributes

BOOL CXTPReportSubListControl::SetReportCtrl(CXTPReportControl* pReportCtrl)
{
	if (pReportCtrl == NULL)
		return FALSE;

	ASSERT_KINDOF(CXTPReportControl, pReportCtrl);

	if (m_pReportCtrl != pReportCtrl)
	{
		ResetContent();
		m_pReportCtrl = pReportCtrl;
	}

	UpdateList();

	return TRUE;
}

CXTPReportControl* CXTPReportSubListControl::GetReportCtrl()
{
	return m_pReportCtrl;
}

/////////////////////////////////////////////////////////////////////////////
// CXTPReportSubListControl operations

void CXTPReportSubListControl::SortAscending(BOOL bSort)
{
	m_bSortAscending = bSort;
	if (GetSafeHwnd()) ResetContent();
	UpdateList();
}

BOOL CXTPReportSubListControl::UpdateList()
{
	if (m_pReportCtrl == NULL)
		return FALSE;

	if (GetSafeHwnd() == NULL)
		return FALSE;

	CClientDC dc(this);
	CXTPFontDC fnt(&dc, &m_pReportCtrl->GetPaintManager()->m_fontCaption);
	int nHeight = dc.GetTextExtent(_T(" "), 1).cy + 5;

	if (GetItemHeight(0) != nHeight) SetItemHeight(0, nHeight);


	CXTPReportColumns* pColumns = m_pReportCtrl->GetColumns();
	int nColumnCount = pColumns->GetCount();

	BOOL bChanged = FALSE;
	// delete all visible items from the list
	for (int i = GetCount() - 1; i >= 0; i--)
	{
		int nItemIndex = (int)GetItemData(i);
		CXTPReportColumn* pColumn = pColumns->Find(nItemIndex);
		if (!pColumn || pColumn->IsVisible() || !pColumn->IsShowInFieldChooser())
		{
			DeleteString(i);
			bChanged = TRUE;
		}
	}

	// add the rest of invisible items
	for (int nColumn = 0; nColumn < nColumnCount; nColumn++)
	{
		CXTPReportColumn* pColumn = pColumns->GetAt(nColumn);
		if (pColumn && !pColumn->IsVisible() && pColumn->IsShowInFieldChooser()
			&& (m_pReportCtrl->m_iIconViewColumn == -1 ? TRUE : (pColumn->GetItemIndex() != m_pReportCtrl->m_iIconViewColumn ? TRUE : FALSE)))
		{
			int nListItem = FindItemData(pColumn->GetItemIndex());
			if (nListItem < 0)
			{
				int nItem = -1;
				if (m_bSortAscending)
				{
					for (nItem = 0; nItem < GetCount(); nItem++)
					{
						CString str = GetItemCaption(nItem);

						if (str > pColumn->GetCaption())
							break;
					}
					nItem = InsertString(nItem, pColumn->GetCaption());
				}
				else
				{
					nItem = AddString(pColumn->GetCaption());
				}

				if (nItem >= 0)
				{
					SetItemData(nItem, pColumn->GetItemIndex());
					bChanged = TRUE;
				}
			}
		}
	}
	EnableWindow(GetCount() > 0);

	if (bChanged)
		Invalidate();

	return TRUE;
}

CXTPReportColumn* CXTPReportSubListControl::GetItemColumn(int nIndex)
{
	if (!m_pReportCtrl || GetSafeHwnd() == 0)
		return NULL;

	int nItemData = (int)GetItemData(nIndex);
	if (nItemData == -1)
		return NULL;

	CXTPReportColumn* pColumn = m_pReportCtrl->GetColumns()->Find(nItemData);

	return pColumn;
}

CString CXTPReportSubListControl::GetItemCaption(int nIndex)
{
	if (!m_pReportCtrl || GetSafeHwnd() == 0)
		return _T("");

	if (GetStyle() & LBS_HASSTRINGS)
	{
		CString str;
		GetText(nIndex, str);
		return str;
	}

	CXTPReportColumn* pColumn = GetItemColumn(nIndex);

	if (pColumn == NULL)
		return _T("");

	return pColumn->GetCaption();

}


int CXTPReportSubListControl::FindItemData(int nItemData)
{
	for (int i = GetCount() - 1; i >= 0; i--)
	{
		int nItemIndex = (int)GetItemData(i);
		if (nItemData == nItemIndex)
			return i;
	}
	return -1;
}

BOOL CXTPReportSubListControl::Include(int /*iSubItem*/)
{
	return TRUE;
}

BOOL CXTPReportSubListControl::Disable(int /*iSubItem*/)
{
	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////
// CXTPReportSubListControl message handlers

void CXTPReportSubListControl::PreSubclassWindow()
{
	CListBox::PreSubclassWindow();
}

void CXTPReportSubListControl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);

	CRect rcItem(lpDrawItemStruct->rcItem);

	CXTPReportPaintManager* pPaintManager = m_pReportCtrl ? m_pReportCtrl->GetPaintManager() : NULL;
	COLORREF clrBack = pPaintManager ? pPaintManager->m_clrControlBack : ::GetXtremeColor(COLOR_WINDOW);


	if (GetCount() > 0 && m_pReportCtrl && pPaintManager)
	{
		BOOL bDisable = Disable((int)lpDrawItemStruct->itemData);

		CXTPFontDC fnt(pDC, &pPaintManager->m_fontCaption);

		if (GetExStyle() & WS_EX_STATICEDGE)
		{
			pDC->Draw3dRect(rcItem, pPaintManager->m_clrHighlightText, pPaintManager->m_clrControlDark);
			rcItem.DeflateRect(1, 1);
			pDC->FillSolidRect(rcItem, pPaintManager->m_clrControlBack);
			rcItem.DeflateRect(1, 1);
		}
		else
		{
			pDC->FillSolidRect(rcItem, pPaintManager->m_clrHeaderControl);
			pDC->Draw3dRect(rcItem, pPaintManager->m_clrBtnFace, GetXtremeColor(COLOR_3DDKSHADOW));
			rcItem.DeflateRect(1, 1);
			pDC->Draw3dRect(rcItem, pPaintManager->m_clrControlBack, pPaintManager->m_clrControlDark);
			rcItem.DeflateRect(1, 1);

		}

		pDC->SetBkMode(TRANSPARENT);

		CXTPReportColumn* pColumn = GetItemColumn((int)lpDrawItemStruct->itemID);
		BOOL bSelected = lpDrawItemStruct->itemState & ODS_SELECTED;

		pDC->SetTextColor(pPaintManager->m_clrCaptionText);

		if (bSelected)
		{
			pDC->FillSolidRect(rcItem, GetXtremeColor(COLOR_3DFACE));
			pDC->InvertRect(rcItem);
			pDC->SetTextColor(bDisable ? ::GetXtremeColor(COLOR_BTNFACE) : ::GetXtremeColor(COLOR_3DHIGHLIGHT));
		}

		CXTPMarkupUIElement* pMarkupUIElement = pColumn->GetMarkupUIElement();

		if (pMarkupUIElement)
		{
			XTPMarkupSetDefaultFont(XTPMarkupElementContext(pMarkupUIElement),
				(HFONT)pDC->GetCurrentFont()->GetSafeHandle(), pDC->GetTextColor());

			XTPMarkupMeasureElement(pMarkupUIElement, rcItem.Width(), INT_MAX);
			XTPMarkupRenderElement(pMarkupUIElement, pDC->GetSafeHdc(), &rcItem);

		}
		else
		{
			if (bDisable && !bSelected)
			{
				pDC->SetTextColor(::GetXtremeColor(COLOR_3DHIGHLIGHT));

				CRect rect = rcItem;
				rect.OffsetRect(1, 1);

				pDC->DrawText(pColumn->GetCaption(), rect,
					DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_END_ELLIPSIS | DT_LEFT);

				pDC->SetTextColor(::GetXtremeColor(COLOR_3DSHADOW));
			}

			pDC->DrawText(pColumn->GetCaption(), rcItem,
				DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_END_ELLIPSIS | DT_LEFT);
		}

	}
	else
		pDC->FillSolidRect(rcItem, clrBack);
}

BOOL CXTPReportSubListControl::BeginDrag(int nItem)
{
	if (GetCount() <= 0)
		return FALSE;

	int nSubItem = (int)GetItemData(nItem);

	if (Disable(nSubItem))
	{
		return FALSE;
	}

	GetClientRect(m_rcDragWnd);
	m_rcDragWnd.bottom = m_rcDragWnd.top + GetItemHeight(0);

	CXTPReportHeader* pHeader = m_pReportCtrl->GetReportHeader();
	CXTPReportColumn* pColumn = m_pReportCtrl->GetColumns()->Find(nSubItem);
	pHeader->StartDragging(pColumn);
	pHeader->m_bDragGroupBox = FALSE;

	//pHeader->m_nDragIndex = m_nSubItem;
	m_pDragWnd = new CXTPReportHeaderDragWnd;
	if (m_pDragWnd)
		m_pDragWnd->Create(m_rcDragWnd, pHeader, m_pReportCtrl->GetPaintManager(), pColumn);
	m_pReportCtrl->SetMouseMode(xtpReportMouseDraggingColumn);

	GetWindowRect(m_rcDropTarget1);
	m_rcDropTarget2 = m_pReportCtrl->m_rcHeaderArea;

	if (pColumn->IsGroupable())
		m_rcDropTarget2.UnionRect(&m_rcDropTarget2, &m_pReportCtrl->m_rcGroupByArea);

	m_pReportCtrl->ClientToScreen(m_rcDropTarget2);

	m_nDropIndex = -1;

	return TRUE;
}

UINT CXTPReportSubListControl::Dragging(CPoint pt)
{
	CPoint point = pt;
	point.Offset(-(m_rcDragWnd.Width() >> 1), -(m_rcDragWnd.Height() >> 1));

	if (m_pDragWnd != NULL)
	{
		m_pDragWnd->SetWindowPos(&wndTop,
			point.x, point.y, 0, 0,
			SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE);
	}

	if (m_pReportCtrl)
	{
		CPoint pointCtrl(pt);
		m_pReportCtrl->ScreenToClient(&pointCtrl);
		m_pReportCtrl->OnMouseMove(0, pointCtrl);
	}


	if (m_rcDropTarget1.PtInRect(pt))
		return DL_MOVECURSOR;

	if (m_rcDropTarget2.PtInRect(pt))
		return DL_MOVECURSOR;

	return DL_STOPCURSOR;
}

void CXTPReportSubListControl::CancelDrag()
{
	if (m_pDragWnd != NULL)
	{
		m_pDragWnd->DestroyWindow();
		m_pDragWnd = NULL;
	}

	CXTPReportHeader* pHeader = m_pReportCtrl->GetReportHeader();
	pHeader->SetHotDivider(-1);

	m_pReportCtrl->SetMouseMode(xtpReportMouseNothing);
}

void CXTPReportSubListControl::Dropped(CPoint pt)
{
	if (m_pDragWnd != NULL)
	{
		m_pDragWnd->DestroyWindow();
		m_pDragWnd = NULL;
	}

	if (m_pReportCtrl)
	{
		m_pReportCtrl->ScreenToClient(&pt);
		m_pReportCtrl->OnLButtonUp(0, pt);
	}
}

void CXTPReportSubListControl::OnPaint()
{
	CPaintDC dcPaint(this);
	CRect rc;
	GetClientRect(rc);

	CXTPBufferDC dc(dcPaint, rc);

	CXTPReportPaintManager* pPaintManager = m_pReportCtrl ? m_pReportCtrl->GetPaintManager() : NULL;
	COLORREF clrBack = pPaintManager ? pPaintManager->m_clrControlBack : GetXtremeColor(COLOR_WINDOW);

	dc.FillSolidRect(rc, IsWindowEnabled() ? clrBack : GetXtremeColor(COLOR_BTNFACE));

	if (GetCount() > 0 || !pPaintManager)
		CWnd::DefWindowProc(WM_PAINT, (WPARAM)dc.m_hDC, 0);
	else
	{
		dc.SetTextColor(GetXtremeColor(COLOR_3DSHADOW));
		dc.SetBkMode(TRANSPARENT);
		CXTPFontDC fnt(&dc, &pPaintManager->m_fontCaption);

		dc.DrawText(pPaintManager->m_strNoFieldsAvailable, rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOPREFIX);
	}
}

LRESULT CXTPReportSubListControl::OnPrintClient(WPARAM wParam, LPARAM lParam)
{
	CListBox::DefWindowProc(WM_ERASEBKGND, wParam, 0);
	return CListBox::DefWindowProc(WM_PRINTCLIENT, wParam, lParam);
}

BOOL CXTPReportSubListControl::OnEraseBkgnd(CDC* /*pDC*/)
{
	return TRUE;
}


void CXTPReportSubListControl::OnLButtonDown(UINT nFlags, CPoint point)
{
	SetFocus();

	BOOL bOutside = TRUE;
	int nItem = ItemFromPoint(point, bOutside);
	if (nItem == LB_ERR)
	{
		CWnd::OnLButtonDown(nFlags, point);
		return;
	}

	SetCurSel(nItem);
	ParentNotify_SelChangd();

	BOOL bAccept = FALSE;
	BOOL bStartDrag = FALSE;

	HCURSOR hCursorNo = AfxGetApp()->LoadStandardCursor(IDC_NO), hCursorArrow = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
	SetCapture();

	while (CWnd::GetCapture() == this)
	{
		MSG msg;
		if (!GetMessage(&msg, NULL, 0, 0))
			break;

		if (msg.message == WM_MOUSEMOVE)
		{
			CPoint pt(msg.lParam);

			if (point != pt)
			{
				if (!bStartDrag && abs(point.x - pt.x) + abs(point.y - pt.y) < 3)
					continue;

				point = pt;

				if (!bStartDrag)
				{
					BeginDrag(nItem);
					bStartDrag = TRUE;
				}

				if (bStartDrag)
				{
					ClientToScreen(&pt);
					UINT nCursor = Dragging(pt);
					::SetCursor(nCursor == DL_STOPCURSOR ? hCursorNo : hCursorArrow);
				}
			}
		}
		else if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) break;
		else if (msg.message == WM_LBUTTONUP)
		{
			bAccept = TRUE;
			break;
		}
		else  ::DispatchMessage(&msg);
	}

	if (GetCapture() == this)
	{
		ReleaseCapture();
	}

	if (bStartDrag)
	{
		if (bAccept)
		{
			ClientToScreen(&point);
			Dropped(point);

			ParentNotify_SelChangd();
		}
		else
		{
			CancelDrag();
		}
	}
}

void CXTPReportSubListControl::ParentNotify_SelChangd()
{
	if (GetParent() && (GetStyle() & LBS_NOTIFY))
		GetParent()->SendMessage(WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), LBN_SELCHANGE), (LPARAM)m_hWnd);

}