// PanelTreeBrowser.cpp : implementation file
//

#include "stdafx.h"
#include "PanelTreeBrowser.h"
#include "PanelPreview.h"

#include "ViewManager.h"
#include "Viewport.h"

#include "Objects\EntityScript.h"

#include "EntityPrototype.h"
#include "EntityPrototypeLibrary.h"
#include "EntityPrototypeManager.h"
#include "Prefabs\PrefabManager.h"
#include "Settings.h"

#include <io.h>
#include <StringUtils.h>

// Sort the item in reverse alphabetical order.
static int CALLBACK TreeCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
	// lParamSort contains a pointer to the tree control.
	// The lParam of an item is just its handle, as specified with SetItemData
	CTreeCtrl* pTreeCtrl = (CTreeCtrl*)lParamSort;

	int nChilds1 = (pTreeCtrl->ItemHasChildren((HTREEITEM)lParam1) == TRUE) ? 1 : 0;
	int nChilds2 = (pTreeCtrl->ItemHasChildren((HTREEITEM)lParam2) == TRUE) ? 1 : 0;
	if (nChilds1 != nChilds2)
		return nChilds2 - nChilds1;

	CString strItem1 = pTreeCtrl->GetItemText((HTREEITEM) lParam1);
	CString strItem2 = pTreeCtrl->GetItemText((HTREEITEM) lParam2);

	return stricmp(strItem1, strItem2);
}

/////////////////////////////////////////////////////////////////////////////
// CPanelTreeBrowser dialog
StdMap<CString,int> CPanelTreeBrowser::m_selectionHistory;
CPanelTreeBrowser::FileHistory CPanelTreeBrowser::m_fileHistory;

CPanelTreeBrowser::CPanelTreeBrowser(CWnd* pParent /*=NULL*/)
	: CXTResizeDialog(CPanelTreeBrowser::IDD, pParent)
{
	//{{AFX_DATA_INIT(CPanelTreeBrowser)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT

	m_panelPreview = NULL;
	m_panelPreviewId = 0;
}

CPanelTreeBrowser::~CPanelTreeBrowser()
{
	if (m_panelPreviewId)
		GetIEditor()->RemoveRollUpPage( ROLLUP_OBJECTS,m_panelPreviewId );
	m_panelPreviewId = 0;
	m_panelPreview = 0;
}

void CPanelTreeBrowser::DoDataExchange(CDataExchange* pDX)
{
	CXTResizeDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_BROWSER_TREE, m_tree);
	DDX_Control(pDX, IDC_RELOAD,m_reloadBtn );
	DDX_Control(pDX, IDC_FILTER,m_filter );
}


BEGIN_MESSAGE_MAP(CPanelTreeBrowser, CXTResizeDialog)
	ON_NOTIFY(NM_DBLCLK, IDC_BROWSER_TREE, OnDblclkBrowserTree)
	ON_NOTIFY(TVN_SELCHANGED, IDC_BROWSER_TREE, OnSelchangedBrowserTree)
	ON_NOTIFY(TVN_BEGINDRAG, IDC_BROWSER_TREE, OnBeginDrag)
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONUP()
	ON_NOTIFY(NM_CLICK, IDC_BROWSER_TREE, OnClickBrowserTree)
	ON_BN_CLICKED(IDC_RELOAD, OnReload)
	ON_WM_DESTROY()
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CPanelTreeBrowser message handlers

BOOL CPanelTreeBrowser::OnInitDialog() 
{
	CXTResizeDialog::OnInitDialog();

	m_dragImage = 0;
	m_bFiles = false;

	CMFCUtils::LoadTrueColorImageList( m_cImageList,IDB_TREE_VIEW,16,RGB(255,0,255) );
	
	// Create the list
	//m_cImageList.Create(IDB_TREE_VIEW, 16, 1, RGB (255, 0, 255));

	// Attach it to the control
	m_tree.SetImageList(&m_cImageList, TVSIL_NORMAL);
	//m_tree.SetImageList(&m_cImageList, TVSIL_STATE);

	m_tree.SetIndent( 0 );
	//m_tree.SetBkColor( RGB(0xE0,0xE0,0xE0) );
	
	SetResize( IDC_BROWSER_TREE,SZ_RESIZE(1) );
	SetResize( IDC_FILTER,SZ_RESIZE(1) );

	// Add the Master CD folder to the list
	//HTREEITEM hRoot = m_tree.InsertItem( "Root", 2, 2, TVI_ROOT);

	/*
	RecurseDirectory( "c:\\mastercd\\Objects", TVI_ROOT, "*.cgf" );

	//m_tree.Expand( m_tree.GetRootItem(), TVE_COLLAPSE);
	//CRect rc;
	//GetClientRect( rc );
	//int h = m_tree.GetVisibleCount()*m_tree.GetItemHeight();
	//SetWindowPos( NULL,0,0,rc.right,h+80,SWP_NOMOVE );

	m_tree.Expand( m_tree.GetFirstVisibleItem(), TVE_COLLAPSE);
	*/
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

//////////////////////////////////////////////////////////////////////////
void CPanelTreeBrowser::OnDestroy()
{
	CXTResizeDialog::OnDestroy();
}

void CPanelTreeBrowser::Create( SelectCallback &cb,const CString &searchSpec,CWnd *parent,int flags )
{
	CXTResizeDialog::Create( IDD,parent );

	//////////////////////////////////////////////////////////////////////////
	SetResize( IDC_RELOAD,SZ_HORREPOS(1) );
	//////////////////////////////////////////////////////////////////////////

	m_flags = flags;
	m_bSelectOnClick = flags & SELECT_ONCLICK;
	m_bDragDropEnabled = !(flags & NO_DRAGDROP);

	m_searchspec = searchSpec;
	Refresh(false);

	m_selectCallback = cb;
}

//////////////////////////////////////////////////////////////////////////
void CPanelTreeBrowser::OnOK()
{
	// When enter pressed in dialog.
	OnReload();
};

//////////////////////////////////////////////////////////////////////////
void CPanelTreeBrowser::Refresh( bool bReloadFiles )
{
	CWaitCursor wait;
	CString searchSpec = m_searchspec;

	char dir[_MAX_PATH];
	char drive[_MAX_DRIVE];
	char fname[_MAX_FNAME];
	char fext[_MAX_EXT];

	_splitpath( searchSpec,drive,dir,fname,fext );

	CString searchPath = Path::GetPath( searchSpec );
	CString fileSpec = searchSpec.Mid( searchPath.GetLength() );

	m_path = dir;
	m_fileSpec = fileSpec;

	//@HACK
	// hardcoded names.
	if (searchSpec == "*EntityClass")
	{
		// Entity classes.
		FillEntityScripts(bReloadFiles);
	}
	else if (searchSpec == "*EntityArchetype")
	{
		// Entity prototypes.
		FillEntityPrototypes();
	}
	else if (searchSpec == "*Prefabs")
	{
		// Entity prototypes.
		FillPrefabs();
	}
	else
	{
		FileHistory::iterator it = m_fileHistory.find(fileSpec);
		if (it == m_fileHistory.end() || bReloadFiles)
		{
			// Load files from disk.
			FilesInfo finfo;
			LoadFiles( finfo );
			FillFiles( finfo );
		}
		else {
			FillFiles( it->second );
		}
		m_bFiles = true;

		/*
		// Just files.
		RecurseDirectory( GetIEditor()->GetMasterCDFolder(),dir,TVI_ROOT,fileSpec );
		*/
		CString numFiles;
		numFiles.Format( "%d Files",m_itemsMap.GetCount() );
		SetDlgItemText( IDC_NUM_FILES,numFiles );
	}

	SelectLastKnownItem();
}

//////////////////////////////////////////////////////////////////////////
void CPanelTreeBrowser::AddPreviewPanel()
{
	if (m_panelPreview)
		return;
	if (!(m_flags & NO_PREVIEW) && gSettings.bPreviewGeometryWindow)
	{
		// Searching geometries.
		if (strstr(m_fileSpec,"*.chr") != 0 || strstr(m_fileSpec,"*.cgf") != 0 || strstr(m_fileSpec,"*.cga") != 0)
		{
			// Create Preview.
			m_panelPreview = new CPanelPreview( AfxGetMainWnd() );
			m_panelPreviewId = GetIEditor()->AddRollUpPage( ROLLUP_OBJECTS,"Object Preview",m_panelPreview );
		}
	}
}

void CPanelTreeBrowser::SelectLastKnownItem()
{
	//Select item from history.
	int index;
	if (m_selectionHistory.Find(m_path+m_fileSpec,index))
	{
		int cnt = 0;
		HTREEITEM hItem = GetTreeItemByIndex( m_tree.GetRootItem(),index,cnt );
		if (hItem) {
			m_tree.Select( hItem,TVGN_CARET );
			m_tree.EnsureVisible( hItem );
		}
	}
}

//////////////////////////////////////////////////////////////////////////
void CPanelTreeBrowser::SelectFile( const CString &filename )
{
	SelectCallback cb = m_selectCallback;
	m_selectCallback = 0;
	HTREEITEM hItem = stl::find_in_map( m_fileToItem,filename,(HTREEITEM)0 );
	if (hItem)
	{
		m_tree.Select( hItem,TVGN_CARET );
		m_tree.EnsureVisible( hItem );
		//m_tree.SetItemBold( hItem,TRUE );
		//m_tree.SetItemColor( hItem,RGB(255,0,0) );
	}
	m_selectCallback = cb;
}

inline bool SortEntityScripts( CEntityScript *pScript1,CEntityScript *pScript2 )
{
	return pScript1->GetFile() < pScript2->GetFile();
}

//////////////////////////////////////////////////////////////////////////
void CPanelTreeBrowser::FillEntityScripts( bool bReload )
{
	m_tree.SetRedraw(FALSE);
	m_fileToItem.clear();
	m_itemsMap.Clear();
	m_tree.DeleteAllItems();

	CString filter;
	m_filter.GetWindowText( filter );
	bool bFilter = !filter.IsEmpty();

	if (bReload)
		CEntityScriptRegistry::Instance()->Reload();

	StdMap<CString,HTREEITEM> items;
	// Entity scripts.
	std::vector<CEntityScript*> scripts;
	CEntityScriptRegistry::Instance()->GetScripts( scripts );
	std::sort( scripts.begin(),scripts.end(),SortEntityScripts );

	for (int i = 0; i < scripts.size(); i++)
	{
		// If class is not usable simply skip it.
		if (!scripts[i]->IsUsable())
			continue;

		CString name = scripts[i]->GetName();

		if (bFilter)
		{
			if (strstri(name,filter) == 0)
				continue;
		}

		HTREEITEM hRoot = TVI_ROOT;
		char *token;

		CString clsFile = scripts[i]->GetFile();
		clsFile.Replace( "Scripts/Entities/","" );
		char classFile[1024];
		strcpy( classFile,clsFile );

		token = strtok( classFile,"\\/" );

		CString itemName;
		while (token)
		{
			CString strToken = token;

			token = strtok( NULL,"\\/" );
			if (!token)
				break;

			itemName += strToken+"\\";
			if (!items.Find( itemName,hRoot ))
			{
				hRoot = m_tree.InsertItem(strToken, 0, 0, hRoot );
				m_tree.SetItemData( hRoot,(DWORD_PTR)hRoot );// Fort sorting.
				items.Insert( itemName,hRoot );
			}
		}

		HTREEITEM hNewItem = m_tree.InsertItem(name, 3, 3, hRoot );
		m_tree.SetItemData( hNewItem,(DWORD_PTR)hNewItem );// Fort sorting.
		m_tree.SetItemState(hNewItem, TVIS_BOLD, TVIS_BOLD);
		m_itemsMap[hNewItem] = name;
	}
	CString numFiles;
	numFiles.Format( "%d Entities",m_itemsMap.GetCount() );
	SetDlgItemText( IDC_NUM_FILES,numFiles );

	//SortTree();

	m_tree.SetRedraw(TRUE);
}
	
//////////////////////////////////////////////////////////////////////////
void CPanelTreeBrowser::FillEntityPrototypes()
{
	m_tree.SetRedraw(FALSE);
	m_fileToItem.clear();
	m_itemsMap.Clear();
	m_tree.DeleteAllItems();

	CString filter;
	m_filter.GetWindowText( filter );
	bool bFilter = !filter.IsEmpty();

	CEntityPrototypeManager *protMan = GetIEditor()->GetEntityProtManager();

	for (int j = 0; j < protMan->GetLibraryCount(); j++)
	{
		IDataBaseLibrary *lib = protMan->GetLibrary(j);

		std::map<CString,HTREEITEM> groupMap;

		HTREEITEM hLibItem = NULL;
		for (int i = 0; i < lib->GetItemCount(); i++)
		{
			CEntityPrototype* prototype = (CEntityPrototype*)lib->GetItem(i);

			CString groupName = prototype->GetGroupName();
			CString itemName = prototype->GetShortName();

			if (bFilter)
			{
				if (strstri(itemName,filter) == 0)
					continue;
			}

			if (!hLibItem)
			{
				hLibItem = m_tree.InsertItem( lib->GetName(), 0, 0 );
				m_tree.SetItemData( hLibItem,(DWORD_PTR)hLibItem );// For sorting.
			}

			HTREEITEM hGroupItem = hLibItem;
			if (!groupName.IsEmpty())
			{
				HTREEITEM hItem = stl::find_in_map( groupMap,groupName,(HTREEITEM)0 );
				if (hItem)
				{
					hGroupItem = hItem;
				}
				else
				{
					hGroupItem = m_tree.InsertItem( groupName, 0, 0, hLibItem );
					m_tree.SetItemData( hGroupItem,(DWORD_PTR)hGroupItem );// Fort sorting.
					groupMap[groupName] = hGroupItem;
				}
			}

			HTREEITEM hNewItem = m_tree.InsertItem(itemName, 3, 3, hGroupItem );
			m_tree.SetItemData( hNewItem,(DWORD_PTR)hNewItem );// Fort sorting.
			m_tree.SetItemState(hNewItem, TVIS_BOLD, TVIS_BOLD);

			CString fullItemName = GuidUtil::ToString(prototype->GetGUID());
			m_itemsMap[hNewItem] = fullItemName;
		}
	}

	CString numFiles;
	numFiles.Format( "%d Entities",m_itemsMap.GetCount() );
	SetDlgItemText( IDC_NUM_FILES,numFiles );

	SortTree();

	m_tree.SetRedraw(TRUE);
}


//////////////////////////////////////////////////////////////////////////
void CPanelTreeBrowser::FillPrefabs()
{
	m_tree.SetRedraw(FALSE);
	m_fileToItem.clear();
	m_itemsMap.Clear();
	m_tree.DeleteAllItems();

	CString filter;
	m_filter.GetWindowText( filter );
	bool bFilter = !filter.IsEmpty();

	CPrefabManager *pManager = GetIEditor()->GetPrefabManager();

	for (int j = 0; j < pManager->GetLibraryCount(); j++)
	{
		IDataBaseLibrary *lib = pManager->GetLibrary(j);

		std::map<CString,HTREEITEM> groupMap;

		HTREEITEM hLibItem = NULL;
		for (int i = 0; i < lib->GetItemCount(); i++)
		{
			CEntityPrototype* prototype = (CEntityPrototype*)lib->GetItem(i);

			CString groupName = prototype->GetGroupName();
			CString itemName = prototype->GetShortName();

			if (bFilter)
			{
				if (strstri(itemName,filter) == 0)
					continue;
			}

			if (!hLibItem)
			{
				hLibItem = m_tree.InsertItem( lib->GetName(), 0, 0 );
				m_tree.SetItemData( hLibItem,(DWORD_PTR)hLibItem );// Fort sorting.
			}

			HTREEITEM hGroupItem = hLibItem;
			if (!groupName.IsEmpty())
			{
				HTREEITEM hItem = stl::find_in_map( groupMap,groupName,(HTREEITEM)0 );
				if (hItem)
				{
					hGroupItem = hItem;
				}
				else
				{
					hGroupItem = m_tree.InsertItem( groupName, 0, 0, hLibItem );
					m_tree.SetItemData( hGroupItem,(DWORD_PTR)hGroupItem );// Fort sorting.
					groupMap[groupName] = hGroupItem;
				}
			}
		
			HTREEITEM hNewItem = m_tree.InsertItem(itemName, 1, 1, hGroupItem );
			m_tree.SetItemData( hNewItem,(DWORD_PTR)hNewItem );// Fort sorting.
			m_tree.SetItemState(hNewItem, TVIS_BOLD, TVIS_BOLD);

			CString fullItemName = GuidUtil::ToString(prototype->GetGUID());
			m_itemsMap[hNewItem] = fullItemName;
		}
	}

	CString numFiles;
	numFiles.Format( "%d Prefabs",m_itemsMap.GetCount() );
	SetDlgItemText( IDC_NUM_FILES,numFiles );

	SortTree();

	m_tree.SetRedraw(TRUE);
}

//////////////////////////////////////////////////////////////////////////
int CPanelTreeBrowser::RecurseDirectory( const CString &basePath,const CString &searchPath, HTREEITEM hRoot, LPCSTR pszFileSpec )
{
	////////////////////////////////////////////////////////////////////////
	// Enumerate all files in the passed directory which match to the the
	// passed pattern. Also continue with adding all subdirectories
	////////////////////////////////////////////////////////////////////////

	CString szFolder = searchPath;

	//char szFolder[_MAX_PATH];
	//strcpy( szFolder,searchPath );

	CFileEnum cTempFiles;
	__finddata64_t sFile;
	char szFilePath[_MAX_PATH];
	HTREEITEM hNewRoot, hNewItem;

	ASSERT(pszFileSpec);

	CString fileSpec = pszFileSpec;
	std::vector<CString> fileSpecs;

	// Split file spec with ';'
	while (!fileSpec.IsEmpty())
	{
		int splitpos = fileSpec.Find(';');
		if (splitpos < 0)
		{
			fileSpecs.push_back(fileSpec);
			break;
		}
		fileSpecs.push_back(fileSpec.Mid(0,splitpos));
		fileSpec = fileSpec.Mid(splitpos+1);
	}

	// Make the path ready for appening a folder or filename
	szFolder = Path::AddBackslash(szFolder);
	int numFiles = 0;

	// Start the enumeration of the files
	if (cTempFiles.StartEnumeration(szFolder, "*.*", &sFile))
	{
		do
		{
			// Construct the full filepath of the current file
			strcpy(szFilePath, szFolder);
			strcat(szFilePath, sFile.name);

			// Have we found a directory ?
			if (sFile.attrib & _A_SUBDIR)
			{
				// Skip the parent directory entries
				if (_stricmp(sFile.name, ".") == 0 ||
					_stricmp(sFile.name, "..") == 0)
				{
					continue;
				}

				// Add it to the list and start recursion
				hNewRoot = m_tree.InsertItem(sFile.name, 0, 0, hRoot);
				m_tree.SetItemData( hNewRoot,(DWORD_PTR)hNewRoot );// Fort sorting.
				int num = RecurseDirectory( basePath,szFilePath, hNewRoot, pszFileSpec);
				m_tree.Expand( hNewRoot,TVE_COLLAPSE);
				m_tree.SortChildren(hNewRoot);
				if (num == 0)
				{
					// Delete empty directory item.
					m_tree.DeleteItem( hNewRoot );
				}
				numFiles += num;

				continue;
			}

			int nImage = 1;

			// Check if the file name maches the pattern
			bool bFileMatch = false;
			for (int i = 0; i < fileSpecs.size(); i++)
			{
				if (PathMatchSpec(sFile.name,fileSpecs[i]))
				{
					bFileMatch = true;
					break;
				}
				nImage = 2;
			}
			if (!bFileMatch)
				continue;

			// Remove the extension from the name
			PathRenameExtension(sFile.name, "");

			// Add the file to the list
			hNewItem = m_tree.InsertItem(sFile.name, nImage, nImage, hRoot);
			m_tree.SetItemData( hNewItem,(DWORD_PTR)hNewItem );// Fort sorting.
			m_tree.SetItemState(hNewItem, TVIS_BOLD, TVIS_BOLD);

			m_itemsMap[hNewItem] = szFilePath;
      

			numFiles++;

		} while (cTempFiles.GetNextFile(&sFile));
	}
	return numFiles;
}

//////////////////////////////////////////////////////////////////////////
void CPanelTreeBrowser::LoadFiles( FilesInfo &info )
{
	CString fileSpec = m_fileSpec;
	CString currFileSpec;
	static CFileUtil::FileArray files;

	info.files.clear();

	// Reserve many files.
	files.resize(0);
	files.reserve( 10000 );

	// Split file spec with ';'
	while (!fileSpec.IsEmpty())
	{
		int splitpos = fileSpec.Find(';');
		if (splitpos < 0)
		{
			currFileSpec = fileSpec;
			CFileUtil::ScanDirectory( m_path,currFileSpec,files,true );
			break;
		}
		CString currFileSpec = fileSpec.Mid(0,splitpos);
		CFileUtil::ScanDirectory( m_path,currFileSpec,files,true );
		fileSpec = fileSpec.Mid(splitpos+1);
	}
	
	info.files.reserve( files.size() );
	for (int i = 0; i < files.size(); i++)
	{
		// Ignore LODs.
		if (CryStringUtils::stristr(files[i].filename,"_lod") != 0)
			continue;
		info.files.push_back( files[i].filename );
	}
	//std::sort( info.files.begin(),info.files.end() );

	m_fileHistory[m_fileSpec] = info;
}

inline bool SortFiles( const CString &s1,const CString &s2 )
{
	return stricmp(s1,s2) < 0;
}

//////////////////////////////////////////////////////////////////////////
void CPanelTreeBrowser::FillFiles( FilesInfo &finfo )
{
	m_tree.SetRedraw( FALSE );
	m_fileToItem.clear();
	m_itemsMap.Clear();

	m_tree.DeleteAllItems();

	int offsetPath = Path::AddBackslash(m_path).GetLength();

	CString filter;
	m_filter.GetWindowText( filter );
	bool bFilter = !filter.IsEmpty();

	std::sort( finfo.files.begin(),finfo.files.end(),SortFiles );

	int i;
	CString filename,ext,path;
	std::map<CString,HTREEITEM> pathmap;

	// First, only create groups.
	for (i = 0; i < finfo.files.size(); i++)
	{
		Path::Split( finfo.files[i],path,filename,ext );
		if (!path.IsEmpty() && path[path.GetLength()-1] == '\\')
			path.Truncate( path.GetLength()-1 );
		
		if (bFilter)
		{
			if (strstri(filename,filter) == 0)
				continue;
		}

		HTREEITEM hGroup = TVI_ROOT;

		if (!path.IsEmpty())
		{
			hGroup = stl::find_in_map( pathmap,path,(HTREEITEM)0 );
			if (!hGroup)
			{
				hGroup = TVI_ROOT;
				int startPos = 0;
				int prevPos = 0;
				CString subpath;
				while (startPos < path.GetLength())
				{
					prevPos = startPos;
					int pos = path.Find( '\\',startPos );
					if (pos >= 0)
					{
						startPos = pos+1;
					}
					else
					{
						startPos = path.GetLength()+1;
						pos = startPos;
					}
					subpath = path.Mid(0,pos);
					HTREEITEM hItem = stl::find_in_map( pathmap,subpath,(HTREEITEM)0 );
					if (!hItem)
					{
						CString subGroupName = path.Mid(prevPos,startPos-prevPos-1);
						hGroup = m_tree.InsertItem( subGroupName,0,0,hGroup );
						pathmap[subpath] = hGroup;
					}
					else
						hGroup = hItem;
				}
			}
		}
	}

	CString basePath = Path::AddBackslash(m_path);
	// Then fill items in groups.
	for (i = 0; i < finfo.files.size(); i++)
	{
		Path::Split( finfo.files[i],path,filename,ext );
		if (!path.IsEmpty() && path[path.GetLength()-1] == '\\')
			path.Truncate( path.GetLength()-1 );

		if (bFilter)
		{
			if (strstri(filename,filter) == 0)
				continue;
		}
		HTREEITEM hGroup = TVI_ROOT;
		if (!path.IsEmpty())
		{
			hGroup = stl::find_in_map( pathmap,path,(HTREEITEM)0 );
		}
		int nImage = 1;
		if (stricmp(ext,".cga")==0)
		{
			nImage = 2;
		}
		HTREEITEM hNewItem = m_tree.InsertItem( filename, nImage, nImage, hGroup );
		CString filename = basePath + finfo.files[i];
		m_itemsMap[hNewItem] = filename;
		m_fileToItem[filename] = hNewItem;
	}


	m_tree.SetRedraw( TRUE );
}

//////////////////////////////////////////////////////////////////////////
void CPanelTreeBrowser::OnDblclkBrowserTree(NMHDR* pNMHDR, LRESULT* pResult) 
{
	*pResult = 0;

	if (m_tree.GetSelectedItem() == NULL)
		return;
		
	CString file = GetSelectedFile();
	if (file.IsEmpty())
		return;

	AcceptFile( file );
}

CString CPanelTreeBrowser::GetSelectedFile()
{
	////////////////////////////////////////////////////////////////////////
	// Return the path of the currently selected file. If there is no
	// currently selected file, just a NULL terminated string will be
	// returned
	////////////////////////////////////////////////////////////////////////

	CString strFileName;
	m_itemsMap.Find( m_tree.GetSelectedItem(),strFileName );
	return strFileName;
}

void CPanelTreeBrowser::AcceptFile( const CString &file )
{
	if (!file.IsEmpty())
	{
		// Select this file.
		if (m_selectCallback)
			m_selectCallback( file );
		//GetIEditor()->StartObjectCreation( m_objectType,file );
	}
}

bool CPanelTreeBrowser::GetTreeItemIndex( HTREEITEM hRoot,HTREEITEM hItem,int &index )
{
	HTREEITEM hIt = hRoot;
	while (hIt != NULL)
	{
		if (hIt == hItem)
			return true;

		index++;

		if (m_tree.ItemHasChildren(hIt))
		{
			if (GetTreeItemIndex( m_tree.GetNextItem(hIt,TVGN_CHILD),hItem,index ))
			{
				return true;
			}
		}
		hIt = m_tree.GetNextSiblingItem( hIt );
	}
	return false;
}

HTREEITEM CPanelTreeBrowser::GetTreeItemByIndex( HTREEITEM hRoot,int itemIndex,int &index )
{
	HTREEITEM hIt = hRoot;
	while (hIt != NULL)
	{
		if (index == itemIndex)
			return hIt;

		index++;
		if (m_tree.ItemHasChildren(hIt))
		{
			HTREEITEM h = GetTreeItemByIndex( m_tree.GetNextItem(hIt,TVGN_CHILD),itemIndex,index );
			if (h != NULL)
			{
				return h;
			}
		}
		hIt = m_tree.GetNextSiblingItem( hIt );
	}
	return 0;
}

void CPanelTreeBrowser::OnSelchangedBrowserTree(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

	int index = 0;
	GetTreeItemIndex( m_tree.GetRootItem(),m_tree.GetSelectedItem(),index );

	// Store selected item in history for this browser.
	m_selectionHistory[m_path+m_fileSpec] = index;

	// If geometry update preview.
	if (m_panelPreview)
	{
		CString file = "";
		m_itemsMap.Find( pNMTreeView->itemNew.hItem,file );
		if (!file.IsEmpty())
		{
			// Check if preview panel is expended.
			m_panelPreview->LoadFile( file );
		}
	}
	if (m_bSelectOnClick)
	{
		CString file = "";
		m_itemsMap.Find( pNMTreeView->itemNew.hItem,file );
		if (!file.IsEmpty())
		{
			if (m_selectCallback)
				m_selectCallback( file );
		}
	}
	
	*pResult = 0;
}

void CPanelTreeBrowser::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

	if (!m_bDragDropEnabled)
		return;

	HTREEITEM hItem = pNMTreeView->itemNew.hItem;

	m_draggedFile = "";
	m_itemsMap.Find( hItem,m_draggedFile );
	if (m_draggedFile.IsEmpty())
		return;

	m_tree.Select( hItem,TVGN_CARET );

	m_dragImage = m_tree.CreateDragImage( hItem );
	if (m_dragImage)
	{
		m_dragImage->BeginDrag(0, CPoint(-10, -10));

		CRect rc;
		AfxGetMainWnd()->GetWindowRect( rc );
		
		CPoint p = pNMTreeView->ptDrag;
		ClientToScreen( &p );
		p.x -= rc.left;
		p.y -= rc.top;
		
		m_dragImage->DragEnter( AfxGetMainWnd(),p );
		SetCapture();
		GetIEditor()->EnableUpdate( false );
	}
	
	*pResult = 0;
}

void CPanelTreeBrowser::OnMouseMove(UINT nFlags, CPoint point) 
{
	CRect rc;
	AfxGetMainWnd()->GetWindowRect( rc );
		
	ClientToScreen( &point );
	point.x -= rc.left;
	point.y -= rc.top;

	if (m_dragImage)
	{
		m_dragImage->DragMove( point );
	}
	
	//CXTResizeDialog::OnMouseMove(nFlags, point);
}

void CPanelTreeBrowser::OnLButtonUp(UINT nFlags, CPoint point) 
{
	//CXTResizeDialog::OnLButtonUp(nFlags, point);

	if (m_dragImage)
	{
		CPoint p;
		GetCursorPos( &p );

		GetIEditor()->EnableUpdate( true );

		m_dragImage->DragLeave( AfxGetMainWnd() );
		m_dragImage->EndDrag();
		delete m_dragImage;
		m_dragImage = 0;
		ReleaseCapture();

		CViewport *pView = GetIEditor()->GetViewManager()->GetViewportAtPoint(p);
		if (pView)
		{
			// Drag and drop into one of views.
			// Start object creation.
			AcceptFile( m_draggedFile ); 
		}
	}
}

void CPanelTreeBrowser::OnClickBrowserTree(NMHDR* pNMHDR, LRESULT* pResult) 
{
	*pResult = 0;
}

//////////////////////////////////////////////////////////////////////////
void CPanelTreeBrowser::OnReload()
{
	Refresh(true);
}

//////////////////////////////////////////////////////////////////////////
void CPanelTreeBrowser::SortItem( HTREEITEM hParent )
{
	TVSORTCB tvs;
	tvs.hParent = hParent;
	tvs.lpfnCompare = TreeCompareProc;
	tvs.lParam = (LPARAM)&m_tree;
	m_tree.SortChildrenCB(&tvs);

	// Look at all of the root-level items
	HTREEITEM hCurrent = m_tree.GetNextItem( hParent,TVGN_CHILD );
	while (hCurrent != NULL)
	{
		SortItem( hCurrent );
		// Try to get the next item
		hCurrent = m_tree.GetNextItem(hCurrent, TVGN_NEXT); 
	}
}

//////////////////////////////////////////////////////////////////////////
void CPanelTreeBrowser::SortTree()
{
	SortItem( TVI_ROOT );
}
