// SchemeTreeView.cpp : implementation file
//

#include "stdafx.h"
#include "xpeluc01.h"
#include "SchemeTreeView.h"
#include "ChildFrm.h"
#include "SchemeView.h"


// CSchemeTreeView

IMPLEMENT_DYNCREATE(CSchemeTreeView, CView)

CSchemeTreeView::CSchemeTreeView()
{

}

CSchemeTreeView::~CSchemeTreeView()
{
}

BEGIN_MESSAGE_MAP(CSchemeTreeView, CView)
	ON_WM_SIZE()
	ON_NOTIFY(TVN_SELCHANGED, IDC_TREESCHEME, CSchemeTreeView::OnSelChanged)
END_MESSAGE_MAP()


// CSchemeTreeView drawing

void CSchemeTreeView::OnDraw(CDC* pDC)
{
	CDocument* pDoc = GetDocument();
	// TODO: add draw code here
}


// CSchemeTreeView diagnostics

#ifdef _DEBUG
void CSchemeTreeView::AssertValid() const
{
	CView::AssertValid();
}

#ifndef _WIN32_WCE
void CSchemeTreeView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}
#endif

CSchemeDoc* CSchemeTreeView::GetDocument() const // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSchemeDoc)));
	return (CSchemeDoc*)m_pDocument;
}

#endif //_DEBUG


// CSchemeTreeView message handlers

void CSchemeTreeView::OnInitialUpdate()
{
	RECT rc;
	GetClientRect(&rc);
	m_wndTreeCtrl.Create(WS_CHILD | WS_VISIBLE | TVS_FULLROWSELECT | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_SHOWSELALWAYS , rc, this, IDC_TREESCHEME);
	CView::OnInitialUpdate();
}

void CSchemeTreeView::OnSize(UINT nType, int cx, int cy)
{
	CView::OnSize(nType, cx, cy);
	if ( m_wndTreeCtrl.m_hWnd)
		m_wndTreeCtrl.SetWindowPos(&wndTop, 0, 0, cx, cy, 0);
}

void CSchemeTreeView::OnUpdate(CView* /*pSender*/, LPARAM /*lHint*/, CObject* /*pHint*/)
{
	CSchemeDoc* pDoc = GetDocument();
	HTREEITEM hItem = m_wndTreeCtrl.GetNextItem(NULL, TVGN_ROOT);
	if ( !hItem )
	{
		hItem = m_wndTreeCtrl.InsertItem(L"Root");
		m_wndTreeCtrl.SetItemData(hItem, (DWORD_PTR)pDoc->m_pBlockRoot);
		mapItems.insert(std::pair<CBlockItem_Virtual*, HTREEITEM>(pDoc->m_pBlockRoot, hItem));
	}
	UpdateSubTree(hItem, pDoc->m_pBlockRoot);
	m_wndTreeCtrl.Invalidate(FALSE);
}

BOOL CSchemeTreeView::UpdateSubTree(HTREEITEM hItem, const CBlockItem_Virtual *pItem)
{
	std::set<CBlockItem_Virtual*> itemSet;

	POSITION pos = pItem->GetFirstBlock();
	while ( pos )
	{	// naplnime mnozinu prvky, ktere opravdu existuji
		CBlockItem* p = pItem->GetNextBlock(pos);
		if ( p->IsKindOf(RUNTIME_CLASS(CBlockItem_Virtual)) )
		{
			itemSet.insert((CBlockItem_Virtual*)p);
		}
	}

	HTREEITEM hItem2 = m_wndTreeCtrl.GetNextItem(hItem, TVGN_CHILD);
	while ( hItem2 )
	{	// prochazim seznam[uroven stromu] a odstranuje prvky, ktere jsou v mnozine
		CBlockItem_Virtual* ptr = (CBlockItem_Virtual*)m_wndTreeCtrl.GetItemData(hItem2);
		std::set<CBlockItem_Virtual*>::iterator it;
		if ( (it = itemSet.find(ptr)) != itemSet.end() )
		{	// prvek se nachazi v mnozine - tedy existuje
			// zjistim, jestli jeho jmeno odpovida jmenu bloku
			CString strItemName = m_wndTreeCtrl.GetItemText(hItem2);
			CString strTrueName = ptr->GetName();
			if ( strItemName != strTrueName )
			{	// jmeno bloku neodpovida textu ve stromu - nastavim jej tedy spravne
				m_wndTreeCtrl.SetItemText(hItem2, strTrueName);
			}
			// pokusim se rekurzivne aktualizovat jeho potomkua a pak jej smazu z mnoziny
			UpdateSubTree(hItem2, (*it));
			itemSet.erase(it);
			hItem2 = m_wndTreeCtrl.GetNextItem(hItem2, TVGN_NEXT);
		}
		else
		{	// prvek se v mnozine nenachazi / neexistuje a proto jej smazeme
			HTREEITEM hItemOld = hItem2;
			hItem2 = m_wndTreeCtrl.GetNextItem(hItem2, TVGN_NEXT);
			m_wndTreeCtrl.DeleteItem(hItemOld);
			// odstranim jej i z mapy
			std::map<CBlockItem_Virtual*, HTREEITEM>::iterator itmap = mapItems.find(ptr);
			if ( itmap != mapItems.end() )
				mapItems.erase(itmap);
			else
				ASSERT(FALSE);
		}
	}

	// v mnozine uz zbyly jen prvky, ktere nejsou v seznamu[urovni stromu]
	// ty pridame a rekurzivne naplnime

	std::set<CBlockItem_Virtual*>::iterator it;
	for ( it = itemSet.begin(); it != itemSet.end(); it++ )
	{
		HTREEITEM hNewItem = m_wndTreeCtrl.InsertItem((*it)->GetName(), hItem);
		m_wndTreeCtrl.SetItemData(hNewItem, (DWORD_PTR)(*it));
		UpdateSubTree(hNewItem, *it);
		// pridame je i do mapy
		mapItems.insert(std::pair<CBlockItem_Virtual*, HTREEITEM>((*it), hNewItem));
	}

	return TRUE;
}

void CSchemeTreeView::OnSelChanged(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMTREEVIEW pNMTree = (LPNMTREEVIEW)pNMHDR;
	CBlockItem_Virtual* p = (CBlockItem_Virtual*)m_wndTreeCtrl.GetItemData(pNMTree->itemNew.hItem);
	CSplitterWnd* pWndParent = (CSplitterWnd*)GetParent();
	//CChildFrame *pWndParent = (CChildFrame*)GetParent();
	CSchemeView *pWndSchemeView = (CSchemeView*)pWndParent->GetPane(0, 1);
	if ( pWndSchemeView )
	{
		pWndSchemeView->SetThisBlock(p);
		pWndSchemeView->m_sUserData.setSelection.clear();
	}
	*pResult = 0;
}

BOOL CSchemeTreeView::Select(CBlockItem_Virtual *ptr)
{
	std::map<CBlockItem_Virtual*, HTREEITEM>::iterator it;
	it = mapItems.find(ptr);
	if ( it == mapItems.end() )
		ASSERT(FALSE);
	m_wndTreeCtrl.Select(it->second, TVGN_CARET);
	return TRUE;
}