// CheckTreeView.cpp : implementation file
//

#include "stdafx.h"
#include "aplguiex.h"
#include <aplAggr.h>

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

/////////////////////////////////////////////////////////////////////////////
// CCheckTreeView

bool g_flag = false;

IMPLEMENT_DYNCREATE(CCheckTreeView, CTreeView)

CCheckTreeView::CCheckTreeView()
{
	m_ReturnData = false;
}

CCheckTreeView::~CCheckTreeView()
{
	for(int i=0; i<m_data_array.GetSize(); i++)
	{		
		delete m_data_array[i];
	}
}


BEGIN_MESSAGE_MAP(CCheckTreeView, CTreeView)
	//{{AFX_MSG_MAP(CCheckTreeView)
		ON_WM_LBUTTONDOWN()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCheckTreeView drawing

void CCheckTreeView::OnDraw(CDC* pDC)
{
	CDocument* pDoc = GetDocument();	
}

void CCheckTreeView::SetItemData(HTREEITEM hItem, DWORD data)
{
	sCheckData *CheckData = GetCheckData(hItem);
	
	CheckData->m_data = data;
	GetTreeCtrl().SetItemData(hItem, (DWORD)CheckData);
}

DWORD CCheckTreeView::GetItemData(HTREEITEM hItem)
{
	sCheckData *data = (sCheckData*)GetTreeCtrl().GetItemData(hItem);

	if(data != NULL)
	{
		if(!m_ReturnData)
		{
			return data->m_data;
		}
		else
		{
			return (DWORD)data;
		}
	}
	else
		return 0;
}

HTREEITEM CCheckTreeView::InsertItem(LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent, HTREEITEM hInsertAfter)
{
	HTREEITEM hItem = InsertItem(TVIF_TEXT, lpszItem, nImage, nSelectedImage, 0, 0, 0, hParent, hInsertAfter);

	return hItem;
}

HTREEITEM CCheckTreeView::InsertItem(LPCTSTR lpszItem, HTREEITEM hParent, HTREEITEM hInsertAfter)
{
	HTREEITEM hItem = InsertItem(TVIF_TEXT, lpszItem, -1, -1, 0, 0, 0, hParent, hInsertAfter);

	return hItem;
}

HTREEITEM CCheckTreeView::InsertItem(UINT nMask, LPCTSTR lpszItem, int nImage, int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam, HTREEITEM hParent, HTREEITEM hInsertAfter)
{
	TVINSERTSTRUCT InsertStruct;
	memset(&InsertStruct, 0, sizeof(TVINSERTSTRUCT));
	InsertStruct.hParent = hParent;
	InsertStruct.hInsertAfter = hInsertAfter;
	InsertStruct.item.iImage = nImage;
	InsertStruct.item.iSelectedImage = nSelectedImage;
	InsertStruct.item.pszText = new TCHAR[_strlen(lpszItem) + 1];
	_strcpy(InsertStruct.item.pszText, lpszItem);
	InsertStruct.item.cchTextMax = _strlen(lpszItem) + 1;
	InsertStruct.item.mask = nMask;
	InsertStruct.item.state = nState;
	InsertStruct.item.stateMask = nStateMask;
	InsertStruct.item.lParam = lParam;


	HTREEITEM hItem = InsertItem(&InsertStruct);
	
	delete InsertStruct.item.pszText;

	return hItem;
}

HTREEITEM CCheckTreeView::InsertItem(LPTVINSERTSTRUCT lpInsertStruct)
{
	HTREEITEM hItem = GetTreeCtrl().InsertItem(lpInsertStruct);
	GetTreeCtrl().SetItemImage(hItem, 1, 1);

	sCheckData *data = new sCheckData;
	data->m_data = lpInsertStruct->item.lParam;
	data->m_bIsChecked = false;
	data->m_grey = false;
	m_data_array.Add(data);

	GetTreeCtrl().SetItemData(hItem, (DWORD)data);

	return hItem;
}

void CCheckTreeView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	UINT flag=0;
	HTREEITEM hitem=GetTreeCtrl().HitTest(point,&flag);
	if(hitem!=0 && flag&TVHT_ONITEMICON)
	{
		sCheckData *data = (sCheckData*)GetCheckData(hitem);
		if(data != NULL)
			if(data->m_bIsChecked == false)
			{				
				data->m_bIsChecked = true;
				m_sel_array.Add(hitem);
				GetTreeCtrl().SetItemImage(hitem, 0, 0);
				data->m_grey = false;
				
				CheckUncheckChild(GetTreeCtrl().GetChildItem(hitem), true);
				MakeParentGrey(hitem);
				CheckUncheckParent(hitem);				
			}
			else
			{	
				if(data->m_grey == false)	// просто выделенный
				{
					data->m_bIsChecked = false;
					GetTreeCtrl().SetItemImage(hitem, 1, 1);
					data->m_grey = true;
					for(int i=0; i<m_sel_array.GetSize(); i++)
					{
						if(m_sel_array[i] == hitem)
						{
							m_sel_array.RemoveAt(i);
							break;
						}
					}
					CheckUncheckChild(GetTreeCtrl().GetChildItem(hitem), false);
					MakeParentGrey(hitem);
					CheckUncheckParent(hitem, false);					
				}
				else	// выделенный и "серый"
				{
					//m_sel_array.Add(hitem);
					GetTreeCtrl().SetItemImage(hitem, 0, 0);
					data->m_grey = false;
					CheckUncheckChild(GetTreeCtrl().GetChildItem(hitem), true);
					MakeParentGrey(hitem);
					CheckUncheckParent(hitem);
				}
			}
	}
	Invalidate();
	
	CTreeView::OnLButtonDown(nFlags, point);
}

void CCheckTreeView::OnInitialUpdate()
{
	CTreeView::OnInitialUpdate();

	CAplGuiExResourceHandleChange rescng;
	
	CBitmap bmp;
	bmp.LoadBitmap(IDB_CHECK);
	if(m_ImageList.m_hImageList == 0)
	{		
		m_ImageList.Create(16,16,ILC_COLOR24|ILC_MASK,20,20);
		m_ImageList.Add(&bmp,RGB(192,192,192));
	}

	GetTreeCtrl().DeleteAllItems();
	m_sel_array.RemoveAll();
	GetTreeCtrl().SetImageList(&m_ImageList, TVSIL_NORMAL);
	GetTreeCtrl().ModifyStyle(0, TVS_HASLINES|TVS_HASBUTTONS|TVS_SHOWSELALWAYS|TVS_LINESATROOT);
}

void CCheckTreeView::CheckUncheckChild(HTREEITEM parent, bool check)
{
	HTREEITEM hChildItem;
	
	while(parent)
	{
		if(GetTreeCtrl().ItemHasChildren(parent))
		{
			hChildItem = GetTreeCtrl().GetChildItem(parent);
			CheckUncheckChild(hChildItem, check);            
		}
		
		CString buf = GetTreeCtrl().GetItemText(parent);
		sCheckData *data = (sCheckData*)GetCheckData(parent);
		if(data != NULL)
		{
			
			if(check)
			{			
				if(data->m_bIsChecked == false)
				{
					m_sel_array.Add(parent);
					GetTreeCtrl().SetItemImage(parent, 0, 0);
					data->m_bIsChecked = true;
					data->m_grey = false;
				}
			}
			else
			{
				if(data->m_bIsChecked == true)
				{
					data->m_bIsChecked = false;
					GetTreeCtrl().SetItemImage(parent, 1, 1);
					data->m_grey = false;
					for(int i=0; i<m_sel_array.GetSize(); i++)
						if(m_sel_array[i] == parent)
						{
							m_sel_array.RemoveAt(i);
							break;
						}
				}
			}
		}

		parent = GetTreeCtrl().GetNextSiblingItem(parent);
	}
}

bool CCheckTreeView::IsFullSelect(HTREEITEM hItem, bool check, bool flag)
{
	HTREEITEM hChildItem;	
	
	while(hItem)
	{
		if(GetTreeCtrl().ItemHasChildren(hItem))
		{
			hChildItem = GetTreeCtrl().GetChildItem(hItem);
			flag = IsFullSelect(hChildItem, check, flag);            
		}

		sCheckData *data = GetCheckData(hItem);
		if(data != NULL)
		{
			if(check)
			{
				if(data->m_bIsChecked == false)
					flag = false;	
			}
			else
			{
				if(data->m_bIsChecked == true)
					flag = true;	
			}
		}
		
		hItem = GetTreeCtrl().GetNextSiblingItem(hItem);
	}

	return flag;
}

bool CCheckTreeView::CheckUncheckParent(HTREEITEM parent, bool check)
{
	HTREEITEM hItem = GetTreeCtrl().GetParentItem(parent);
	bool flag;

	if(hItem != NULL)
	{
		if(check)
			flag = true;
		else
			flag = false;
		bool select = IsFullSelect(GetTreeCtrl().GetChildItem(hItem), check, flag);
		if(select && check)
		{
			sCheckData *data = (sCheckData*)GetTreeCtrl().GetItemData(hItem);
			if(!data->m_bIsChecked)
			{
				data->m_bIsChecked = true;
				m_sel_array.Add(hItem);
			}
			GetTreeCtrl().SetItemImage(hItem, 0, 0);
			data->m_grey = false;
		}
		else if(!select && !check)
		{
			sCheckData *data = (sCheckData*)GetTreeCtrl().GetItemData(hItem);
			if(data->m_bIsChecked)
			{			
				data->m_bIsChecked = false;
				for(int i=0; i<m_sel_array.GetSize(); i++)
					if(m_sel_array[i] == hItem)
					{
						m_sel_array.RemoveAt(i);
						break;
					}
			}

			GetTreeCtrl().SetItemImage(hItem, 1, 1);
			data->m_grey = false;
		}

		CheckUncheckParent(hItem, check);
	}

	return true;
}

void CCheckTreeView::MakeParentGrey(HTREEITEM hItem)
{
	HTREEITEM parent = GetTreeCtrl().GetParentItem(hItem);

	if(parent != NULL)
	{
		sCheckData *data = (sCheckData*)GetCheckData(parent);
		if(data != NULL)
		{			
			if(!data->m_bIsChecked)
			{
				m_sel_array.Add(parent);
				data->m_bIsChecked = true;
			}
			GetTreeCtrl().SetItemImage(parent, 2, 2);
			data->m_grey = true;
		}
		
		MakeParentGrey(parent);
	}
}

bool CCheckTreeView::IsChecked(HTREEITEM hItem)
{
	sCheckData *data = (sCheckData*)GetCheckData(hItem);

	return data->m_bIsChecked;
}

void CCheckTreeView::SetChecked(HTREEITEM hItem, bool bCheck)
{
	UINT flag=0;
	HTREEITEM hitem=hItem;
	if(hitem!=0)
	{
		sCheckData *data = (sCheckData*)GetCheckData(hitem);
		if(data != NULL)

			data->m_bIsChecked = bCheck;

			if(data->m_bIsChecked == true)
			{				

				m_sel_array.Add(hitem);
				GetTreeCtrl().SetItemImage(hitem, 0, 0);
				data->m_grey = false;

				CheckUncheckChild(GetTreeCtrl().GetChildItem(hitem), true);
				MakeParentGrey(hitem);
				CheckUncheckParent(hitem);				
			}
			else
			{	
				if(data->m_grey == false)	// просто выделенный
				{
					data->m_bIsChecked = false;
					GetTreeCtrl().SetItemImage(hitem, 1, 1);
					data->m_grey = true;
					for(int i=0; i<m_sel_array.GetSize(); i++)
					{
						if(m_sel_array[i] == hitem)
						{
							m_sel_array.RemoveAt(i);
							break;
						}
					}
					CheckUncheckChild(GetTreeCtrl().GetChildItem(hitem), false);
					MakeParentGrey(hitem);
					CheckUncheckParent(hitem, false);					
				}
				else	// выделенный и "серый"
				{
					//m_sel_array.Add(hitem);
					GetTreeCtrl().SetItemImage(hitem, 0, 0);
					data->m_grey = false;
					CheckUncheckChild(GetTreeCtrl().GetChildItem(hitem), true);
					MakeParentGrey(hitem);
					CheckUncheckParent(hitem);
				}
			}
	}
}

int CCheckTreeView::GetCheckedCount()
{
	return m_sel_array.GetSize();
}

CArray<HTREEITEM, HTREEITEM>* CCheckTreeView::GetSelectedArray()
{
	return &m_sel_array;
}

bool CCheckTreeView::RefreshTree()
{
	m_sel_array.RemoveAll();

	return true;
}


/////////////////////////////////////////////////////////////////////////////
// CCheckTreeView diagnostics

#ifdef _DEBUG
void CCheckTreeView::AssertValid() const
{
	CTreeView::AssertValid();
}

void CCheckTreeView::Dump(CDumpContext& dc) const
{
	CTreeView::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CCheckTreeView message handlers
