//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
//=============================================================================

#if defined(WIN32) && !defined( _X360 )
#include <windows.h>
#endif
#undef PropertySheet

#include "matsys_controls/gamefiletreeview.h"
#include "filesystem.h"
#include "tier1/KeyValues.h"
#include "vgui/ISurface.h"
#include "vgui/Cursor.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"


using namespace vgui;


//-----------------------------------------------------------------------------
// list of all tree view icons
//-----------------------------------------------------------------------------
enum
{
	IMAGE_FOLDER = 1,
	IMAGE_OPENFOLDER,
	IMAGE_FILE,
};


//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
CGameFileTreeView::CGameFileTreeView( Panel *parent, const char *name, const char *pRootFolderName, const char *pRootDir, const char *pExtension ) : BaseClass(parent, name), m_Images( false )
{
	m_RootDir = pRootDir;
	
	m_Ext = pExtension;
	m_bUseExt = ( pExtension != NULL );
	
	m_RootFolderName = pRootFolderName;

	// build our list of images
	m_Images.AddImage( scheme()->GetImage( "resource/icon_folder", false ) );
	m_Images.AddImage( scheme()->GetImage( "resource/icon_folder_selected", false ) );
	m_Images.AddImage( scheme()->GetImage( "resource/icon_file", false ) );
	SetImageList( &m_Images, false );
}


//-----------------------------------------------------------------------------
// Purpose: Refreshes the active file list
//-----------------------------------------------------------------------------
void CGameFileTreeView::RefreshFileList()
{
	RemoveAll();
	SetFgColor(Color(216, 222, 211, 255));

	// add the base node
	KeyValues *pkv = new KeyValues( "root" );
	pkv->SetString( "text", m_RootFolderName );
	pkv->SetInt( "root", 1 );
	pkv->SetInt( "expand", 1 );
	int iRoot = AddItem( pkv, GetRootItemIndex() );
	pkv->deleteThis();
	ExpandItem( iRoot, true );
}

	
//-----------------------------------------------------------------------------
// Selects the root folder
//-----------------------------------------------------------------------------
void CGameFileTreeView::SelectRoot()
{
	AddSelectedItem( GetRootItemIndex(), true );
}


//-----------------------------------------------------------------------------
// Gets the number of root directories
//-----------------------------------------------------------------------------
int CGameFileTreeView::GetRootDirectoryCount()
{
	return GetNumChildren( GetRootItemIndex() );
}


//-----------------------------------------------------------------------------
// Gets the ith root directory
//-----------------------------------------------------------------------------
const char *CGameFileTreeView::GetRootDirectory( int nIndex )
{
	int nItemIndex = GetChild( GetRootItemIndex(), nIndex );
	KeyValues *kv = GetItemData( nItemIndex );
	if ( !kv )
		return NULL;
	return kv->GetString( "path", NULL );
}


//-----------------------------------------------------------------------------
// Populate the root node (necessary since tree view can't have multiple roots)
//-----------------------------------------------------------------------------
void CGameFileTreeView::PopulateRootNode( int itemIndex )
{
	AddDirectoriesOfNode( itemIndex, m_RootDir );

	if ( m_bUseExt )
	{
		AddFilesOfNode( itemIndex, m_RootDir, m_Ext );
	}
}


//-----------------------------------------------------------------------------
// Populate the root node with directories
//-----------------------------------------------------------------------------
bool CGameFileTreeView::DoesDirectoryHaveSubdirectories( const char *pFilePath )
{
	char pSearchString[MAX_PATH];
	Q_snprintf( pSearchString, MAX_PATH, "%s\\*", pFilePath );

	// get the list of files
	FileFindHandle_t findHandle;

	// generate children
	// add all the items
	const char *pszFileName = g_pFullFileSystem->FindFirstEx( pSearchString, "GAME", &findHandle );
	while ( pszFileName )
	{
		bool bIsDirectory = g_pFullFileSystem->FindIsDirectory( findHandle );
		if ( bIsDirectory && Q_strnicmp( pszFileName, ".", 2 ) && Q_strnicmp( pszFileName, "..", 3 ) )
			return true;

		pszFileName = g_pFullFileSystem->FindNext( findHandle );
	}

	g_pFullFileSystem->FindClose( findHandle );
	return false;
}

	
//-----------------------------------------------------------------------------
// Populate the root node with directories
//-----------------------------------------------------------------------------
void CGameFileTreeView::AddDirectoriesOfNode( int itemIndex, const char *pFilePath )
{
	char pSearchString[MAX_PATH];
	Q_snprintf( pSearchString, MAX_PATH, "%s\\*", pFilePath );

	// get the list of files
	FileFindHandle_t findHandle;

	// generate children
	// add all the items
	const char *pszFileName = g_pFullFileSystem->FindFirstEx( pSearchString, "GAME", &findHandle );
	while ( pszFileName )
	{
		bool bIsDirectory = g_pFullFileSystem->FindIsDirectory( findHandle );
		if ( bIsDirectory && Q_strnicmp( pszFileName, ".", 2 ) && Q_strnicmp( pszFileName, "..", 3 ) )
		{
			KeyValues *kv = new KeyValues( "node", "text", pszFileName );
			 
			char pFullPath[MAX_PATH];
			Q_snprintf( pFullPath, sizeof(pFullPath), "%s/%s", pFilePath, pszFileName );
			Q_FixSlashes( pFullPath );
			Q_strlower( pFullPath );
			bool bHasSubdirectories = DoesDirectoryHaveSubdirectories( pFullPath );
			kv->SetString( "path", pFullPath );

			kv->SetInt( "expand", bHasSubdirectories );
			kv->SetInt( "dir", 1 );
			kv->SetInt( "image", IMAGE_FOLDER );

			int itemID = AddItem(kv, itemIndex);
 			kv->deleteThis();

			// mark directories in orange
			SetItemColorForDirectories( itemID );
		}

		pszFileName = g_pFullFileSystem->FindNext( findHandle );
	}

	g_pFullFileSystem->FindClose( findHandle );
}


//-----------------------------------------------------------------------------
// Populate the root node with files
//-----------------------------------------------------------------------------
void CGameFileTreeView::AddFilesOfNode( int itemIndex, const char *pFilePath, const char *pExt )
{
	char pSearchString[MAX_PATH];
	Q_snprintf( pSearchString, MAX_PATH, "%s\\*.%s", pFilePath, pExt );

	// get the list of files
	FileFindHandle_t findHandle;

	// generate children
	// add all the items
	const char *pszFileName = g_pFullFileSystem->FindFirst( pSearchString, &findHandle );
	while ( pszFileName )
	{
		if ( !g_pFullFileSystem->FindIsDirectory( findHandle ) )
		{
			KeyValues *kv = new KeyValues( "node", "text", pszFileName );

			char pFullPath[MAX_PATH];
			Q_snprintf( pFullPath, MAX_PATH, "%s\\%s", pFilePath, pszFileName );
			kv->SetString( "path", pFullPath );
			kv->SetInt( "image", IMAGE_FILE );

			AddItem(kv, itemIndex);
			kv->deleteThis();
		}

		pszFileName = g_pFullFileSystem->FindNext( findHandle );
	}

	g_pFullFileSystem->FindClose( findHandle );
}


//-----------------------------------------------------------------------------
// override to incremental request and show p4 directories
//-----------------------------------------------------------------------------
void CGameFileTreeView::GenerateChildrenOfNode(int itemIndex)
{
	KeyValues *pkv = GetItemData(itemIndex);
	if ( pkv->GetInt("root") )
	{
		PopulateRootNode( itemIndex );
		return;
	}

	if (!pkv->GetInt("dir"))
		return;

	const char *pFilePath = pkv->GetString("path", "");
	if (!pFilePath[0])
		return;

	surface()->SetCursor(dc_waitarrow);

	AddDirectoriesOfNode( itemIndex, pFilePath );

	if ( m_bUseExt )
	{
		AddFilesOfNode( itemIndex, pFilePath, m_Ext );
	}
}


//-----------------------------------------------------------------------------
// setup a context menu whenever a directory is clicked on
//-----------------------------------------------------------------------------
void CGameFileTreeView::GenerateContextMenu( int itemIndex, int x, int y ) 
{
	return;

	/*
	KeyValues *pkv = GetItemData(itemIndex);
	const char *pFilePath = pkv->GetString("path", "");
	if (!pFilePath[0])
		return;

	Menu *pContext = new Menu(this, "FileContext");
	pContext->AddMenuItem("Cloak folder", new KeyValues("CloakFolder", "item", itemIndex), GetParent(), NULL);

	// show the context menu
	pContext->SetPos(x, y);
	pContext->SetVisible(true);
	*/
}


//-----------------------------------------------------------------------------
// Sets an item to be colored as if its a menu
//-----------------------------------------------------------------------------
void CGameFileTreeView::SetItemColorForDirectories( int itemID )
{
	// mark directories in orange
	SetItemFgColor( itemID, Color(224, 192, 0, 255) );
}


//-----------------------------------------------------------------------------
// setup a smaller font
//-----------------------------------------------------------------------------
void CGameFileTreeView::ApplySchemeSettings(IScheme *pScheme)
{
	BaseClass::ApplySchemeSettings(pScheme);
	SetFont( pScheme->GetFont("DefaultSmall") );
}