/*
**	Command & Conquer Renegade(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

// PresetsForm.cpp : implementation file
//

#include "stdafx.h"
#include "leveledit.h"
#include "presetslibform.h"
#include "utils.h"
#include "filemgr.h"
#include "definitionfactorymgr.h"
#include "definitionclassids.h"
#include "definitionfactory.h"
#include "definitionmgr.h"
#include "definition.h"
#include "icons.h"
#include "terraindefinition.h"
#include "preset.h"
#include "presetmgr.h"
#include "sceneeditor.h"
#include "saveload.h"
#include "rawfile.h"
#include "chunkio.h"
#include "filelocations.h"
#include "nodecategories.h"
#include "editorchunkids.h"
#include "regkeys.h"
#include "nodemgr.h"
#include "LevelEditView.h"
#include "PlaySoundDialog.h"
#include "AudibleSound.h"
#include "UpdatePresetDialog.h"
#include "definitionutils.h"
#include "presetlogger.h"
#include "rendobj.h"
#include "phys.h"
#include "textfile.h"
#include "node.h"
#include "ramfile.h"
#include "editorbuild.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


///////////////////////////////////////////////////////////////////////
//
//	Helper objects
//
///////////////////////////////////////////////////////////////////////
class SelectionCaptureClass
{
public:
	SelectionCaptureClass (PresetsFormClass *preset_form)
	{
		m_PresetForm							= preset_form;
		HTREEITEM tree_item					= m_PresetForm->m_TreeCtrl.GetSelectedItem ();
		PresetClass *preset					= m_PresetForm->Get_Item_Preset (tree_item);
		DefinitionFactoryClass *factory	= m_PresetForm->Get_Item_Factory (tree_item);
		if (preset != NULL) {
			m_ID = preset->Get_ID ();
			m_IsFactory = false;
		} else {
			m_ID = factory->Get_Class_ID ();
			m_IsFactory = true;
		}
		return ;
	}

	void Restore (void)
	{
		m_PresetForm->Reselect_Item (m_ID, m_IsFactory);
		return ;
	}

private:
	PresetsFormClass *	m_PresetForm;
	int						m_ID;
	bool						m_IsFactory;
};


///////////////////////////////////////////////////////////////////////
//
//	Macros
//
///////////////////////////////////////////////////////////////////////
#ifndef TreeView_SetOverlay
   #define TreeView_SetOverlay(hwndLV, i, overlay) \
      {	\
			TVITEMEX item_info = { TVIF_STATE, i, INDEXTOOVERLAYMASK(overlay), TVIS_OVERLAYMASK, 0 };	\
			TreeView_SetItem(hwndLV, &item_info);	\
		}
#endif


///////////////////////////////////////////////////////////////////////
//
//	Constants
//
///////////////////////////////////////////////////////////////////////
typedef enum
{
	TYPE_FACTORY,
	TYPE_PRESET,
} ITEM_TYPE;

typedef struct
{
	ITEM_TYPE	type;
	union
	{
		DefinitionFactoryClass *factory;
		PresetClass *preset;
	};

} ITEM_DATA;


static const int TOOLBAR_HEIGHT					= 36;
static const int TOOLBAR_V_SPACING				= 5;
static const int TOOLBAR_V_BORDER				= TOOLBAR_V_SPACING * 2;
static const int TOOLBAR_H_SPACING				= 5;
static const int TOOLBAR_H_BORDER				= TOOLBAR_H_SPACING * 2;


/////////////////////////////////////////////////////////////////////////////
//
// PresetsFormClass
//
/////////////////////////////////////////////////////////////////////////////
PresetsFormClass::PresetsFormClass(CWnd *parent_wnd)
	:	m_DragItem (NULL),
		m_IsDragging (false),
		m_DragImageList (NULL),
		CDialog(PresetsFormClass::IDD)
{
	//{{AFX_DATA_INIT(PresetsFormClass)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	Create (PresetsFormClass::IDD, parent_wnd);
	return ;
}

PresetsFormClass::~PresetsFormClass()
{
	return ;
}

void PresetsFormClass::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(PresetsFormClass)
	DDX_Control(pDX, IDC_PRESETS_TREE, m_TreeCtrl);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(PresetsFormClass, CDialog)
	//{{AFX_MSG_MAP(PresetsFormClass)
	ON_WM_SIZE()
	ON_COMMAND(IDC_ADD, OnAdd)
	ON_NOTIFY(TVN_DELETEITEM, IDC_PRESETS_TREE, OnDeleteitemPresetsTree)
	ON_COMMAND(IDC_MODIFY, OnModify)
	ON_COMMAND(IDC_MAKE, OnMake)
	ON_COMMAND(IDC_ADD_TEMP, OnAddTemp)
	ON_COMMAND(IDC_DELETE, OnDelete)
	ON_NOTIFY(TVN_SELCHANGED, IDC_PRESETS_TREE, OnSelchangedPresetsTree)
	ON_COMMAND(IDC_PLAY, OnPlay)
	ON_COMMAND(IDC_INFO, OnInfo)
	ON_COMMAND(IDC_EXTRA, OnExtra)
	ON_UPDATE_COMMAND_UI(IDC_CONVERT, OnUpdateConvert)
	ON_UPDATE_COMMAND_UI(IDC_INFO, OnUpdateInfo)
	ON_UPDATE_COMMAND_UI(IDC_PLAY, OnUpdatePlay)
	ON_UPDATE_COMMAND_UI(IDC_UPDATE_VSS, OnUpdateUpdateVss)
	ON_WM_DRAWITEM()
	ON_WM_MEASUREITEM()
	ON_COMMAND(IDC_CONVERT, OnConvert)
	ON_COMMAND(IDC_UPDATE_VSS, OnUpdateVss)
	ON_COMMAND(IDM_BATCH_IMPORT_TERRAIN, OnBatchImportTerrain)
	ON_COMMAND(IDM_UPDATE_EMBEDDED_NODE_LIST, OnBuildEmbedNodeList)
	ON_COMMAND(IDM_CLEAR_EMBEDDED_NODE_LIST, OnClearEmbeddedNodeList)	
	ON_UPDATE_COMMAND_UI(IDM_BATCH_IMPORT_TERRAIN, OnUpdateBatchImportTerrain)
	ON_UPDATE_COMMAND_UI(IDM_UPDATE_EMBEDDED_NODE_LIST, OnUpdateEmbeddedNodeList)
	ON_UPDATE_COMMAND_UI(IDM_CLEAR_EMBEDDED_NODE_LIST, OnUpdateClearEmbeddedNodeList)	
	ON_NOTIFY(TVN_BEGINDRAG, IDC_PRESETS_TREE, OnBegindragPresetsTree)
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_WM_DESTROY()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// PresetsFormClass diagnostics

#ifdef _DEBUG
void PresetsFormClass::AssertValid() const
{
	CDialog::AssertValid();
}

void PresetsFormClass::Dump(CDumpContext& dc) const
{
	CDialog::Dump(dc);
}
#endif //_DEBUG


/////////////////////////////////////////////////////////////////////////////
//
// OnSize
//
/////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnSize
(
	UINT	nType,
	int	cx,
	int	cy
)
{
	CDialog::OnSize(nType, cx, cy);
	
	if (::IsWindow (m_TreeCtrl) && (cx > 0) && (cy > 0)) {

		// Get the bounding rectangle of the form window
		CRect parentrect;
		GetWindowRect (&parentrect);
		
		// Get the bounding rectangle of the toolbar
		CRect toolbar_rect;
		m_Toolbar.GetWindowRect (&toolbar_rect);
		ScreenToClient (&toolbar_rect);

		// Move the toolbar so it is in its correct position
		m_Toolbar.SetWindowPos (NULL,
								TOOLBAR_H_SPACING,
								(cy - TOOLBAR_V_SPACING) - toolbar_rect.Height (),
								cx - TOOLBAR_H_BORDER,
								toolbar_rect.Height (),
								SWP_NOZORDER);

		// Get the bounding rectnagle of the list ctrl
		RECT list_rect;
		m_TreeCtrl.GetWindowRect (&list_rect);
				
		CRect client_rect = list_rect;
		ScreenToClient (&client_rect);
		int list_height = ((cy - TOOLBAR_V_BORDER) - toolbar_rect.Height ()) - client_rect.top;

		//
		// Resize the tab control to fill the empty contents of the client area
		//
		m_TreeCtrl.SetWindowPos (	NULL,
									0,
									0,
									cx-((list_rect.left-parentrect.left) << 1),
									list_height,
									SWP_NOZORDER | SWP_NOMOVE);	
	}
		
	return ;
}


/////////////////////////////////////////////////////////////////////////////
//
// OnInitDialog
//
/////////////////////////////////////////////////////////////////////////////
BOOL
PresetsFormClass::OnInitDialog (void)
{
	CDialog::OnInitDialog ();

	CRect rect;
	GetClientRect (&rect);
	m_Toolbar.CreateEx (this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP, CRect(0, 0, 0, 0), 101);
	m_Toolbar.SetOwner (this);
	m_Toolbar.LoadToolBar (IDR_PRESET_TOOLBAR1);
	m_Toolbar.SetBarStyle (m_Toolbar.GetBarStyle () | CBRS_TOOLTIPS | CBRS_FLYBY);
	m_Toolbar.GetToolBarCtrl ().SetExtendedStyle (TBSTYLE_EX_DRAWDDARROWS);
	
	TBBUTTONINFO button_info = { sizeof (TBBUTTONINFO), TBIF_STYLE, 0 };
	int index = m_Toolbar.CommandToIndex (IDC_EXTRA);
	m_Toolbar.GetToolBarCtrl ().GetButtonInfo (IDC_EXTRA, &button_info);
	button_info.fsStyle |= TBSTYLE_DROPDOWN;
	m_Toolbar.GetToolBarCtrl ().SetButtonInfo (IDC_EXTRA, &button_info);

	//
	// Get the bounding rectangle of the form window
	//
	CRect parentrect;
	GetWindowRect (&parentrect);
	m_Toolbar.SetWindowPos (NULL, 0, 0, parentrect.Width () - TOOLBAR_H_BORDER, TOOLBAR_HEIGHT, SWP_NOZORDER | SWP_NOMOVE);	
	m_Toolbar.Enable_Button (IDC_ADD,		Enable_Button (IDC_ADD));
	m_Toolbar.Enable_Button (IDC_DELETE,	Enable_Button (IDC_DELETE));

	//
	// Pass the general use imagelist onto the tree control
	//
	m_TreeCtrl.SetImageList (::Get_Global_Image_List (), TVSIL_NORMAL);
	Reload_Presets ();
	
	//
	//	Select the first item in the tree control
	//
	HTREEITEM first_item = m_TreeCtrl.GetNextItem (NULL, TVGN_CHILD);
	if (first_item != NULL) {
		m_TreeCtrl.SelectItem (first_item);
	}

	SetProp (m_TreeCtrl, "TRANS_ACCS", (HANDLE)1);
	SetProp (m_hWnd, "TRANS_ACCS", (HANDLE)1);
	return TRUE;
}


/////////////////////////////////////////////////////////////////////////////
//
// Reload_Presets
//
/////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Reload_Presets (void)
{
	m_TreeCtrl.SetRedraw (FALSE);
	m_TreeCtrl.SelectItem (NULL);
	m_TreeCtrl.DeleteAllItems ();

	//
	//	Loop through and add all the registered definition factories to
	// the tree control
	//
	for (int index = 0; index < PRESET_CATEGORY_COUNT; index ++) {

		//
		//	Add this factory to the tree
		//
		HTREEITEM tree_item = m_TreeCtrl.InsertItem (PRESET_CATEGORIES[index].name, FOLDER_ICON, FOLDER_ICON);
			
		//
		//	Is there a factory to create this class of defintion?
		//
		DefinitionFactoryClass *factory = DefinitionFactoryMgrClass::Find_Factory (PRESET_CATEGORIES[index].clsid);
		if (factory != NULL) {
				
			//
			//	Add all presets for this factory into the tree
			//
			if (factory->Is_Displayed ()) {
				Set_Item_Data (tree_item, factory);
				Fill_In_Presets (tree_item);
			}
		} else {

			//
			//	Find all the sub-factories
			//			
			for (	factory = DefinitionFactoryMgrClass::Get_First (PRESET_CATEGORIES[index].clsid);
					factory != NULL;
					factory = DefinitionFactoryMgrClass::Get_Next (factory, PRESET_CATEGORIES[index].clsid))
			{
				//
				//	Add this sub-factory and all its definitions to the tree
				//
				if (factory->Is_Displayed ()) {
					LPCTSTR name = factory->Get_Name ();
					HTREEITEM child_item = m_TreeCtrl.InsertItem (factory->Get_Name (), FOLDER_ICON, FOLDER_ICON, tree_item);
					Set_Item_Data (child_item, factory);
					Fill_In_Presets (child_item);
				}
			}
		}
	}
	
	Sort_Nodes (TVI_ROOT);
	m_TreeCtrl.SetRedraw (TRUE);
	return ;
}


/////////////////////////////////////////////////////////////////////////////
//
// Fill_In_Presets
//
/////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Fill_In_Presets (HTREEITEM root_item)
{
	DefinitionFactoryClass *factory = Get_Item_Factory (root_item);
	if (factory != NULL && factory->Is_Displayed ()) {
		uint32 class_id = factory->Get_Class_ID ();

		//
		//	Find all the presets that belong to this class
		//
		PresetClass *preset = NULL;
		for (	preset = PresetMgrClass::Get_First (class_id, PresetMgrClass::ID_CLASS);
				preset != NULL;
				preset = PresetMgrClass::Get_Next (preset, class_id, PresetMgrClass::ID_CLASS))
		{
			
			//
			//	Add this preset to the tree
			//
			if (preset->Get_Parent () == NULL) {
				HTREEITEM tree_item = Insert_Preset (root_item, preset);
				if (tree_item != NULL) {

					//
					//	Recursively fill in this definition's 'children'
					//
					Fill_In_Preset_Children (tree_item, preset->Get_ID ());
				}
			}
		}
	}

	return ;
}


/////////////////////////////////////////////////////////////////////////////
//
// Fill_In_Preset_Children
//
/////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Fill_In_Preset_Children
(
	HTREEITEM	root_item,
	uint32		parent_id
)
{
	//
	//	Lookup the parent preset
	//
	PresetClass *parent_preset = PresetMgrClass::Find_Preset (parent_id);	
	if (parent_preset == NULL) {
		return ;
	}

	//
	//	Loop over all the children of this preset
	//
	int count = parent_preset->Get_Child_Preset_Count ();
	for (int index = 0; index < count; index ++) {
		PresetClass *child_preset = parent_preset->Get_Child_Preset (index);
		if (child_preset != NULL) {

			//
			//	Check to make sure we have no recursive links
			//
			PresetClass *parent = child_preset->Get_Parent ();
			if (parent == child_preset || parent->Get_ID () == child_preset->Get_ID ()) {
				CString message;
				message.Format ("Preset '%s' is recursively linked to itself.\r\n", child_preset->Get_Name ());
				MessageBox (message, "Preset Error", MB_ICONERROR | MB_OK | MB_SETFOREGROUND);
				continue ;
			}

			//
			//	Check to make sure the parent is correct
			//
			if (parent != NULL && child_preset->Get_Class_ID () != parent->Get_Class_ID ()) {
				CString message;
				message.Format ("Preset '%s' is incorrectly linked as a child of '%s'.\r\n", child_preset->Get_Name (), parent->Get_Name ());
				MessageBox (message, "Preset Error", MB_ICONERROR | MB_OK | MB_SETFOREGROUND);
			}
			
			//
			//	Add this preset to the tree
			//
			HTREEITEM tree_item = Insert_Preset (root_item, child_preset);
			if (tree_item != NULL) {

				//
				//	Recursively fill in this definition's 'children'
				//
				Fill_In_Preset_Children (tree_item, child_preset->Get_ID ());
			}
		}
	}

	return ;
}


/////////////////////////////////////////////////////////////////////////////
//
// Find_Preset
//
/////////////////////////////////////////////////////////////////////////////
HTREEITEM
PresetsFormClass::Find_Preset (HTREEITEM root_item, uint32 id)
{
	HTREEITEM preset_item = NULL;

	//
	//	Look for the preset in this item's children (recursive)
	//
	for (	HTREEITEM tree_item = m_TreeCtrl.GetChildItem (root_item);
			(tree_item != NULL) && (preset_item == NULL);
			tree_item = m_TreeCtrl.GetNextSiblingItem (tree_item))
	{
		DefinitionClass *definition = Get_Item_Definition (tree_item);

		//
		// Is this the preset we were looking for?
		//
		if ((definition != NULL) && (definition->Get_ID () == id)) {
			preset_item = tree_item;
		} else if (m_TreeCtrl.ItemHasChildren (tree_item)) {
			
			//
			// Recursively call this method for all sub-folders in this tree
			//
			preset_item = Find_Preset (tree_item, id);
		}
	}

	return preset_item;
}


/////////////////////////////////////////////////////////////////////////////
//
// Find_Factory
//
/////////////////////////////////////////////////////////////////////////////
HTREEITEM
PresetsFormClass::Find_Factory (HTREEITEM root_item, uint32 id)
{
	HTREEITEM factory_item = NULL;

	//
	//	Look for the preset in this item's children (recursive)
	//
	for (	HTREEITEM tree_item = m_TreeCtrl.GetChildItem (root_item);
			(tree_item != NULL) && (factory_item == NULL);
			tree_item = m_TreeCtrl.GetNextSiblingItem (tree_item))
	{
		DefinitionFactoryClass *factory = Get_Item_Factory (tree_item);

		//
		// Is this the factory we were looking for?
		//
		if ((factory != NULL) && (factory->Get_Class_ID () == id)) {
			factory_item = tree_item;
		} else if (m_TreeCtrl.ItemHasChildren (tree_item)) {
			
			//
			// Recursively call this method for all sub-folders in this tree
			//
			factory_item = Find_Factory (tree_item, id);
		}
	}

	return factory_item;
}


/////////////////////////////////////////////////////////////////////////////
//
// Get_Selected_Factory
//
/////////////////////////////////////////////////////////////////////////////
DefinitionFactoryClass *
PresetsFormClass::Get_Selected_Factory (void)
{	
	HTREEITEM curr_item					= m_TreeCtrl.GetSelectedItem ();
	DefinitionFactoryClass *factory	= Get_Item_Factory (curr_item);
		
	// Does this item represent a definition?
	if (factory == NULL) {		
		
		//
		//	Find the defintion's factory (if possible)
		//
		DefinitionClass *definition = Get_Item_Definition (curr_item);
		if (definition != NULL) {
			uint32 class_id = definition->Get_Class_ID ();
			factory = DefinitionFactoryMgrClass::Find_Factory (class_id);
		} 		
	}

	return factory;
}


/////////////////////////////////////////////////////////////////////////////
//
// Set_Item_Data
//
/////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Set_Item_Data (HTREEITEM item, DefinitionFactoryClass *factory)
{
	//
	//	Allocate a new wrapper if we need to
	//
	ITEM_DATA *item_data = (ITEM_DATA *)m_TreeCtrl.GetItemData (item);
	if (item_data == NULL) {
		item_data = new ITEM_DATA;
	}

	//
	//	Set a flag in the wrapper so we know what kind of data
	// this tree item contains.
	//
	item_data->type		= TYPE_FACTORY;
	item_data->factory	= factory;
	m_TreeCtrl.SetItemData (item, (DWORD)item_data);
	return ;	
}


/////////////////////////////////////////////////////////////////////////////
//
// Set_Item_Data
//
/////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Set_Item_Data (HTREEITEM item, PresetClass *preset)
{
	//
	//	Allocate a new wrapper if we need to
	//
	ITEM_DATA *item_data = (ITEM_DATA *)m_TreeCtrl.GetItemData (item);
	if (item_data == NULL) {
		item_data = new ITEM_DATA;
	}

	//
	//	Set a flag in the wrapper so we know what kind of data
	// this tree item contains.
	//
	item_data->type	= TYPE_PRESET;
	item_data->preset	= preset;
	m_TreeCtrl.SetItemData (item, (DWORD)item_data);
	return ;	
}


/////////////////////////////////////////////////////////////////////////////
//
// Get_Item_Factory
//
/////////////////////////////////////////////////////////////////////////////
DefinitionFactoryClass *
PresetsFormClass::Get_Item_Factory (HTREEITEM item)
{
	DefinitionFactoryClass *factory = NULL;
	if (item != NULL) {

		//
		//	If this item represents a factory, then return the factory
		//	pointer to the caller.
		//
		ITEM_DATA *item_data = (ITEM_DATA *)m_TreeCtrl.GetItemData (item);
		if ((item_data != NULL) && (item_data->type == TYPE_FACTORY)) {
			factory = item_data->factory;
		}
	}

	return factory;
}


/////////////////////////////////////////////////////////////////////////////
//
// Get_Item_Definition
//
/////////////////////////////////////////////////////////////////////////////
DefinitionClass *
PresetsFormClass::Get_Item_Definition (HTREEITEM item)
{
	DefinitionClass *definition = NULL;
	if (item != NULL) {

		//
		//	Get the definition from the preset this item
		// represents
		//
		PresetClass *preset = Get_Item_Preset (item);
		if (preset != NULL) {
			definition = preset->Get_Definition ();
		}
	}

	return definition;
}


/////////////////////////////////////////////////////////////////////////////
//
// Get_Item_Preset
//
/////////////////////////////////////////////////////////////////////////////
PresetClass *
PresetsFormClass::Get_Item_Preset (HTREEITEM item)
{
	PresetClass *preset = NULL;
	if (item != NULL) {

		//
		//	If this item represents a definition, then return the definition
		//	pointer to the caller.
		//
		ITEM_DATA *item_data = (ITEM_DATA *)m_TreeCtrl.GetItemData (item);
		if ((item_data != NULL) && (item_data->type == TYPE_PRESET)) {
			preset = item_data->preset;
		}
	}

	return preset;
}


/////////////////////////////////////////////////////////////////////////////
//
// Get_Icon
//
/////////////////////////////////////////////////////////////////////////////
int
PresetsFormClass::Get_Icon (PresetClass *preset)
{
	int icon = FOLDER_ICON;
	
	DefinitionClass *definition = preset->Get_Definition ();
	if (definition != NULL) {
		int class_id		= definition->Get_Class_ID ();
		int superclass_id	= ::SuperClassID_From_ClassID (class_id);
		switch (superclass_id) {

			case CLASSID_TERRAIN:
				icon = TERRAIN_ICON;
				break;

			case CLASSID_TILE:
				icon = TILE_ICON;
				break;

			case CLASSID_GAME_OBJECTS:
			case CLASSID_MUNITIONS:
			case CLASSID_DUMMY_OBJECTS:
				if (class_id == CLASSID_GAME_OBJECT_DEF_BUILDING) {
					icon = BUILDING_ICON;
				} else {
					icon = OBJECT_ICON;
				}
				break;

			case CLASSID_LIGHT:
				icon = LIGHT_ICON;
				break;

			case CLASSID_SOUND:
				icon = SOUND_ICON;
				break;

			case CLASSID_WAYPATH:
				icon = WAYPATH_ICON;
				break;

			case CLASSID_ZONE:
				icon = ZONE_ICON;
				break;

			case CLASSID_TRANSITION:
				icon = TRANSITION_ICON;
				break;

			case CLASSID_TWIDDLERS:
				icon = RAND_ICON;
				break;

			case CLASSID_BUILDINGS:
				icon = BUILDING_ICON;
				break;

			case CLASSID_EDITOR_OBJECTS:
				if (class_id == CLASSID_VIS_POINT_DEF) {
					icon = VIS_ICON;
				} else  if (class_id == CLASSID_PATHFIND_START_DEF) {
					icon = PATHFIND_ICON;
				}
				break;

			case CLASSID_GLOBAL_SETTINGS:
				icon = FILE_ICON;
				break;
		}
	}

	if (preset->Get_IsTemporary ()) {
		icon = TEMP_ICON;
	}

	return icon;
}


/////////////////////////////////////////////////////////////////////////////
//
// Insert_Preset
//
/////////////////////////////////////////////////////////////////////////////
HTREEITEM
PresetsFormClass::Insert_Preset
(
	HTREEITEM		root_item,
	PresetClass *	preset
)
{
	int icon = Get_Icon (preset);

	//
	//	Insert a new node into the tree to represent this item
	//
	HTREEITEM tree_item = m_TreeCtrl.InsertItem (preset->Get_Name (), icon, icon, root_item);
	if (tree_item != NULL) {
		Set_Item_Data (tree_item, preset);

		bool needs_overlay = (preset->Get_Node_List ().Count () > 0);
		TreeView_SetOverlay (m_TreeCtrl, tree_item, needs_overlay);
	}	

	return tree_item;
}


/////////////////////////////////////////////////////////////////////////////
//
// OnDeleteitemPresetsTree
//
/////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnDeleteitemPresetsTree
(
	NMHDR *	pNMHDR,
	LRESULT *pResult
)
{
	NM_TREEVIEW *pNMTreeView = (NM_TREEVIEW *)pNMHDR;
	(*pResult) = 0;

	//
	// Free the wrapper we installed around this item
	//
	ITEM_DATA *item_data = (ITEM_DATA *)m_TreeCtrl.GetItemData (pNMTreeView->itemOld.hItem);
	SAFE_DELETE (item_data);
	m_TreeCtrl.SetItemData (pNMTreeView->itemOld.hItem, 0L);	
	return ;
}


/////////////////////////////////////////////////////////////////////////////
//
// OnModify
//
/////////////////////////////////////////////////////////////////////////////
bool
PresetsFormClass::Modify_Preset (void)
{
	bool retval = false;

	HTREEITEM current_item	= m_TreeCtrl.GetSelectedItem ();
	PresetClass *preset		= Get_Item_Preset (current_item);
	if (preset != NULL) {

		StringClass old_name = preset->Get_Name ();

		//
		//	Show the properties dialog for this preset
		//
		if (preset->Show_Properties ()) {
			
			//
			//	Check to see if the user has renamed the preset
			//
			StringClass new_name = preset->Get_Name ();
			if (::lstrcmp (old_name, new_name) != 0) {
				
				//
				//	Rename the item in the tree
				//
				m_TreeCtrl.SetRedraw (FALSE);
				m_TreeCtrl.SetItemText (current_item, preset->Get_Name ());
				m_TreeCtrl.SetRedraw (TRUE);
				m_TreeCtrl.InvalidateRect (NULL, TRUE);

				//
				//	Log the rename operation
				//
				if (preset->Get_IsTemporary () == false) {
					PresetLoggerClass::Log_Renamed (old_name, new_name);
				}
			}

			retval = true;
		}
	}

	return retval;
}


/////////////////////////////////////////////////////////////////////////////
//
// OnModify
//
/////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnModify (void) 
{
	HTREEITEM current_item	= m_TreeCtrl.GetSelectedItem ();
	PresetClass *preset		= Get_Item_Preset (current_item);
	if (preset != NULL) {

		if (preset->Get_IsTemporary () == false) {

			//
			//	Check out the definition database
			//
			SelectionCaptureClass sel_capture (this);
			bool undo_on_err	= false;
			uint32 class_id	= preset->Get_Class_ID ();
			if (PresetMgrClass::Check_Out_Database (class_id, &undo_on_err)) {
				sel_capture.Restore ();

				//
				//	Re-get the preset (its pointer has changed, the
				// old one is crap).
				//
				current_item	= m_TreeCtrl.GetSelectedItem ();
				preset			= Get_Item_Preset (current_item);
				if (preset != NULL) {

					//
					//	Show the preset settings
					//
					if (Modify_Preset ()) {
						Save_Global_Presets (class_id);
						PresetMgrClass::Add_Dirty_Preset (preset->Get_ID ());						
					} else if (undo_on_err) {
						PresetMgrClass::Undo_Database_Check_Out (class_id);
					}
				}
			}

		} else {
			
			//
			//	Show the preset settings
			//
			if (Modify_Preset ()) {
				Save_Temp_Presets ();				
			}
		}

		NodeMgrClass::Reload_Nodes (preset);
	}

	return ;
}


/////////////////////////////////////////////////////////////////////////////
//
// Load_Databases
//
/////////////////////////////////////////////////////////////////////////////
bool
PresetsFormClass::Load_Databases (void)
{
	// Start fresh
	PresetMgrClass::Free_Presets ();
	DefinitionMgrClass::Free_Definitions ();
	
	bool retval = false;

#ifdef PUBLIC_EDITOR_VER
	
	//
	//	Reload the presets
	//
	retval = Old_Load_Presets ();
	retval	&=	Load_Temp_Presets ();

#else
	
	//
	//	Reload the presets
	//
	retval	=	Load_Preset_Libraries ();
	retval	&=	Load_Temp_Presets ();

#endif //PUBLIC_EDITOR_VER
	
	return retval;
}


/////////////////////////////////////////////////////////////////////////////
//
// Load_Preset_Libraries
//
/////////////////////////////////////////////////////////////////////////////
bool
PresetsFormClass::Load_Preset_Libraries (void)
{
	//
	//	Try to load the library for each factory
	//
	DefinitionFactoryClass *factory = NULL;
	for (	factory = DefinitionFactoryMgrClass::Get_First ();
			factory != NULL;
			factory = DefinitionFactoryMgrClass::Get_Next (factory))
	{
		if (factory->Is_Displayed ()) {
			Load_Presets (factory->Get_Class_ID ());
		}
	}

	return true;
}


/////////////////////////////////////////////////////////////////////////////
//
// Load_Presets
//
/////////////////////////////////////////////////////////////////////////////
bool
PresetsFormClass::Load_Presets (uint32 class_id)
{
	//
	//	Build a filename for the presets library
	//
	CString path;
	::Get_File_Mgr ()->Get_Preset_Library_Path (class_id, false, path);

	//
	//	Open the file
	//
	HANDLE file = ::CreateFile (	path,
											GENERIC_READ,
											FILE_SHARE_READ,
											NULL,
											OPEN_EXISTING,
											0L,
											NULL);

	if (file != INVALID_HANDLE_VALUE) {

		//
		//	Determine how large the file is
		//
		int file_size = ::GetFileSize (file, NULL);
		if (file_size > 0 && file_size < 99999999) 
		{
			//
			//	Read the file into memory
			//
			unsigned char *buffer = new unsigned char[file_size];
			DWORD bytes_read = 0;
			::ReadFile (file, buffer, file_size, &bytes_read, NULL);

			//
			//	Close the file
			//
			::CloseHandle (file);
			file = INVALID_HANDLE_VALUE;

			//
			//	Use a RAM file for the loading
			//
			RAMFileClass file_obj (buffer, file_size);
			file_obj.Open (FileClass::READ);
			ChunkLoadClass chunk_load (&file_obj);

			//
			//	Load the file
			//
			SaveLoadSystemClass::Load (chunk_load);

			//
			//	Free the buffer
			//
			delete [] buffer;
			buffer = NULL;
		}
	}

	return true;
}


/////////////////////////////////////////////////////////////////////////////
//
// Old_Load_Presets
//
/////////////////////////////////////////////////////////////////////////////
bool
PresetsFormClass::Old_Load_Presets (void)
{
	CString path = ::Get_File_Mgr ()->Make_Full_Path (OBJECTS_DDB_PATH);

	//
	//	Open the file
	//
	HANDLE file = ::CreateFile (path,
										  GENERIC_READ,
										  FILE_SHARE_READ,
										  NULL,
										  OPEN_EXISTING,
										  0L,
										  NULL);

	if (file != INVALID_HANDLE_VALUE) {

		//
		//	Determine how large the file is
		//
		int file_size = ::GetFileSize (file, NULL);
		if (file_size > 0 && file_size < 99999999) 
		{
			//
			//	Read the file into memory
			//
			unsigned char *buffer = new unsigned char[file_size];
			DWORD bytes_read = 0;
			::ReadFile (file, buffer, file_size, &bytes_read, NULL);

			//
			//	Close the file
			//
			::CloseHandle (file);
			file = INVALID_HANDLE_VALUE;

			//
			//	Use a RAM file for the loading
			//
			RAMFileClass file_obj (buffer, file_size);
			file_obj.Open (FileClass::READ);
			ChunkLoadClass chunk_load (&file_obj);

			//
			//	Load the file
			//
			SaveLoadSystemClass::Load (chunk_load);

			//
			//	Free the buffer
			//
			delete [] buffer;
			buffer = NULL;
		}
	}

	return true;
}


/////////////////////////////////////////////////////////////////////////////
//
// Load_Temp_Presets
//
/////////////////////////////////////////////////////////////////////////////
bool
PresetsFormClass::Load_Temp_Presets (void)
{
	CString path = ::Get_File_Mgr ()->Make_Full_Path (TEMP_DB_PATH);

	//
	//	Open the file
	//
	HANDLE hfile = ::CreateFile (path,
										  GENERIC_READ,
										  FILE_SHARE_READ,
										  NULL,
										  OPEN_EXISTING,
										  0L,
										  NULL);

	if (hfile != INVALID_HANDLE_VALUE) {

		RawFileClass file_obj;
		file_obj.Attach (hfile);
		ChunkLoadClass chunk_load (&file_obj);

		//
		//	Load the file
		//
		SaveLoadSystemClass::Load (chunk_load);
	}
	
	return true;
}


/////////////////////////////////////////////////////////////////////////////
//
// Save_Temp_Presets
//
/////////////////////////////////////////////////////////////////////////////
bool
PresetsFormClass::Save_Temp_Presets (void)
{
	Save_Presets (0, true);
	return true;
}


/////////////////////////////////////////////////////////////////////////////
//
// Save_Global_Presets
//
/////////////////////////////////////////////////////////////////////////////
bool
PresetsFormClass::Save_Global_Presets (uint32 class_id)
{

#ifndef PUBLIC_EDITOR_VER
	
	Save_Presets (class_id, false);

#endif //PUBLIC_EDITOR_VER

	return true;
}


/////////////////////////////////////////////////////////////////////////////
//
// Build_DDB_File_List
//
/////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Build_DDB_File_List
(
	DynamicVectorClass<CString> &	file_list,
	HTREEITEM							parent_item
)
{
	//
	//	Loop over all the immediate children
	//
	for (	HTREEITEM child_item = m_TreeCtrl.GetChildItem (parent_item);
			child_item != NULL;
			child_item = m_TreeCtrl.GetNextSiblingItem (child_item))
	{
		//
		//	If this tree item represents a definition factory, then
		// we should have a preset library to match
		//
		DefinitionFactoryClass *factory = Get_Item_Factory (child_item);
		if (factory != NULL) {			

			//
			//	Build a filename for this preset library
			//
			CString path;
			::Get_File_Mgr ()->Get_Preset_Library_Path (factory->Get_Class_ID (), false, path);

			//
			//	Add this preset library to the list
			//
			file_list.Add (path);

		} else if (m_TreeCtrl.ItemHasChildren (child_item)) {
			
			//
			// Recursively call this method for all sub-folders in this tree
			//		
			Build_DDB_File_List (file_list, child_item);
		}
	}
	
	return ;
}


/////////////////////////////////////////////////////////////////////////////
//
// Save_Preset_Libraries
//
/////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Save_Preset_Libraries (HTREEITEM parent_item)
{

#ifdef PUBLIC_EDITOR_VER

	//
	//	Simply save the presets together in one file
	//
	CString path = ::Get_File_Mgr ()->Make_Full_Path (OBJECTS_DDB_PATH);
	Save_Presets (path, 0, false, false);		

#else

	//
	//	Loop over all the immediate children
	//
	for (	HTREEITEM child_item = m_TreeCtrl.GetChildItem (parent_item);
			child_item != NULL;
			child_item = m_TreeCtrl.GetNextSiblingItem (child_item))
	{
		//
		//	If this tree item represents a definition factory, then save
		// a preset library for all presets of this class ID
		//
		DefinitionFactoryClass *factory = Get_Item_Factory (child_item);
		if (factory != NULL) {			
			Save_Global_Presets (factory->Get_Class_ID ());
		} else if (m_TreeCtrl.ItemHasChildren (child_item)) {
			
			//
			// Recursively call this method for all sub-folders in this tree
			//		
			Save_Preset_Libraries (child_item);
		}
	}

#endif //PUBLIC_EDITOR_VER
	
	return ;
}


/////////////////////////////////////////////////////////////////////////////
//
// Save_Presets
//
/////////////////////////////////////////////////////////////////////////////
bool
PresetsFormClass::Save_Presets
(
	LPCTSTR	path,
	uint32	class_id,
	bool		class_id_matters,
	bool		temps_only
)
{
	///
	// Delete the file if it already exists
	//
	if (::GetFileAttributes (path) != 0xFFFFFFFF) {
			DWORD attributes = ::GetFileAttributes (path);
		::SetFileAttributes (path, attributes & (~FILE_ATTRIBUTE_READONLY));
		::DeleteFile (path);
	}

	//
	//	Create the file at the specified location
	//
	HANDLE file		= ::CreateFile (	path,
												GENERIC_WRITE,
												0,
												NULL,
												CREATE_ALWAYS,
												0L,
												NULL);

	ASSERT (file != INVALID_HANDLE_VALUE);
	if (file != INVALID_HANDLE_VALUE) {
		
		//
		//	Now write the presets and definitions out to this file
		//
		Save_Presets (file, class_id, class_id_matters, temps_only);
			
	} else {
		
		//
		//	Warn the user
		//
		DWORD last_error = ::GetLastError ();
		CString message;		
		message.Format ("Unable to create database file.\nPath:%s\nError Code:%d", path, last_error);
		::MessageBox (::AfxGetMainWnd ()->m_hWnd, message, "File I/O Error", MB_ICONERROR | MB_OK);
	}

	return true;
}


/////////////////////////////////////////////////////////////////////////////
//
// Save_Presets
//
/////////////////////////////////////////////////////////////////////////////
bool
PresetsFormClass::Save_Presets (uint32 class_id, bool temps_only)
{
	//
	//	Build a filename for the presets library
	//
	CString path;
	::Get_File_Mgr ()->Get_Preset_Library_Path (class_id, temps_only, path);

	//
	//	Now save the presets to this file
	//
	return Save_Presets (path, class_id, !temps_only, temps_only);
}


/////////////////////////////////////////////////////////////////////////////
//
// Save_Presets
//
/////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Save_Presets (HANDLE file, uint32 class_id, bool class_id_matters, bool temps_only)
{
	//
	//	Create a chunk IO object that we can use to save our subsystems
	//
	RawFileClass file_obj;
	file_obj.Attach (file);
	ChunkSaveClass chunk_save (&file_obj);

	//
	//	Remove all the presets that don't match our criteria
	//
	PRESET_LIST preset_list;
	preset_list.Set_Growth_Step (2000);
	PresetMgrClass::Remove_Non_Matching_Presets (class_id, class_id_matters, temps_only, preset_list);

	//
	//	Turn saving off for all definitions
	//
	DefinitionClass *definition		= NULL;
	for (	definition = DefinitionMgrClass::Get_First ();
			definition != NULL;
			definition = DefinitionMgrClass::Get_Next (definition))
	{
		definition->Enable_Save (false);
	}

	//
	//	Now turn saving on for all definitions that are needed by
	// one of the presets.
	//
	DEFINITION_LIST defs_to_save;
	PresetClass *preset = NULL;
	for (	preset = PresetMgrClass::Get_First ();
			preset != NULL;
			preset = PresetMgrClass::Get_Next (preset))
	{
		//
		//	Build a list of definitions this preset depends on
		//
		DEFINITION_LIST curr_defs;
		preset->Collect_Definitions (curr_defs);

		//
		//	Turn saving on for all these definitions
		//
		for (int index = 0; index < curr_defs.Count (); index ++) {
			DefinitionClass *definition = curr_defs[index];
			if (definition != NULL) {
				definition->Enable_Save (true);
			}
		}
	}

	//
	//	The definition database consists of the definitions (global)
	//	and the presets (editor only).
	//
	SaveLoadSystemClass::Save (chunk_save, _TheDefinitionMgr);
	SaveLoadSystemClass::Save (chunk_save, _ThePresetMgr);

	//
	//	Turn saving back on for all definitions
	//
	for (	definition = DefinitionMgrClass::Get_First ();
			definition != NULL;
			definition = DefinitionMgrClass::Get_Next (definition))
	{
		definition->Enable_Save (true);
	}

	//
	//	Now add back all the presets we removed
	//
	PresetMgrClass::Put_Presets_Back (preset_list);
	return ;
}


/////////////////////////////////////////////////////////////////////////////
//
// Reselect_Item
//
/////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Reselect_Item (int id, bool is_factory)
{
	HTREEITEM tree_item = NULL;
	if (is_factory) {
		tree_item = Find_Factory (TVI_ROOT, id);
	} else {
		tree_item = Find_Preset (TVI_ROOT, id);
	}

	m_TreeCtrl.Select (tree_item, TVGN_FIRSTVISIBLE);
	m_TreeCtrl.SelectItem (tree_item);
	return ;
}


/////////////////////////////////////////////////////////////////////////////
//
// OnAddTemp
//
/////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnAddTemp (void)
{
	DefinitionFactoryClass *factory = Get_Selected_Factory ();
	if (factory != NULL) {

		if (Add_New_Preset (NULL, true) != NULL) {
			Save_Temp_Presets ();
		}
	}

	return ;
}


/////////////////////////////////////////////////////////////////////////////
//
// OnAdd
//
/////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnAdd (void)
{	
	DefinitionFactoryClass *factory = Get_Selected_Factory ();
	if (factory != NULL) {

		//
		//	Check out the definition database
		//
		SelectionCaptureClass sel_capture (this);
		bool undo_check_out = false;
		if (PresetMgrClass::Check_Out_Database (factory->Get_Class_ID (), &undo_check_out)) {
			sel_capture.Restore ();

			//
			//	Create a new preset
			//
			PresetClass *preset = Add_New_Preset (NULL);
			if (preset != NULL) {
				
				//
				//	Log creation
				//
				PresetLoggerClass::Log_Created (preset);

				//
				//	Register this new preset for check-in
				//
				Save_Global_Presets (factory->Get_Class_ID ());
				PresetMgrClass::Add_Dirty_Preset (preset->Get_ID ());				
			} else if (undo_check_out) {
				PresetMgrClass::Undo_Database_Check_Out (factory->Get_Class_ID ());
			}
		}
	}

	return ;
}


/////////////////////////////////////////////////////////////////////////////
//
// OnMake
//
/////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnMake (void)
{
	HTREEITEM current_item	= m_TreeCtrl.GetSelectedItem ();
	PresetClass *preset		= Get_Item_Preset (current_item);
	if (preset != NULL) {
		::Get_Scene_Editor ()->Create_Node (preset);

		//
		//	Repartition the scene if the user placed a terrain
		//
		if (preset->Get_Class_ID () == CLASSID_TERRAIN) {
			::Get_Scene_Editor ()->Re_Partition_Static_Projectors ();
			::Get_Scene_Editor ()->Re_Partition_Static_Lights ();
			::Get_Scene_Editor ()->Re_Partition_Static_Objects ();			
		}

		::Refresh_Main_View ();
	}

	return ;	
}


/////////////////////////////////////////////////////////////////////////////
//
// Add_New_Preset
//
/////////////////////////////////////////////////////////////////////////////
PresetClass *
PresetsFormClass::Add_New_Preset (LPCTSTR name, bool is_temp, bool sel_new)
{
	PresetClass *new_preset = NULL;

	DefinitionFactoryClass *factory = Get_Selected_Factory ();
	if (factory != NULL) {

		HTREEITEM current_item		= m_TreeCtrl.GetSelectedItem ();
		PresetClass *parent_preset	= Get_Item_Preset (current_item);

		//
		//	Create a new preset
		//
		new_preset = PresetMgrClass::Create_Preset (factory->Get_Class_ID (), name, is_temp);
		new_preset->Set_Parent (parent_preset);

		//
		//	Give the new preset its parent's values by default
		//
		if (parent_preset != NULL) {		
			new_preset->Copy_Properties (*parent_preset);
		}

		//
		//	Edit the preset's properties
		//
		if (name != NULL || new_preset->Show_Properties ()) {
			
			//
			//	Add this preset to the framework
			//
			HTREEITEM new_item = Insert_Preset (current_item, new_preset);
			PresetMgrClass::Add_Preset (new_preset);
			DefinitionMgrClass::Register_Definition (new_preset->Get_Definition ());

			if (parent_preset != NULL) {
				parent_preset->Add_Child_Preset (new_preset->Get_ID ());
			}

			//
			//	Select the new entry
			//
			if (sel_new) {
				m_TreeCtrl.Select (new_item, TVGN_FIRSTVISIBLE);
				m_TreeCtrl.SelectItem (new_item);				
			}
			m_TreeCtrl.SortChildren (current_item);
			m_TreeCtrl.InvalidateRect (NULL, TRUE);

		} else {			
			DefinitionClass *definition = new_preset->Get_Definition ();
			SAFE_DELETE (definition);
			SAFE_DELETE (new_preset);
		}
	}

	return new_preset;
}


/////////////////////////////////////////////////////////////////////////////
//
// OnDelete
//
/////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnDelete (void)
{
	HTREEITEM current_item	= m_TreeCtrl.GetSelectedItem ();
	PresetClass *preset		= Get_Item_Preset (current_item);
	if (preset != NULL) {

		//
		//	Make sure the user really wants to do this
		//
		if (::Message_Box (	m_hWnd,
									IDS_DELETE_PRESET_MSG,
									IDS_DELETE_PRESET_TITLE,
									MB_ICONQUESTION | MB_YESNO) == IDYES	)
		{
			CWaitCursor wait_cursor;

			//
			//	Check out the definition database (unless its a temp)
			//
			SelectionCaptureClass sel_capture (this);
			bool undo_on_err = false;
			bool was_temp = preset->Get_IsTemporary ();;
			if (was_temp || PresetMgrClass::Check_Out_Database (preset->Get_Class_ID (), &undo_on_err)) {
				sel_capture.Restore ();

				//
				//	Re-get the preset (its pointer has changed, the
				// old one is crap).
				//
				current_item	= m_TreeCtrl.GetSelectedItem ();
				preset			= Get_Item_Preset (current_item);
				if (preset != NULL) {

					//
					//	Log the delete operation
					//
					if (preset->Get_IsTemporary () == false) {
						PresetLoggerClass::Log_Deleted (preset->Get_Name ());
					}

					//
					//	Build a list of all the sub-items that are affected by this operation
					//
					DynamicVectorClass<HTREEITEM> tree_item_list;
					tree_item_list.Add (current_item);
					Build_Child_List (current_item, tree_item_list);

					//
					//	Determine what class-id's these presets belong to (they all belong
					// to the same class)
					//
					uint32 class_id = 0;
					DefinitionClass *definition = preset->Get_Definition ();
					if (definition != NULL) {
						class_id = definition->Get_Class_ID ();
					}
					
					//
					//	Free all the nodes in the scene that use any of these presets.
					// Also unregister the preset and its definition
					//
					bool save_temp_lib = was_temp;
					for (int index = 0; index < tree_item_list.Count (); index ++) {
						PresetClass *preset = Get_Item_Preset (tree_item_list[index]);
						if (preset != NULL) {
							::Get_Scene_Editor ()->Delete_Nodes (preset);
							PresetMgrClass::Remove_Preset (preset);													
							
							//
							//	Determine if we need to save the temporary preset
							// library later or not.
							//
							if (preset->Get_IsTemporary ()) {
								save_temp_lib = true;
							}

							//
							//	Unlink the definition
							//
							preset->Set_Definition (NULL);

							//
							//	Free the definition
							//
							DefinitionClass *definition = preset->Get_Definition ();
							if (definition != NULL) {
								DefinitionMgrClass::Unregister_Definition (definition);
								preset->Set_Definition (NULL);
								SAFE_DELETE (definition);
							}
							
							//
							//	Free the preset
							//
							SAFE_DELETE (preset);
						}
					}

					//
					//	Save the temporary presets library if necessary.
					//
					if (save_temp_lib) {
						Save_Temp_Presets ();
					}

					//
					//	Save the global presets library if necessary
					//
					if (was_temp == false) {
						Save_Global_Presets (class_id);

						if (PresetMgrClass::Get_Immediate_Check_In_Mode ()) {
							PresetMgrClass::Check_In_Presets ();
						} else {							
							PresetMgrClass::Set_Presets_Dirty ();
						}
					}

					m_TreeCtrl.DeleteItem (current_item);
					::Refresh_Main_View ();
				}
			}
		}
	}

	return ;	
}


////////////////////////////////////////////////////////////////////////////
//
//  Sort_Nodes
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Sort_Nodes (HTREEITEM root_item, bool recursive)
{
	for (	HTREEITEM tree_item = m_TreeCtrl.GetChildItem (root_item);
			tree_item != NULL;
			tree_item = m_TreeCtrl.GetNextSiblingItem (tree_item))
	{
		//
		//	Sort the children
		//
		m_TreeCtrl.SortChildren (tree_item);

		//
		//	Recurse through the hierarchy
		//
		if (recursive && m_TreeCtrl.ItemHasChildren (tree_item)) {
			Sort_Nodes (tree_item);
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Create_Preset
//
////////////////////////////////////////////////////////////////////////////
PresetClass *
PresetsFormClass::Create_Preset (DefinitionFactoryClass *factory, bool is_temp)
{
	//
	//	Create a new definition for the preset
	//
	DefinitionClass *definition = factory->Create ();

	//
	//	Assign the definition a new ID
	//
	if (is_temp) {		
		definition->Set_ID (::Get_Next_Temp_ID ());
	} else {
		definition->Set_ID (DefinitionMgrClass::Get_New_ID (definition->Get_Class_ID ()));
	}
	
	//
	//	Create the new preset
	//
	PresetClass *new_preset = new PresetClass;
	new_preset->Set_Definition (definition);	
	new_preset->Set_IsTemporary (is_temp);
	return new_preset;
}


////////////////////////////////////////////////////////////////////////////
//
//  Build_Child_List
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Build_Child_List
(
	HTREEITEM								parent_item,
	DynamicVectorClass<HTREEITEM> &	list
)
{
	//
	//	Loop over all the immediate children
	//
	for (	HTREEITEM child_item = m_TreeCtrl.GetChildItem (parent_item);
			child_item != NULL;
			child_item = m_TreeCtrl.GetNextSiblingItem (child_item))
	{
		list.Add (child_item);
		if (m_TreeCtrl.ItemHasChildren (child_item)) {
			
			//
			// Recursively call this method for all sub-folders in this tree
			//
			Build_Child_List (child_item, list);
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Enable_Button
//
////////////////////////////////////////////////////////////////////////////
bool
PresetsFormClass::Enable_Button (int cmd_id)
{
	bool retval = false;

	HTREEITEM current_item					= m_TreeCtrl.GetSelectedItem ();
	if (current_item != NULL) {
		PresetClass *preset					= Get_Item_Preset (current_item);
		DefinitionFactoryClass *factory	= Get_Item_Factory (current_item);
		bool read_only							= ::Get_File_Mgr()->Is_VSS_Read_Only ();
		bool temp								= (preset != NULL && preset->Get_IsTemporary ()) ? true : false;
		bool is_proxy_test_folder			= false;

		//
		//	Determine if this is the proxy-test folder or not (special rules
		// apply to this folder).
		//
		if (preset != NULL) {
			is_proxy_test_folder = preset->Is_A_Parent (PROXY_TESTS_FOLDER);
		}

		//
		//	Change the read_only state depending on the user class
		//
		if (read_only == false && ::Get_File_Mgr ()->Is_Special_User ()) {
			read_only = true;
			if (preset != NULL) {															
				if (preset->Is_A_Parent (SPECIAL_USER_FOLDER)) {
					read_only = false;

					//
					//	Don't let special users modify the folder itself (just sub-folders)
					//
					if (	::lstrcmpi (preset->Get_Name (), SPECIAL_USER_FOLDER) == 0 &&
							(cmd_id == IDC_MODIFY || cmd_id == IDC_DELETE))
					{
						read_only = true;
					}
				}
			}
		}

		//
		//	What operation is this?
		//
		switch (cmd_id)
		{
			case IDC_ADD:
				retval = ((preset || factory) && !read_only && !temp && !is_proxy_test_folder);
				break;

			case IDC_ADD_TEMP:
				retval = (preset || factory);
				break;

			case IDC_MAKE:
				retval = (preset != NULL);
				break;

			case IDC_MODIFY:
				retval = (preset && (!read_only || temp));
				break;

			case IDC_DELETE:
				retval = (preset && (!read_only || temp));
				break;

			case IDC_PLAY:
				retval = (preset != NULL && preset->Is_Valid_Sound_Preset ()) ? true : false;
				break;

			case IDC_UPDATE_VSS:
				retval = ((preset != NULL) && !read_only);
				break;				

			case IDC_INFO:
				retval = (preset != NULL);
				break;

			case IDC_CONVERT:
				retval = ((preset != NULL) && temp && !read_only && !is_proxy_test_folder);
				if (	preset != NULL &&
						preset->Get_Parent () != NULL &&
						preset->Get_Parent ()->Get_IsTemporary ())
				{
					retval = false;
				}
				break;

			case IDM_BATCH_IMPORT_TERRAIN:
			{
				if (preset != NULL && preset->Get_Class_ID () == CLASSID_TERRAIN) {
					retval = true;
				}
			}
			break;

			case IDM_CLEAR_EMBEDDED_NODE_LIST:
			{
				retval = (preset && (!read_only || temp));

				if (preset != NULL && preset->Get_Node_List ().Count () == 0) {
					retval = false;
				}
			}
			break;

			case IDM_UPDATE_EMBEDDED_NODE_LIST:
				retval = (preset && (!read_only || temp));

				//
				//	Only allow this option for terrain and tile presets
				//
				if (preset != NULL) {
					if (	preset->Get_Class_ID () != CLASSID_TERRAIN &&
							preset->Get_Class_ID () != CLASSID_TILE)
					{
						retval = false;
					}
				}

				break;
		}
	}

	return retval;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnSelchangedPresetsTree
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnSelchangedPresetsTree (NMHDR *pNMHDR, LRESULT *pResult)
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	(*pResult) = 0;

	//
	//	Enable/disable the toolbar buttons
	//
	m_Toolbar.Enable_Button (IDC_ADD,		Enable_Button (IDC_ADD));
	m_Toolbar.Enable_Button (IDC_ADD_TEMP,	Enable_Button (IDC_ADD_TEMP));
	m_Toolbar.Enable_Button (IDC_MAKE,		Enable_Button (IDC_MAKE));
	m_Toolbar.Enable_Button (IDC_MODIFY,	Enable_Button (IDC_MODIFY));
	m_Toolbar.Enable_Button (IDC_DELETE,	Enable_Button (IDC_DELETE));
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Propagate_Changes
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Propagate_Changes
(
	HTREEITEM				modified_item,
	DERIVED_PARAM_LIST &	list
)
{
	CWaitCursor wait_cursor;
	CLevelEditView::Allow_Repaint (false);

	PresetClass *preset				= Get_Item_Preset (modified_item);
	DefinitionClass *definition	= preset->Get_Definition ();

	//
	//	Loop over the list of derived parameters that need to
	// be updated with the new values.
	//
	for (int index = 0; index < list.Count (); index ++) {
		DERIVED_PARAM_INFO &info			= list[index];

		//
		//	Copy all the inherited parameter values from the parent preset
		//
		int list_count = info.base_param_list.Count ();
		for (int list_index = 0; list_index < list_count; list_index ++) {
			//int param_index						= info.inherited_param_list[list_index];

			ParameterClass *parameter			= info.base_param_list[list_index];
			ParameterClass *curr_parameter	= info.derived_param_list[list_index];
			ASSERT (parameter != NULL);
			ASSERT (curr_parameter != NULL);

			//
			//	Copy the parameter value from the parent.
			//
			curr_parameter->Copy_Value (*parameter);

			//
			//	Release the parameter pointers
			//
			//definition->Unlock_Parameter (param_index);
			//curr_definition->Unlock_Parameter (param_index);
		}

		//
		//	Now reload any nodes in the scene that refer to the
		// changed preset.
		//
		if (info.preset != NULL) {
			NodeMgrClass::Reload_Nodes (info.preset);
		}
	}

	//
	//	Now reload any nodes in the scene that refer to the
	// changed preset.
	//
	NodeMgrClass::Reload_Nodes (preset);
	CLevelEditView::Allow_Repaint (true);
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Compare_Derived_Parameters
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Compare_Derived_Parameters
(
	PresetClass *			curr_preset,
	DefinitionClass *		base_def,
	DefinitionClass *		derived_def,
	DERIVED_PARAM_LIST &	list
)
{
	DERIVED_PARAM_INFO info;
	info.preset = curr_preset;
		
	//
	//	Compare all the parameters with this derived definition to
	// find any that are not overridden.
	//
	int param_count = base_def->Get_Parameter_Count ();
	for (int param_index = 0; param_index < param_count; param_index ++) {
		ParameterClass *parameter			= base_def->Lock_Parameter (param_index);
		ParameterClass *curr_parameter	= derived_def->Lock_Parameter (param_index);
		ASSERT (parameter != NULL);
		ASSERT (curr_parameter != NULL);

		//
		//	If the parameter values are exactly the same, then
		// we will assume this parameter is derived and not overridden
		//
		if (*curr_parameter == *parameter) {
			info.base_param_list.Add (parameter);
			info.derived_param_list.Add (curr_parameter);
		} else if (parameter->Get_Type () == ParameterClass::TYPE_MODELDEFINITIONID) {
			
			//
			//	Lookup the definitions that these parameters reference
			//
			int base_id		= ((ModelDefParameterClass *)parameter)->Get_Value ();
			int derived_id = ((ModelDefParameterClass *)curr_parameter)->Get_Value ();
			DefinitionClass *base_model_def		= DefinitionMgrClass::Find_Definition (base_id, false);
			DefinitionClass *derived_model_def	= DefinitionMgrClass::Find_Definition (derived_id, false);

			//
			//	Recursively add parameters from these definitions to the list
			//
			if (	base_model_def != NULL && derived_model_def != NULL &&
					base_model_def->Get_Class_ID () == derived_model_def->Get_Class_ID ())
			{
				Compare_Derived_Parameters (NULL, base_model_def, derived_model_def, list);
			}
		}

		//
		//	Release the parameter pointers
		//
		base_def->Unlock_Parameter (param_index);
		derived_def->Unlock_Parameter (param_index);
	}

	//
	//	If this preset contains at least one derived (not overridden) value,
	// then add it to the list.
	//
	if (info.base_param_list.Count () > 0) {
		list.Add (info);
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Build_Inherited_Param_List
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Build_Inherited_Param_List
(
	HTREEITEM				parent_item,
	DERIVED_PARAM_LIST &	list
)
{
	PresetClass *preset				= Get_Item_Preset (parent_item);
	DefinitionClass *definition	= preset->Get_Definition ();

	//
	//	Build a list of children (derived presets)
	//
	DynamicVectorClass<HTREEITEM> child_list;	
	Build_Child_List (parent_item, child_list);

	//
	//	Loop over all the derived presets and build up the list
	// of non-overridden parameter values
	//
	for (int index = 0; index < child_list.Count (); index ++) {
		HTREEITEM tree_item = child_list[index];

		PresetClass *curr_preset			= Get_Item_Preset (tree_item);
		DefinitionClass *curr_definition	= curr_preset->Get_Definition ();
		ASSERT (curr_definition->Get_Class_ID () == definition->Get_Class_ID ());

		//
		//	Build the list of parameters that are the same as the base
		//
		Compare_Derived_Parameters (curr_preset, definition, curr_definition, list);
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnPlay
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnPlay (void)
{
	HTREEITEM tree_item = m_TreeCtrl.GetSelectedItem ();
	PresetClass *preset = Get_Item_Preset (tree_item);
	if (preset != NULL && preset->Get_Definition () != NULL) {

		AudibleSoundDefinitionClass *definition = NULL;
		definition = (AudibleSoundDefinitionClass *)preset->Get_Definition ();

		//
		//	Make sure we have a local copy of this sound
		//
		CString filename = definition->Get_Filename ();
		if (::Get_File_Mgr ()->Does_File_Exist (filename, true)) {
		
			//
			//	Pass the sound filename onto the dialog
			//
			PlaySoundDialogClass dialog (filename, this);
			dialog.DoModal ();
		}
	}
	
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnInfo
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnInfo (void)
{
	HTREEITEM current_item	= m_TreeCtrl.GetSelectedItem ();
	PresetClass *preset		= Get_Item_Preset (current_item);
	if (preset != NULL) {

		//
		//	Show the (read-only) properties dialog for this preset
		//
		preset->Show_Properties (true);
	}
	
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnExtra
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnExtra (void) 
{
	//
	//	Determine the screen coords of the toolbar button
	//
	CRect rect;
	m_Toolbar.GetItemRect (m_Toolbar.CommandToIndex (IDC_EXTRA), &rect);
	m_Toolbar.ClientToScreen (&rect);

	//
	//	Load the menu we want to display
	//
	HMENU main_menu = ::LoadMenu (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDR_XTRA_POPUP));
	HMENU menu = ::GetSubMenu (main_menu, 0);

	//
	//	Make the menu commands owner-draw so we can paint icons next to them
	//
	::ModifyMenu (menu, IDC_PLAY, MF_BYCOMMAND | MF_OWNERDRAW, IDC_PLAY, NULL);
	::ModifyMenu (menu, IDC_CONVERT, MF_BYCOMMAND | MF_OWNERDRAW, IDC_CONVERT, NULL);
	::ModifyMenu (menu, IDC_UPDATE_VSS, MF_BYCOMMAND | MF_OWNERDRAW, IDC_UPDATE_VSS, NULL);
	::ModifyMenu (menu, IDM_BATCH_IMPORT_TERRAIN, MF_BYCOMMAND | MF_OWNERDRAW, IDM_BATCH_IMPORT_TERRAIN, NULL);
	::ModifyMenu (menu, IDM_UPDATE_EMBEDDED_NODE_LIST, MF_BYCOMMAND | MF_OWNERDRAW, IDM_UPDATE_EMBEDDED_NODE_LIST, NULL);	
	::ModifyMenu (menu, IDM_CLEAR_EMBEDDED_NODE_LIST, MF_BYCOMMAND | MF_OWNERDRAW, IDM_CLEAR_EMBEDDED_NODE_LIST, NULL);		
	
	//
	//	Disable any buttons if necessary
	//
	if (Enable_Button (IDC_PLAY) == false) {
		::EnableMenuItem (menu, IDC_PLAY, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
	}

	if (Enable_Button (IDC_CONVERT) == false) {
		::EnableMenuItem (menu, IDC_CONVERT, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
	}

	if (Enable_Button (IDC_UPDATE_VSS) == false) {
		::EnableMenuItem (menu, IDC_UPDATE_VSS, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
	}

	if (Enable_Button (IDM_BATCH_IMPORT_TERRAIN) == false) {
		::EnableMenuItem (menu, IDM_BATCH_IMPORT_TERRAIN, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
	}

	if (Enable_Button (IDM_UPDATE_EMBEDDED_NODE_LIST) == false) {
		::EnableMenuItem (menu, IDM_UPDATE_EMBEDDED_NODE_LIST, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
	}

	if (Enable_Button (IDM_CLEAR_EMBEDDED_NODE_LIST) == false) {
		::EnableMenuItem (menu, IDM_CLEAR_EMBEDDED_NODE_LIST, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
	}	

	//
	//	Display the menu
	//
	::TrackPopupMenu (menu, TPM_LEFTALIGN | TPM_TOPALIGN, rect.left, rect.bottom, 0, m_hWnd, NULL);	

	//
	//	Cleanup
	//
	::DestroyMenu (main_menu);
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnNotify
//
////////////////////////////////////////////////////////////////////////////
BOOL
PresetsFormClass::OnNotify
(
	WPARAM wParam,
	LPARAM lParam,
	LRESULT* pResult
) 
{
	if (((NMHDR *)lParam)->code == TBN_DROPDOWN) {

		OnExtra ();
		(*pResult) = TBDDRET_DEFAULT;
		return TRUE;
	}
	
	return CDialog::OnNotify(wParam, lParam, pResult);
}


////////////////////////////////////////////////////////////////////////////
//
//  OnUpdateConvert
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnUpdateConvert (CCmdUI *pCmdUI) 
{
	pCmdUI->Enable (Enable_Button (IDC_CONVERT));
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnUpdateInfo
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnUpdateInfo (CCmdUI *pCmdUI)
{
	pCmdUI->Enable (Enable_Button (IDC_INFO));
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnUpdatePlay
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnUpdatePlay (CCmdUI *pCmdUI)
{
	pCmdUI->Enable (Enable_Button (IDC_PLAY));
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnUpdateUpdateVss
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnUpdateUpdateVss (CCmdUI *pCmdUI)
{
	pCmdUI->Enable (Enable_Button (IDC_UPDATE_VSS));
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Get_Menu_Text
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Get_Menu_Text (int menu_id, CString &text)
{
	switch (menu_id)
	{
		case IDC_PLAY:
			text = "Play...";
			break;

		case IDC_CONVERT:
			text = "Convert Temp...";
			break;

		case IDC_UPDATE_VSS:
			text = "Update VSS...";
			break;

		case IDM_BATCH_IMPORT_TERRAIN:
			text = "Batch Import Terrain...";
			break;
					
		case IDM_CLEAR_EMBEDDED_NODE_LIST:
			text = "Clear Embedded Node List";
			break;

		case IDM_UPDATE_EMBEDDED_NODE_LIST:
			text = "Embed Nodes...";
			break;
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnDrawItem
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnDrawItem
(
	int					nIDCtl,
	LPDRAWITEMSTRUCT	lpDrawItemStruct
) 
{
	HICON icon = NULL;

	CString text;
	Get_Menu_Text (lpDrawItemStruct->itemID, text);

	switch (lpDrawItemStruct->itemID)
	{
		case IDC_PLAY:
			icon = (HICON)::LoadImage (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDI_PLAY), IMAGE_ICON, 16, 16, LR_SHARED);
			break;

		case IDC_CONVERT:
			icon = (HICON)::LoadImage (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDI_CONVERT), IMAGE_ICON, 16, 16, LR_SHARED);
			break;

		case IDC_UPDATE_VSS:
			icon = (HICON)::LoadImage (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDI_UPDATE), IMAGE_ICON, 16, 16, LR_SHARED);
			break;

		case IDM_BATCH_IMPORT_TERRAIN:
			icon = (HICON)::LoadImage (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDI_TERRAIN), IMAGE_ICON, 16, 16, LR_SHARED);
			break;

		case IDM_UPDATE_EMBEDDED_NODE_LIST:
			icon = (HICON)::LoadImage (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDI_OBJECT), IMAGE_ICON, 16, 16, LR_SHARED);
			break;

		case IDM_CLEAR_EMBEDDED_NODE_LIST:
			icon = (HICON)::LoadImage (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDI_DELETE), IMAGE_ICON, 16, 16, LR_SHARED);
			break;			
	}

	CRect rect = lpDrawItemStruct->rcItem;

	int dss_state = DSS_NORMAL;
	UINT bk_color = 0;
		
	//
	//	Deteremine what background and text color to use
	//
	if (lpDrawItemStruct->itemState & ODS_GRAYED) {
		bk_color = COLOR_MENU;
		::SetBkColor (lpDrawItemStruct->hDC, ::GetSysColor (COLOR_MENU));
		::SetTextColor (lpDrawItemStruct->hDC, ::GetSysColor (COLOR_GRAYTEXT));
		dss_state = DSS_DISABLED;
	} else if (lpDrawItemStruct->itemState & ODS_SELECTED) {
		bk_color = COLOR_HIGHLIGHT;
		::SetBkColor (lpDrawItemStruct->hDC, ::GetSysColor (COLOR_HIGHLIGHT));
		::SetTextColor (lpDrawItemStruct->hDC, ::GetSysColor (COLOR_HIGHLIGHTTEXT));
	} else {
		bk_color = COLOR_MENU;
		::SetBkColor (lpDrawItemStruct->hDC, ::GetSysColor (COLOR_MENU));
		::SetTextColor (lpDrawItemStruct->hDC, ::GetSysColor (COLOR_MENUTEXT));
	}

	//
	//	Determine the height of the text
	//
	CSize text_size;
	::GetTextExtentPoint32 (lpDrawItemStruct->hDC, text, text.GetLength (), &text_size);
	
	//
	//	Render the text
	//
	rect.top += 2;
	rect.bottom -= 2;
	::FillRect (lpDrawItemStruct->hDC, &rect, (HBRUSH) (bk_color+1));

	::SetBkMode (lpDrawItemStruct->hDC, TRANSPARENT);
	::DrawState (	lpDrawItemStruct->hDC,
						NULL,
						NULL,
						(LPARAM)(LPCTSTR)text,
						0,
						rect.left + 24,
						rect.top + (rect.Height () >> 1) - (text_size.cy >> 1),
						0, 0, DST_TEXT | dss_state);

	//
	//	Draw the associated icon (if necessary)
	//
	if (icon != NULL) {
		::DrawState ( lpDrawItemStruct->hDC, NULL, NULL, (LPARAM)icon, 0, rect.left + 4, rect.top + 4, 16, 16, DST_ICON | dss_state);
	}	

	
	CDialog::OnDrawItem (nIDCtl, lpDrawItemStruct);
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnMeasureItem
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnMeasureItem
(
	int						nIDCtl,
	LPMEASUREITEMSTRUCT	lpMeasureItemStruct
) 
{
	CString text;
	Get_Menu_Text (lpMeasureItemStruct->itemID, text);

	NONCLIENTMETRICS metrics = { sizeof (NONCLIENTMETRICS), 0 };
	::SystemParametersInfo (SPI_GETNONCLIENTMETRICS, 0, &metrics, FALSE);
	
	HDC mem_dc = ::CreateCompatibleDC (NULL);	
	HFONT font = ::CreateFontIndirect (&metrics.lfMenuFont);
	HFONT old_font = (HFONT)::SelectObject (mem_dc, font);

	CSize text_size;
	::GetTextExtentPoint32 (mem_dc, text, text.GetLength (), &text_size);
	
	::SelectObject (mem_dc, old_font);
	::DeleteObject (font);
	::DeleteDC (mem_dc);

	lpMeasureItemStruct->itemWidth = text_size.cx + 24;
	lpMeasureItemStruct->itemHeight = 24;
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnConvert
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnConvert (void)
{
	HTREEITEM item = m_TreeCtrl.GetSelectedItem ();
	PresetClass *preset = Get_Item_Preset (item);
	if (preset != NULL) {

		//
		//	Make sure the user really wants to do this...
		//
		CString message;
		message.Format ("Are you sure you wish to convert '%s' from a temporary preset to a shared preset?", preset->Get_Name ());
		if (MessageBox (message, "Preset Convert", MB_ICONQUESTION | MB_YESNO) == IDYES) {
			CWaitCursor wait_cursor;

			//
			//	Check out the definition database
			//
			SelectionCaptureClass sel_capture (this);
			bool undo_check_out	= false;
			uint32 class_id		= preset->Get_Class_ID ();
			if (PresetMgrClass::Check_Out_Database (class_id, &undo_check_out)) {
				sel_capture.Restore ();

				item = m_TreeCtrl.GetSelectedItem ();
				PresetClass *preset = Get_Item_Preset (item);
				if (preset != NULL) {

					//
					//	Change the preset's ID from temp-range to normal-range
					//
					preset->Set_IsTemporary (false);
					preset->Set_ID (DefinitionMgrClass::Get_New_ID (preset->Get_Class_ID ()));

					//
					//	Now change the IDs of any embedded definition objects
					//
					Fix_Embedded_Definition_IDs (preset->Get_Definition ());

					//
					//	Now save-out the databases (they have both changed)
					//
					Save_Global_Presets (class_id);
					PresetMgrClass::Add_Dirty_Preset (preset->Get_ID ());					
					Save_Temp_Presets ();

					//
					//	Finally change the preset's icon
					//
					int icon = Get_Icon (preset);
					m_TreeCtrl.SetItemImage (item, icon, icon);

					//
					//	Force a re-paint
					//
					m_TreeCtrl.SelectItem (item);
					m_TreeCtrl.InvalidateRect (NULL, TRUE);
				} else if (undo_check_out) {
					MessageBox ("Unable to find preset.", "Preset Error", MB_ICONERROR | MB_OK);
					PresetMgrClass::Undo_Database_Check_Out (class_id);
				}
			}
		}
	}
	
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnUpdateVss
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnUpdateVss (void)
{
	HTREEITEM item = m_TreeCtrl.GetSelectedItem ();
	PresetClass *preset = Get_Item_Preset (item);
	if (preset != NULL) {

		//
		//	Show the update-preset dialog
		//
		UpdatePresetDialogClass dialog (preset, this);
		dialog.DoModal ();
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnClearEmbeddedNodeList
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnClearEmbeddedNodeList (void)
{
	CWaitCursor wait_cursor;

	//
	//	Get the currently selected preset
	//
	HTREEITEM current_item	= m_TreeCtrl.GetSelectedItem ();
	PresetClass *preset		= Get_Item_Preset (current_item);
	if (preset != NULL) {

		if (preset->Get_IsTemporary () == false) {

			//
			//	Check out the definition database
			//
			SelectionCaptureClass sel_capture (this);
			bool undo_on_err	= false;
			uint32 class_id	= preset->Get_Class_ID ();
			if (PresetMgrClass::Check_Out_Database (class_id, &undo_on_err)) {
				sel_capture.Restore ();

				//
				//	Re-get the preset (its pointer has changed, the
				// old one is crap).
				//
				current_item	= m_TreeCtrl.GetSelectedItem ();
				preset			= Get_Item_Preset (current_item);
				
				//
				//	Now, free the embedded nodes
				//
				if (preset != NULL) {
					preset->Free_Node_List ();
					Save_Global_Presets (preset->Get_Class_ID ());
					PresetMgrClass::Add_Dirty_Preset (preset->Get_ID ());
				}
			}

		} else {
			
			//
			//	Free the embedded nodes
			//
			preset->Free_Node_List ();
			Save_Temp_Presets ();				
		}

		Reset_Embedded_Node_Instances (preset);
		NodeMgrClass::Reload_Nodes (preset);

		if (preset != NULL) {

			//
			//	Update the overlay icon on the preset
			//
			bool needs_overlay = (preset->Get_Node_List ().Count () > 0);
			TreeView_SetOverlay (m_TreeCtrl, current_item, needs_overlay);
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Reset_Embedded_Node_Instances
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Reset_Embedded_Node_Instances (PresetClass *preset)
{
	if (preset == NULL) {
		return ;
	}

	//
	//	Loop over all the nodes in the scene
	//
	for (	NodeClass *node = NodeMgrClass::Get_First ();
			node != NULL;
			node = NodeMgrClass::Get_Next (node))
	{
		//
		//	If this was an embedded node, then convert it to
		// a "normal" node.
		//
		if (node->Get_Container_Preset_ID () == preset->Get_ID ()) {
			node->Set_Is_Proxied (false);
			node->Set_Needs_Save (true);
			node->Set_Container_Preset_ID (0);
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnBuildEmbedNodeList
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnBuildEmbedNodeList (void)
{
	//
	//	Prompt the user
	//
	if (::MessageBox (m_hWnd,
				"This operation will embed a copy of all the nodes in scene into this preset.  Are you sure you wish to continue?",
				"Embed Nodes", MB_ICONQUESTION | MB_YESNO) == IDNO)
	{
		return ;
	}

	CWaitCursor wait_cursor;

	//
	//	Get the currently selected preset
	//
	HTREEITEM current_item	= m_TreeCtrl.GetSelectedItem ();
	PresetClass *preset		= Get_Item_Preset (current_item);
	if (preset != NULL) {

		if (preset->Get_IsTemporary () == false) {

			//
			//	Check out the definition database
			//
			SelectionCaptureClass sel_capture (this);
			bool undo_on_err	= false;
			uint32 class_id	= preset->Get_Class_ID ();
			if (PresetMgrClass::Check_Out_Database (class_id, &undo_on_err)) {
				sel_capture.Restore ();

				//
				//	Re-get the preset (its pointer has changed, the
				// old one is crap).
				//
				current_item	= m_TreeCtrl.GetSelectedItem ();
				preset			= Get_Item_Preset (current_item);
				
				//
				//	Now, update the embedded node information for this preset
				//
				if (preset != NULL) {
					Update_Embedded_Nodes (preset);
					Save_Global_Presets (preset->Get_Class_ID ());
					PresetMgrClass::Add_Dirty_Preset (preset->Get_ID ());						
				}
			}

		} else {
			
			//
			//	Update the embedded node information for this preset
			//
			Update_Embedded_Nodes (preset);
			Save_Temp_Presets ();				
		}

		NodeMgrClass::Reload_Nodes (preset);

		//
		//	Update the overlay icon on the preset
		//
		if (preset != NULL) {
			bool needs_overlay = (preset->Get_Node_List ().Count () > 0);
			TreeView_SetOverlay (m_TreeCtrl, current_item, needs_overlay);
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Update_Embedded_Nodes
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Update_Embedded_Nodes (PresetClass *preset)
{
	Reset_Embedded_Node_Instances (preset);

	//
	//	Loop over all the nodes in the scene
	//
	for (	NodeClass *node = NodeMgrClass::Get_First ();
			node != NULL;
			node = NodeMgrClass::Get_Next (node))
	{
		//
		//	Just find the first node that came from this preset
		//
		if (node->Get_Preset () == preset) {
			break;
		}
	}

	//
	//	Generate the node list
	//
	if (node != NULL) {
		preset->Build_Node_List (node);
	}
		
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnBatchImportTerrain
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnBatchImportTerrain (void)
{
	CFileDialog dialog (	TRUE,
								".w3d",
								NULL,
								OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_ALLOWMULTISELECT | OFN_EXPLORER,
								"Westwood 3D Files (*.w3d)|*.w3d||",
								this);

	TCHAR filename_list[MAX_PATH*20] = { 0 };
	dialog.m_ofn.lpstrFile = filename_list;
	dialog.m_ofn.nMaxFile = sizeof (filename_list);

	//
	// Ask the user what files they wish to import
	//
	if (dialog.DoModal () == IDOK) {

      //
		// Loop through all the selected files
		//
		POSITION pos = dialog.GetStartPosition (); 
		while (pos != NULL) {

			//
			//	Add this preset to the tree
			//
			Add_Terrain_Preset (dialog.GetNextPathName (pos));
      }

		//
		//	Save the temp presets lib
		//
		Save_Temp_Presets ();
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnUpdateClearEmbeddedNodeList
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnUpdateClearEmbeddedNodeList (CCmdUI *pCmdUI)
{
	pCmdUI->Enable (Enable_Button (IDM_CLEAR_EMBEDDED_NODE_LIST));
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnUpdateEmbeddedNodeList
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnUpdateEmbeddedNodeList (CCmdUI *pCmdUI)
{
	pCmdUI->Enable (Enable_Button (IDM_UPDATE_EMBEDDED_NODE_LIST));
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnUpdateBatchImportTerrain
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnUpdateBatchImportTerrain (CCmdUI *pCmdUI)
{
	pCmdUI->Enable (Enable_Button (IDM_BATCH_IMPORT_TERRAIN));
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Add_Terrain_Preset
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Add_Terrain_Preset (LPCTSTR filename)
{
	if (::Is_W3D_Filename (filename)) {

		//
		//	Make an asset name from the filename
		//
		CString preset_name = ::Asset_Name_From_Filename (filename);
		if (preset_name.GetLength () > 0) {
			
			//
			//	Add the new preset
			//
			PresetClass *preset = Add_New_Preset (preset_name, true, false);
			if (preset != NULL && preset->Get_Class_ID () == CLASSID_TERRAIN) {
				
				//
				//	Configure the preset
				//
				TerrainDefinitionClass *definition = (TerrainDefinitionClass *)preset->Get_Definition ();
				definition->Set_Model_Name (::Get_File_Mgr ()->Make_Relative_Path (filename));
			}
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnBegindragPresetsTree
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnBegindragPresetsTree
(
	NMHDR *	pNMHDR,
	LRESULT *pResult
)
{
	NM_TREEVIEW *tv_info = (NM_TREEVIEW *)pNMHDR;
	(*pResult) = 0;

	if (Is_Drag_OK (tv_info->itemNew.hItem)) {
		
		//
		//	Set-up for our drag operation
		//
		m_DragItem = tv_info->itemNew.hItem;
		if (m_DragItem != NULL) {
			
			m_DragImageList = m_TreeCtrl.CreateDragImage (m_DragItem);
			m_DragImageList->BeginDrag (0, CPoint (-20, -20));			
			m_IsDragging = true;
			SetCapture ();
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnLButtonUp
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnLButtonUp (UINT nFlags, CPoint point) 
{
	if (m_IsDragging) {

		//
		//	Convert the tab mouse-position to the tree's mouse-position
		//
		CPoint tree_pt = point;
		ClientToScreen (&tree_pt);
		m_TreeCtrl.ScreenToClient (&tree_pt);
				
		//
		//	Reset the state of the tree
		//
		CImageList::EndDrag ();
		ReleaseCapture ();
		m_TreeCtrl.SelectDropTarget (NULL);
		m_TreeCtrl.SelectItem (m_DragItem);		

		//
		//	Check to ensure its OK to move the preset
		//
		UINT flags					= TVHT_ONITEM;
		HTREEITEM drop_target	= m_TreeCtrl.HitTest (tree_pt, &flags);
		if (Is_Drop_OK (drop_target)) {
			
			//
			//	Perform the move operation
			//
			m_TreeCtrl.SelectItem (drop_target);
			Do_Drop (m_DragItem, drop_target);
		}

		m_DragItem		= NULL;
		m_IsDragging	= false;
	}

	CDialog::OnLButtonUp (nFlags, point);
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnMouseMove
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnMouseMove (UINT nFlags, CPoint point) 
{
	if (m_IsDragging) {
		
		//
		//	Convert the tab mouse-position to the tree's mouse-position
		//
		CPoint tree_pt = point;
		ClientToScreen (&tree_pt);
		m_TreeCtrl.ScreenToClient (&tree_pt);
	
		//
		//	Draw the outline of the drag operation
		//
		CImageList::DragMove (tree_pt);
		m_DragImageList->DragLeave (&m_TreeCtrl);

		//
		//	Determine if we should hilight one of the entries in the tree control
		//
		UINT flags					= TVHT_ONITEM;
		HTREEITEM drop_target	= m_TreeCtrl.HitTest (tree_pt, &flags);
		if (drop_target != NULL) {
			m_TreeCtrl.SelectDropTarget (drop_target);
		}

		m_DragImageList->DragEnter (&m_TreeCtrl, tree_pt);

		//
		//	Choose a cursor
		//
		if (drop_target == NULL || Is_Drop_OK (drop_target) == false) {
			SetCursor (::LoadCursor (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDC_NODROP)));
		} else {
			SetCursor (::LoadCursor (NULL, IDC_ARROW));
		}
	}
		
	CDialog::OnMouseMove (nFlags, point);
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Is_Drag_OK
//
////////////////////////////////////////////////////////////////////////////
bool
PresetsFormClass::Is_Drag_OK (HTREEITEM drag_item)
{
	bool retval = false;

	PresetClass *preset	= Get_Item_Preset (drag_item);
	bool read_only			= ::Get_File_Mgr()->Is_VSS_Read_Only ();
	bool temp				= (preset != NULL && preset->Get_IsTemporary ()) ? true : false;

	//
	//	We allow the user to drag a preset if its a temp or they have write
	// access to the database.
	//
	if (preset != NULL && (read_only == false || temp == true)) {
		retval = true;
	}

	return retval;
}


////////////////////////////////////////////////////////////////////////////
//
//  Is_Drop_OK
//
////////////////////////////////////////////////////////////////////////////
bool
PresetsFormClass::Is_Drop_OK (HTREEITEM drop_item)
{
	bool retval = false;

	if (m_DragItem != NULL && drop_item != NULL) {
		
		PresetClass *drag_preset			= Get_Item_Preset (m_DragItem);
		PresetClass *drop_preset			= Get_Item_Preset (drop_item);
		DefinitionFactoryClass *factory	= Get_Item_Factory (drop_item);
		if (drag_preset != NULL && (drop_preset != NULL || factory != NULL)) {

			//
			//	Check to make sure we don't try to move a preset to one of its children
			//
			if (drop_preset == NULL || drop_preset->Is_A_Parent (drag_preset) == false) {

				//
				//	Get information about what 'type' of presets these are
				//
				int drag_classid = drag_preset->Get_Class_ID ();
				int drop_classid = 0;
				if (drop_preset != NULL) {
					drop_classid = drop_preset->Get_Class_ID ();
				} else {
					drop_classid = factory->Get_Class_ID ();
				}

				//
				//	Are the preset's factories the same?
				//
				if (drag_classid == drop_classid) {

					bool is_drop_temp	= (drop_preset != NULL && drop_preset->Get_IsTemporary ()) ? true : false;
					bool is_drag_temp	= (drag_preset != NULL && drag_preset->Get_IsTemporary ()) ? true : false;

					//
					//	We allow the drop if the target is a factory, or both the drag and drops are non-temp
					//
					if (factory != NULL || is_drag_temp || is_drop_temp == false) {					
						retval = true;
					}
				}
			}
		}
	}

	return retval;
}


////////////////////////////////////////////////////////////////////////////
//
//  Do_Drop
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Do_Drop (HTREEITEM drag_item, HTREEITEM drop_item)
{
	CWaitCursor wait_cursor;

	PresetClass *drag_preset = Get_Item_Preset (drag_item);
	bool is_drag_temp	= (drag_preset != NULL && drag_preset->Get_IsTemporary ()) ? true : false;

	//
	//	Does this operation affect only shared presets or only temps?
	//
	if (is_drag_temp == false) {
		uint32 drag_preset_id = drag_preset->Get_Definition ()->Get_ID ();

		//
		//	Check out the definition database
		//
		SelectionCaptureClass sel_capture (this);
		bool undo_on_err	= false;
		uint32 class_id	= drag_preset->Get_Class_ID ();
		if (PresetMgrClass::Check_Out_Database (class_id, &undo_on_err)) {
			sel_capture.Restore ();

			//
			//	Look-up the preset tree items
			//
			drag_item = Find_Preset (TVI_ROOT, drag_preset_id);
			drop_item = m_TreeCtrl.GetSelectedItem ();
			drag_preset = Get_Item_Preset (drag_item);

			//
			//	Are the drag and drop locations still valid?
			//
			if (	drag_preset != NULL &&
					drag_preset->Get_Definition ()->Get_ID () == drag_preset_id &&
					drag_item != NULL && drop_item != NULL && drag_item != drop_item)
			{				
				//
				//	Perform the operation and save the presets...
				//
				Move_Preset (drag_item, drop_item);	
				Save_Global_Presets (class_id);
				PresetMgrClass::Add_Dirty_Preset (drag_preset->Get_ID ());				

			} else {
				
				//
				//	Inform the user that something has changed...
				//
				::MessageBox (	NULL,
									"Either the drag source or the drop target no longer exists, please try again.",
									"Drag/Drop Error",
									MB_OK | MB_ICONERROR);

				if (undo_on_err) {
					PresetMgrClass::Undo_Database_Check_Out (class_id);
				}
			}
		}

	} else {
		
		//
		//	Simply move the preset and save the temp library
		//
		Move_Preset (drag_item, drop_item);
		if (drag_preset != NULL) {
			Save_Temp_Presets ();
		}
	}
	
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Move_Preset
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Move_Preset (HTREEITEM preset_item, HTREEITEM parent_item)
{
	ASSERT (preset_item != NULL);
	ASSERT (parent_item != NULL);

	PresetClass *preset = Get_Item_Preset (preset_item);
	if (preset != NULL) {
		
		//
		//	Let the preset know who its new parent is
		//
		PresetClass *parent_preset	= Get_Item_Preset (parent_item);
		preset->Set_Parent (parent_preset);
		if (parent_preset != NULL) {
			parent_preset->Add_Child_Preset (preset->Get_ID ());
		}

		//
		//	Make a log entry about the new parent
		//
		if (preset->Get_IsTemporary () == false) {

			//
			//	Get the name of the new parent
			//
			const char *parent_name = NULL;
			if (parent_preset != NULL) {
				parent_name = parent_preset->Get_Name ();
			}

			//
			//	Log the operation
			//
			PresetLoggerClass::Log_Moved (preset, parent_name);
		}

		//
		//	Move the tree item (and all its children)
		//
		m_TreeCtrl.SetRedraw (false);
		Copy_Preset_Items (preset_item, parent_item);
		m_TreeCtrl.DeleteItem (preset_item);
		m_TreeCtrl.SetRedraw (true);
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Copy_Preset_Items
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Copy_Preset_Items (HTREEITEM preset_item, HTREEITEM parent_item)
{
	//
	//	Copy the preset to its new parent
	//
	PresetClass *preset = Get_Item_Preset (preset_item);
	HTREEITEM new_item = Insert_Preset (parent_item, preset);

	//
	//	Recursive copy all child items
	//
	for (	HTREEITEM child_item = m_TreeCtrl.GetChildItem (preset_item);
			child_item != NULL;
			child_item = m_TreeCtrl.GetNextSiblingItem (child_item))
	{
		Copy_Preset_Items (child_item, new_item);
	}

	// Ensure the entries are sorted correctly
	m_TreeCtrl.SortChildren (parent_item);
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnDestroy
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::OnDestroy (void)
{
	::RemoveProp (m_TreeCtrl, "TRANS_ACCS");
	::RemoveProp (m_hWnd, "TRANS_ACCS");

	CDialog::OnDestroy ();
	return ;
	
}


////////////////////////////////////////////////////////////////////////////
//
//  Export_File_Dependencies
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Export_File_Dependencies (const char *filename)
{
	//
	//	Create the file
	//
	TextFileClass file (filename);
	if (file.Open (RawFileClass::WRITE)) {

		//
		//	Build a list of all the entries in the tree
		//
		DynamicVectorClass<HTREEITEM> entry_list;
		Build_Child_List (TVI_ROOT, entry_list);

		//
		//	Loop over all the presets in the list
		//
		for (int index = 0; index < entry_list.Count (); index ++) {
			PresetClass *preset = Get_Item_Preset (entry_list[index]);
			if (preset != NULL) {
				DefinitionClass *definition = preset->Get_Definition ();
				if (definition != NULL) {
					
					//
					//	Generate the list of file's that this preset is dependent on
					//
					DynamicVectorClass<StringClass> file_list;
					Build_File_Dependencies_For_Definition (file_list, definition);

					//
					//	If the list wasn't empty, then export the filenames to the text file.
					//
					if (file_list.Count () > 0) {
						
						//
						//	Start the entry off with the name of the preset
						//
						StringClass entry;
						entry.Format ("%s\t", (const char *)definition->Get_Name ());

						//
						//	Now, spit out the list of files
						//
						for (int index = 0; index < file_list.Count (); index ++) {
							entry += file_list[index];
							entry += "\t";
						}

						//
						//	Add the entry to the text file
						//
						file.Write_Line (entry);
					}
				}
			}
		}

		//
		//	Close the file
		//
		file.Close ();
	}

	return ;
	
}


////////////////////////////////////////////////////////////////////////////
//
//  Build_File_Dependencies_For_Definition
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Build_File_Dependencies_For_Definition
(
	DynamicVectorClass<StringClass> &	file_list,
	DefinitionClass *							definition
)
{	
	//
	//	Loop over all the parameters of this definition
	//
	int count = definition->Get_Parameter_Count ();
	for (int index = 0; index < count; index ++) {
		ParameterClass *parameter = definition->Lock_Parameter (index);

		//
		//	Handle the different file types
		//
		if (parameter->Is_Type (ParameterClass::TYPE_FILENAME)) {
			FilenameParameterClass *filename_param = reinterpret_cast<FilenameParameterClass *> (parameter);
			
			//
			//	Add the filename to the list if its not empty
			//
			StringClass filename = filename_param->Get_String ();			
			if (filename.Get_Length () > 0) {
				file_list.Add (filename);
			}

		} else if (parameter->Get_Type () == ParameterClass::TYPE_MODELDEFINITIONID) {
			int def_id = ((ModelDefParameterClass *)parameter)->Get_Value ();
			
			//
			//	Recurse into the model's definition (if necessary)
			//
			DefinitionClass *model_definition = DefinitionMgrClass::Find_Definition (def_id, false);
			if (model_definition != NULL) {
				Build_File_Dependencies_For_Definition (file_list, model_definition);
			}

		} else if (parameter->Get_Type () == ParameterClass::TYPE_PHYSDEFINITIONID) {
			int def_id = ((PhysDefParameterClass *)parameter)->Get_Value ();

			//
			//	Recurse into the physic object's definition (if necessary)
			//
			DefinitionClass *phys_definition = DefinitionMgrClass::Find_Definition (def_id, false);
			if (phys_definition != NULL) {
				Build_File_Dependencies_For_Definition (file_list, phys_definition);
			}
		}

		definition->Unlock_Parameter (index);
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Add_Preset
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Add_Preset (PresetClass *preset)
{
	uint32 class_id = preset->Get_Class_ID ();

	//
	//	Find the root item 
	//
	HTREEITEM root_item = Find_Factory (TVI_ROOT, class_id);
	if (root_item != NULL) {
		
		//
		//	Add the preset to the tree
		//
		Insert_Preset (root_item, preset);
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Sort_Items
//
////////////////////////////////////////////////////////////////////////////
void
PresetsFormClass::Sort_Items (uint32 class_id)
{
	//
	//	Find the root item 
	//
	HTREEITEM root_item = Find_Factory (TVI_ROOT, class_id);
	if (root_item != NULL) {

		//
		//	Sort all items under this root
		//
		m_TreeCtrl.SetRedraw (FALSE);
		Sort_Nodes (root_item);
		m_TreeCtrl.SetRedraw (TRUE);
	}

	return ;
}


