/**
* Called when the material name has changed
* @param pMaterial The material that was deleted.
* @param oldName The old name of the material.
*/
void MaterialTreeView::MV_OnMaterialNameChanged( MaterialDoc *pMaterial, const char *oldName ) {
	CTreeCtrl &tree = GetTreeCtrl();
	if( !internalChange ) {
		//Delete the old tree item
		HTREEITEM *item = NULL;
		materialToTree.Get( oldName, &item );
		CTreeCtrl &tree = GetTreeCtrl();
		HTREEITEM tempItem = *item;
		CleanLookupTrees( tempItem );
		tree.DeleteItem( tempItem );
		//Now add it back
		idStrList list( 1024 );
		idMaterial	*mat = pMaterial->renderMaterial;
		idStr temp;
		if( treeWithFile ) {
			idStr filename = mat->GetFileName();
			filename.StripPath();
			temp = idStr( mat->GetFileName() ) + "/" + idStr( mat->GetName() ) + "|" + filename;
		} else {
			temp = mat->GetName();
		}
		list.Append( temp );
		AddStrList( NULL, &list, treeWithFile );
		//Keep the items sorted
		//item = NULL;
		materialToTree.Get( pMaterial->name.c_str(), &item );
		if( *item ) {
			CTreeCtrl &tree = GetTreeCtrl();
			HTREEITEM parent = tree.GetParentItem( *item );
			tree.SortChildren( parent );
		}
		MV_OnMaterialChange( pMaterial );
	}
}
/**
* Cleans the lookup tables for the provided item and all children.
* @param item The item to start from
*/
void MaterialTreeView::CleanLookupTrees(HTREEITEM item) {

	idStr qt = GetQuicktreePath(item);
	quickTree.Remove(qt);

	CTreeCtrl& tree = GetTreeCtrl();

	//Clean special lookup tables
	DWORD type = tree.GetItemData(item);
	if(type == TYPE_FILE) {
		idStr file = GetMediaPath(item, TYPE_FILE);
		fileToTree.Remove(file);
	} else if(type == TYPE_MATERIAL) {
		idStr name = GetMediaPath(item, TYPE_MATERIAL);
		materialToTree.Remove(name);
	}

	//Clean all my children
	if(tree.ItemHasChildren(item)) {
		HTREEITEM childItem = tree.GetChildItem(item);
		while(childItem != NULL) {
			CleanLookupTrees(childItem);
			childItem = tree.GetNextSiblingItem(childItem);
		}
	}
}
/**
* Renames a material folder.
* @param item The folder tree item.
* @param name The new name of the material folder.
*/
void MaterialTreeView::RenameFolder( HTREEITEM item, const char *name ) {
	CTreeCtrl &tree = GetTreeCtrl();
	//Clean up the quicktree with the current tree before we allow the edit to commit
	CleanLookupTrees( item );
	//Store some data so the we can make the appropriate changes after the commit
	renamedFolder = item;
	affectedMaterials.Clear();
	GetMaterialPaths( renamedFolder, &affectedMaterials );
	tree.SetItemText( item, name );
	PostMessage( MSG_RENAME_FOLDER_COMPLETE );
}
/**
* Makes sure that a rename operation can be performed after a label edit is complete and
* performs the folder or material rename.
*/
void MaterialTreeView::OnTvnEndlabeledit( NMHDR *pNMHDR, LRESULT *pResult ) {
	LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>( pNMHDR );
	*pResult = 0;
	if( pTVDispInfo->item.pszText ) {
		//Convert any edited text to lower case to keep the name canonical
		idStr newLabel = pTVDispInfo->item.pszText;
		newLabel.ToLower();
		strncpy( pTVDispInfo->item.pszText, newLabel.c_str(), pTVDispInfo->item.cchTextMax );
		CTreeCtrl &tree = GetTreeCtrl();
		DWORD type = tree.GetItemData( pTVDispInfo->item.hItem );
		if( type == TYPE_MATERIAL ) {
			MaterialDoc *pMaterial = materialDocManager->GetCurrentMaterialDoc();
			//Remove our old quick lookup value
			materialToTree.Remove( pMaterial->name.c_str() );
			//Generate the new name
			idStr material;
			HTREEITEM parent = tree.GetParentItem( pTVDispInfo->item.hItem );
			DWORD parentType = tree.GetItemData( parent );
			if( parentType == TYPE_MATERIAL_FOLDER ) {
				//Need to include the material folder
				material = GetMediaPath( parent, TYPE_MATERIAL_FOLDER );
				material += "/";
			}
			material += pTVDispInfo->item.pszText;
			if( declManager->FindMaterial( material, false ) ) {
				//Can't rename because it conflicts with an existing file
				MessageBox( "Unable to rename material because it conflicts with another material", "Error" );
			} else {
				//Add it to our quick lookup
				materialToTree.Set( material, pTVDispInfo->item.hItem );
				//Finally make the change
				internalChange = true;
				pMaterial->SetMaterialName( material );
				internalChange = false;
				renamedFolder = pTVDispInfo->item.hItem;
				PostMessage( MSG_RENAME_MATERIAL_COMPLETE );
				*pResult = 1;
			}
		} else if( type == TYPE_MATERIAL_FOLDER ) {
			//Clean up the quicktree with the current tree before we allow the edit to commit
			CleanLookupTrees( pTVDispInfo->item.hItem );
			//Store some data so the we can make the appropriate changes after the commit
			renamedFolder = pTVDispInfo->item.hItem;
			affectedMaterials.Clear();
			GetMaterialPaths( renamedFolder, &affectedMaterials );
			PostMessage( MSG_RENAME_FOLDER_COMPLETE );
			RenameMaterialFolderModifier *mod = new RenameMaterialFolderModifier( materialDocManager, pTVDispInfo->item.pszText, this, pTVDispInfo->item.hItem, tree.GetItemText( pTVDispInfo->item.hItem ) );
			materialDocManager->AddMaterialUndoModifier( mod );
			*pResult = 1;
		}
	}
}
/**
* Called when a file has been reloaded
* @param filename The file that was reloaded.
*/
void MaterialTreeView::MV_OnFileReload( const char *filename ) {
	HTREEITEM *fileItem = NULL;
	fileToTree.Get( filename, &fileItem );
	HTREEITEM item = *fileItem;
	CTreeCtrl &tree = GetTreeCtrl();
	CleanLookupTrees( item );
	tree.DeleteItem( item );
	BuildMaterialList( treeWithFile, filename );
	//Resort the parent to make sure the file is back where it was
	HTREEITEM *newItem = NULL;
	fileToTree.Get( filename, &newItem );
	if( *newItem ) {
		CTreeCtrl &tree = GetTreeCtrl();
		HTREEITEM parent = tree.GetParentItem( *newItem );
		tree.SortChildren( parent );
	}
}
/**
* Deletes a given folder.
* @param item The folder to delete.
* @param addUndo True if this operation can be undone.
*/
void  MaterialTreeView::DeleteFolder( HTREEITEM item, bool addUndo ) {
	CTreeCtrl &tree = GetTreeCtrl();
	idList<MaterialTreeItem_t> materialsToDelete;
	//Get the complete list of materials to delete
	GetMaterialPaths( item, &materialsToDelete );
	idStrList affectedMaterials;
	//Now delete the materials
	for( int i = 0; i < materialsToDelete.Num(); i++ ) {
		affectedMaterials.Append( materialsToDelete[i].materialName );
		const idMaterial *material = declManager->FindMaterial( materialsToDelete[i].materialName );
		MaterialDoc *pMaterial = NULL;
		pMaterial = materialDocManager->CreateMaterialDoc( const_cast<idMaterial *>( material ) );
		materialDocManager->DeleteMaterial( pMaterial, false );
	}
	//Make our undo modifier
	if( addUndo ) {
		DeleteMaterialFolderModifier *mod = new DeleteMaterialFolderModifier( materialDocManager, tree.GetItemText( item ), this, tree.GetParentItem( item ), &affectedMaterials );
		materialDocManager->AddMaterialUndoModifier( mod );
	}
	//Now clean up the folders and quicktree
	CleanLookupTrees( item );
	//Remove any folders that were there
	tree.DeleteItem( item );
}