// BlocksToolBar.cpp : implementation file
//

#include "stdafx.h"
#include "xpeluc01.h"
#include "BlocksToolBar.h"
#include "BlockDirectory.h"
#include "BlockItem.h"


// CBlocksToolBar dialog

IMPLEMENT_DYNAMIC(CBlocksToolBar, CDialog)

CBlocksToolBar::CBlocksToolBar(CWnd* pParent /*=NULL*/)
	: CDialog(CBlocksToolBar::IDD, pParent)
{
	m_pBlocksDoc = new CBlocksDoc();
}

CBlocksToolBar::~CBlocksToolBar()
{
	delete m_pBlocksDoc;
}

void CBlocksToolBar::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_TREE1, m_wndTreeCtrl);
	DDX_Control(pDX, IDC_LIST1, m_wndListCtrl);
}


BEGIN_MESSAGE_MAP(CBlocksToolBar, CDialog)
	ON_WM_SIZE()
	ON_NOTIFY(TVN_SELCHANGED, IDC_TREE1, &CBlocksToolBar::OnTvnSelchangedTree1)
	ON_NOTIFY(LVN_BEGINDRAG, IDC_LIST1, &CBlocksToolBar::OnLvnBegindragList1)
//	ON_NOTIFY(LVN_GETDISPINFO, IDC_LIST1, &CBlocksToolBar::OnLvnGetdispinfoList1)
//	ON_WM_CREATE()
END_MESSAGE_MAP()


// CBlocksToolBar message handlers

void CBlocksToolBar::OnSize(UINT nType, int cx, int cy)
{
	if ( m_wndTreeCtrl.m_hWnd && m_wndListCtrl.m_hWnd )
	{
		CDialog::OnSize(nType, cx, cy);
		CRect rc;
		m_wndTreeCtrl.GetWindowRect(&rc);

		m_wndTreeCtrl.SetWindowPos(&wndTop, 0, 0, rc.Width(), cy, 0);
		switch ( m_wndTreeCtrl.IsWindowVisible() )
		{
		case FALSE:
			m_wndListCtrl.SetWindowPos(&wndTop, 0, 0, cx, cy, 0);
			break;
		default:
			m_wndListCtrl.SetWindowPos(&wndTop, rc.Width(), 0, cx - rc.Width(), cy, 0);
			break;
		}
	}
}

BOOL CBlocksToolBar::OnInitDialog()
{
	CDialog::OnInitDialog();
	m_nClipboardFormat = RegisterClipboardFormat(L"XPELUC01_CLIPBOARD_FORMAT");

	m_wndListCtrl.SetExtendedStyle(m_wndListCtrl.GetExtendedStyle() | LVS_EX_FULLROWSELECT);

	m_pBlocksDoc->Load();

	LoadListHeader();

	LoadTreeCtrl();

	return TRUE;  // return TRUE unless you set the focus to a control
	// EXCEPTION: OCX Property Pages should return FALSE
}

BOOL CBlocksToolBar::LoadTreeCtrl()
{
	m_wndTreeCtrl.DeleteAllItems();
	CBlockDirectory *pRoot;
	pRoot = m_pBlocksDoc->GetRootDirectory();

	TVINSERTSTRUCT tvi;
	ZeroMemory(&tvi, sizeof(tvi));
	tvi.hParent = NULL;
	tvi.hInsertAfter = TVI_LAST;
	tvi.item.mask = TVIF_TEXT | TVIF_PARAM;
	tvi.item.lParam = (LPARAM)pRoot;
	tvi.item.pszText = L"[root]";
	HTREEITEM hTreeItem = m_wndTreeCtrl.InsertItem(&tvi);

	UpdateSubTree(hTreeItem, pRoot);
	return TRUE;
}

BOOL CBlocksToolBar::LoadListHeader()
{
	m_wndListCtrl.InsertColumn(0, L"Name", 0, 80);
	m_wndListCtrl.InsertColumn(1, L"Description", 0, 270);
	m_wndListCtrl.InsertColumn(2, L"Inputs", 0, 32);
	m_wndListCtrl.InsertColumn(3, L"Outputs", 0, 32);
	return TRUE;
}

BOOL CBlocksToolBar::UpdateSubTree(HTREEITEM hParent, CBlockDirectory* pDir)
{
	CMapStringToOb map;
	// ziskame prvniho potomka
	HTREEITEM hItem = m_wndTreeCtrl.GetNextItem(hParent, TVGN_CHILD);
	while (hItem)
	{	// nacteme do mapy vsechny existujici polozky
		TVITEM tvItem;
		WCHAR buf[256];
		ZeroMemory(&tvItem, sizeof(tvItem));
		tvItem.mask = TVIF_PARAM | TVIF_TEXT;
		tvItem.hItem = hItem;
		tvItem.cchTextMax = 256;
		tvItem.pszText = buf;
		m_wndTreeCtrl.GetItem(&tvItem);
		CBlockDirectory *pTempDir;
		if ( pDir->Lookup(tvItem.pszText, pTempDir) )
		{	// polozka existuje / pridame do seznamu a prejdeme na dalsi
			map.SetAt(tvItem.pszText, (CObject*)tvItem.lParam);
			if ( (LPARAM)pTempDir != tvItem.lParam )
				m_wndTreeCtrl.SetItemData(hItem, (DWORD_PTR)pTempDir);
			UpdateSubTree(hItem, pTempDir);
			hItem = m_wndTreeCtrl.GetNextItem(hItem, TVGN_NEXT);
		}
		else
		{	// polozka neexistuje / prejdeme na dalsi a predchozi smazeme
			HTREEITEM hOldItem = hItem;
			hItem = m_wndTreeCtrl.GetNextItem(hItem, TVGN_NEXT);
			m_wndTreeCtrl.DeleteItem(hOldItem);
		}
	}
	// nyni v pDir je ulozeno mozna vice polozek. V pripade, ze ano, pridame je do treeviewctrl
	HANDLE hFind;
	CString strTmpKey;
	CBlockDirectory* pTmpDir;
	if ( hFind = pDir->FindFirstDir(strTmpKey, pTmpDir) )
	{
		do
		{
			CObject *val;
			if ( !map.Lookup(strTmpKey, val) )
			{	// v treeviewctrl polozka neni / pridame ji tam
				TVINSERTSTRUCT tvis;
				ZeroMemory(&tvis, sizeof(tvis));
				tvis.hInsertAfter = TVI_SORT;
				tvis.hParent = hParent;
				tvis.item.mask = TVIF_PARAM | TVIF_TEXT;
				tvis.item.lParam = (LPARAM)pTmpDir;
				tvis.item.pszText = (LPWSTR)strTmpKey.GetString();
				HTREEITEM hItem = m_wndTreeCtrl.InsertItem(&tvis);
				UpdateSubTree(hItem, pTmpDir);
			}
		}while ( pDir->FindNextDir(hFind, strTmpKey, pTmpDir) );
	}
	return TRUE;
}
void CBlocksToolBar::OnTvnSelchangedTree1(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
	// TODO: Add your control notification handler code here
	CBlockDirectory *pDir = (CBlockDirectory*)pNMTreeView->itemNew.lParam;
	CBlockItem *blkItem;
	m_wndListCtrl.DeleteAllItems();
	HANDLE hFind;
	if ( hFind = pDir->FindFirstItem(blkItem) )
	{
		int nItem = 0;
		do
		{
			CString strTemp;
			nItem = m_wndListCtrl.InsertItem(LVIF_TEXT | LVIF_PARAM, nItem, blkItem->GetName(), 0, 0, NULL, (LPARAM)blkItem);
			m_wndListCtrl.SetItem(nItem, 1, LVIF_TEXT, blkItem->GetDescription(), 0, 0, 0, NULL);
			if ( blkItem->GetInputCount() != -1 )
				strTemp.Format(L"%d", blkItem->GetInputCount());
			else
				strTemp = "NA";
			m_wndListCtrl.SetItem(nItem, 2, LVIF_TEXT, strTemp.GetString(), 0, 0, 0, NULL);
			if ( blkItem->GetOutputCount() != -1 )
				strTemp.Format(L"%d", blkItem->GetOutputCount());
			else
				strTemp = "NA";
			m_wndListCtrl.SetItem(nItem, 3, LVIF_TEXT, strTemp.GetString(), 0, 0, 0, NULL);
			nItem++;
		}while (pDir->FindNextItem(hFind, blkItem) );
	}
	*pResult = 0;
}

void CBlocksToolBar::OnLvnBegindragList1(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);

	COleDataSource *pSource = new COleDataSource();
	STGMEDIUM stgmed;
	FORMATETC fmtetc;
	DWORD len;

	CMemFile file;
	CArchive ar(&file, CArchive::store);
	CObject* pItem = (CObject*)m_wndListCtrl.GetItemData(pNMLV->iItem);
	ar << pItem;
	ar.Close();

	ZeroMemory(&fmtetc, sizeof(fmtetc));
	fmtetc.cfFormat = m_nClipboardFormat;
	fmtetc.ptd = NULL;
	fmtetc.dwAspect = DVASPECT_CONTENT;
	fmtetc.lindex = -1;
	fmtetc.tymed = TYMED_HGLOBAL;

	ZeroMemory(&stgmed, sizeof(stgmed));
	stgmed.tymed = TYMED_HGLOBAL;

	len = (DWORD)file.GetLength();
	stgmed.hGlobal = ::GlobalAlloc(GMEM_SHARE, len);
	BYTE* pBuf = file.Detach();
	
	LPVOID pData = ::GlobalLock(stgmed.hGlobal);
	memcpy(pData, pBuf, len);
	GlobalUnlock(stgmed.hGlobal);

	pSource->CacheData(m_nClipboardFormat, &stgmed, &fmtetc);
	pSource->DoDragDrop();

	file.Close();
	free(pBuf);

	delete pSource;
	*pResult = 0;
}

//void CBlocksToolBar::OnLvnGetdispinfoList1(NMHDR *pNMHDR, LRESULT *pResult)
//{
//	NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
//	pDispInfo->item.pszText = (LPWSTR)((CBlockItem*)pDispInfo->item.lParam)->GetName();
//}
