// NodeObject.cpp: implementation of the CNodeObject class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ContentTrack.h"
#include "NodeObject.h"
#include "NodeDataValueFileDoc.h"

#include "mainfrm.h"
#include <assert.h>

#include <ElementRenderer\StateChange.hpp>
#include <MLR\MLRTexturePool.hpp>
#include <MLR\MLRTexture.hpp>
#include <MLR\MLRShape.hpp>
#include <GameOS\ToolOS.hpp>

#include "..\..\Code\Buildnum\buildnum.h"

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

//CMapStringToPtr g_mapKeyType;


//****************************************************************************
// Procedure    ForwardMessage
//
// Purpose      Lets another process do what it needs to when we're in the
//              middle of something lengthy.
//
// Parameters   none
//
// Returns      nonzero if all messages were removed from the queue; zero
//                              if some are left when we return.
//
// History
//10/06/94 KenSh           Don't remove WM_CLOSE, WM_QUIT, etc.,from the queue.  Screws up in Win32.
//
BOOL ForwardMessages()
{
	MSG   msg;

	while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
	{
		if( msg.message == WM_QUIT ||
			msg.message == WM_CLOSE ||
			msg.message == WM_DESTROY )
		{
			// Put the message back on the queue and get out of here.
		    PostMessage( msg.hwnd, msg.message, msg.wParam, msg.lParam );
			return FALSE;
		}

		TranslateMessage (&msg);
		DispatchMessage (&msg);
	}

	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CNodeObject
//////////////////////////////////////////////////////////////////////

CString ReplaceNoCase(CString input,CString strOld,CString strNew,int *pCount = NULL)
{
	if (pCount)
		*pCount = 0;
	if (0 == strOld.GetLength())
		return input;
	CString output;

	int index = 0;
	CString strFind = input;
	strFind.MakeLower();
	strOld.MakeLower();
	int iFind = 0;
	while (-1 != iFind)
	{
		iFind = strFind.Find(strOld,index);
		if (iFind>=0)
		{
			output += input.Mid(index,(iFind-index))+strNew;
			if (pCount)
				(*pCount)++;
			index = iFind+strOld.GetLength();
		}
	}
	output += input.Mid(index,input.GetLength()-index);
	return output;
}

static DWORD g_dwNameMem = 0;

CNodeObject::CNodeObject(CNodeObject *pParent,CString name,CNodeObject *pClone,CString oldName,CString newName)
{
	m_iClassID = CLASS_CNODEOBJECT;
	
	m_pNodeParent = pParent;
	m_bDirty = true;

	m_iRefCount = 0;
	m_dwVisited = 0;

	m_pListChildren = m_pListReferences = NULL;

	m_szName = NULL;
	if (name.GetLength())
	{
		int rcount;
		CString output = ReplaceNoCase(name,oldName,newName,&rcount);
		if (rcount)
		{
			int x=1;
		}
		m_szName = strdup(output);
		g_dwNameMem += strlen(m_szName)+1;
	}
	if (pClone)
	{
		POSITION pos = pClone->GetFirstChild();
		while (pos)
		{
			CNodeObject *pChild = pClone->GetNextChild(pos);
			CNodeObject *pChildClone = pChild->Clone(this,oldName,newName);
			AddChild(pChildClone);
		}
		Paste(pClone);
	}
}

CNodeObject::~CNodeObject()
{
	//TODO: this should already be empty
	m_mapViewHandles.RemoveAll();

	if (m_pListChildren)
	{
		NODELIST *pos = m_pListChildren;
		while (pos)
		{
			pos->pData->RemoveRef(this);
			NODELIST *nextpos = pos->pNext;
			delete pos;
			pos = nextpos;
		}
	}
	/*
	POSITION pos = this->GetFirstChild();
	while (pos)
	{
		CNodeObject *pObj = this->GetNextChild(pos);
		pObj = pObj->RemoveRef(this);
	}
	m_listChildren.RemoveAll();*/
	/*
	pos = m_listReferences.GetHeadPosition();
	if (pos)
	{
		// Not all references were removed before deleting this item
		int x=1;
	}*/
	if (m_szName)
		delete m_szName;
}

void CNodeObject::SetName(const char *name)
{
	if (m_szName)
		delete m_szName;
	m_szName = strdup(name);
}

int CNodeObject::GetName(CString &str)
{
	char buf[MAX_PATH];
	int len = GetName(buf,MAX_PATH);
	str = buf;
	return len;
}

CString CNodeObject::GetNameStr()
{
	CString str;
	GetName(str);
	return str;
}

// Buf must be pre-allocated
int CNodeObject::GetName(char *buf,int buflen)
{
	strncpy(buf,m_szName,buflen);
	return Min(buflen,strlen(m_szName));
}

POSITION CNodeObject::GetFirstChild()
{
//	return this->m_listChildren.GetHeadPosition();
	return (POSITION)m_pListChildren;
}

CNodeObject *CNodeObject::GetNextChild(POSITION &pos)
{
	// TODO: Should probably check that the object type is a valid derivative of CNodeObject
	//return (CNodeObject *)this->m_listChildren.GetNext(pos);
	NODELIST *pItem = (NODELIST *)pos;
	pos = (POSITION)pItem->pNext;
	return pItem->pData;
}

POSITION CNodeObject::AddChild(CNodeObject *pNode)
{
	NODELIST *pItem = new NODELIST;
	pItem->pData = pNode;
	pItem->pNext = m_pListChildren;
	m_pListChildren = pItem;
	pNode->AddRef(this);
	return (POSITION)pItem;
	/*
	if(pNode)
	{
		pNode->AddRef(this);
		return this->m_listChildren.AddHead(pNode);
	}
	VERIFY(false);
	return NULL;*/
}

CNodeObject *CNodeObject::RemoveChild(POSITION pos)
{
	//CNodeObject *pChild = this->GetAt(pos);
	/*
	m_listChildren.RemoveAt(pos);
	*/
	// TODO: Speed this up??
	NODELIST *pPrev=NULL,*pItem = m_pListChildren;
	while (pItem && ((POSITION)pItem != pos))
	{
		pPrev = pItem;
		pItem = pItem->pNext;
	}
	if (pItem)
	{
		if (pPrev)
		{
			pPrev->pNext = pItem->pNext;
		}
		else
		{
			m_pListChildren = pItem->pNext;
		}

		CNodeObject *pNode = pItem->pData;
		delete pItem;

		pNode = pNode->RemoveRef(this);
		if (pNode && (0 == pNode->GetRefCount()))
		{
			delete pNode;
			pNode = NULL;
		}
		return pNode;
	}
	// Didn't find pos as a child of this node
	assert(false);
	return NULL;
}

CNodeObject *CNodeObject::GetAt(POSITION pos)
{
	NODELIST *pItem = m_pListChildren;
	while (pItem)
	{
		if ((POSITION)pItem == pos)
			return pItem->pData;
		pItem = pItem->pNext;
	}
	//return (CNodeObject *)m_listChildren.GetAt(pos);
	assert(false);
	return NULL;
}

HANDLE CNodeObject::ViewNode(CTreeCtrl *pCtrl,HTREEITEM hParent,int depth)
{
	HTREEITEM hItem = NULL;
	CString name;
	GetName(name);
	bool bExpand = false;

	if (GetClassID() == CLASS_CNODEDATAVALUE)
	{
		CNodeDataValue *pthis = (CNodeDataValue *)this;
		if (pthis->GetKeyType() == KEYTYPE_UNKNOWN)
			name = "(Unknown)"+name;
	}
	if (this->IsFile())
	{
		CNodeDataValueFile *pthis = (CNodeDataValueFile *)this;
		if (!pthis->GetNodeDisk()->IsFound())
			name = "(Not Found)"+name;
	}
	

	if (NULL == hParent)
	{
		CNodeObject *pNode = this->GetParentNode();
		if (pNode)
		{
			// We are trying to view a node that has not been expanded, so load up the parent tree
			HANDLE handle = pNode->ViewNode(pCtrl,NULL,0);
			hParent = (HTREEITEM)handle;
			bExpand = true;
			pCtrl->Expand(hParent,TVE_EXPAND);
		}
	}

	if (NULL == hItem)
	{
		if (m_mapViewHandles.Lookup(hParent,(void *&)hItem))
		{
			if (m_bDirty)
			{
				// Either change all of the instances in mapViewHandles here (assuming all are same type of view)
				// or clean the dirty bit after all the views have been updated
				pCtrl->SetItemText(hItem,name);
				pCtrl->SetItemData(hItem,(DWORD)this);
			}
		}
		else
		{
			hItem = pCtrl->InsertItem(name,hParent);
			m_mapViewHandles[hParent] = hItem;
			pCtrl->SetItemData(hItem,(DWORD)this);
		}
	}

	if (!pCtrl->GetItemState(hItem,TVIS_EXPANDED))
	{
		if (depth)
			depth--;
		else
		{
			// We should only be expanding up here
			return hItem;
		}
	}

	if (bExpand)
	{
		// This is the last one, so set it to bold
		//pCtrl->Expand(hItem,TVE_EXPAND);
		//pCtrl->SetItemState(hItem,TVIS_BOLD,TVIS_BOLD);
	}
	else
	{
		POSITION pos = this->GetFirstChild();
		while (pos)
		{
			CNodeObject *pNode = this->GetNextChild(pos);
			HTREEITEM hChildItem;
			if ((depth >0) || (pNode->m_mapViewHandles.Lookup(hItem,(void *&)hChildItem)))
				pNode->ViewNode(pCtrl,hItem,depth);
		}
		m_bDirty = false;
	}
	return hItem;
}

void CNodeObject::Update()
{
	if (GetVisit(VISIT_FLAG1))
		return;
	SetVisit(VISIT_FLAG1);
	POSITION pos = this->GetFirstChild();
	while (pos)
	{
		CNodeObject *pNode = this->GetNextChild(pos);
		pNode->Update();
	}
}

CNodeObject *CNodeObject::RemoveRef(CNodeObject *pFrom)
{
	NODELIST *pPrev=NULL,*pItem = m_pListReferences;
	while (pItem && (pItem->pData!=pFrom))
	{
		pPrev = pItem;
		pItem = pItem->pNext;
	}
	if (pItem)
	{
		m_iRefCount--;
		if (pPrev)
		{
			pPrev->pNext = pItem->pNext;
		}
		else
		{
			m_pListReferences = pItem->pNext;
		}
		delete pItem;

		if (0 == m_iRefCount)
		{
			delete this;
			return NULL;
		}
		return this;
	}

	// pFrom is not a reference of this node
	assert(false);
	return NULL;


	/*
	POSITION pos = m_listReferences.Find(pFrom);
	if (pos)
	{
		m_listReferences.RemoveAt(pos);
		m_iRefCount--;
	}
	else
	{
		// Trying to remove a reference when one wasn't made from here
		//assert(false);
		// Or that this is a DiskFile that is not in the content directory so it doesn't have a content root reference
		VERIFY(false);
	}
	
	if (0 == m_iRefCount)
	{
		delete this;
		return NULL;
	}
	return this;*/
}

CNodeObject *CNodeObject::FindChild(CString strName,bool bRecurse)
{
//	strName.MakeLower();
	POSITION pos = GetFirstChild();
	while (pos)
	{
		CNodeObject *pChild = GetNextChild(pos);
		CString name;
		pChild->GetName(name);
		//name.MakeLower();
		//if (name == strName)
		if (0 == stricmp(name,strName))
			return pChild;
		if (bRecurse)
		{
			pChild = pChild->FindChild(strName,bRecurse);
			if (pChild)
				return pChild;
		}
	}
	return NULL;
}

void CNodeObject::AddRef(CNodeObject *pFrom)
{
	NODELIST *pItem = new NODELIST;
	pItem->pNext = m_pListReferences;
	m_pListReferences= pItem;
	pItem->pData = pFrom;
	m_iRefCount++;
	/*
	m_listReferences.AddHead(pFrom);
	m_iRefCount++;
	VERIFY(m_listReferences.GetCount() == m_iRefCount);*/
}

POSITION CNodeObject::GetFirstReference()
{
	//return m_listReferences.GetHeadPosition();
	return (POSITION)m_pListReferences;
}

CNodeObject *CNodeObject::GetNextReference(POSITION &pos)
{
	//return (CNodeObject *)this->m_listReferences.GetNext(pos);
	NODELIST *pItem = (NODELIST *)pos;
	pos = (POSITION)pItem->pNext;
	return pItem->pData;
}

CNodeObject *CNodeObject::Clone(CNodeObject *pParent,CString oldName,CString newName)
{
	CNodeObject *pClone = NULL;
	// Return a clone of this node
	CString name;
	GetName(name);
	switch (GetClassID())
	{
	case CLASS_CNODEOBJECT: return new CNodeObject(pParent,name,this,oldName,newName);
	case CLASS_CNODEDISK:
	case CLASS_CNODEDISKDIRECTORY:
	case CLASS_CNODEDISKFILE:
	case CLASS_CNODEDATA: break;
	case CLASS_CNODEDATAPAGE: return new CNodeDataPage(pParent,NULL,name,"","",this,oldName,newName);
	case CLASS_CNODEDATAENTRY: return new CNodeDataEntry(pParent,NULL,name,"",this,oldName,newName);
	case CLASS_CNODEDATAVALUE: return new CNodeDataValue(pParent,name,this,oldName,newName);
	case CLASS_CNODEDATAVALUEFLOAT: return new CNodeDataValueFloat(pParent,name,this,oldName,newName);
	case CLASS_CNODEDATAVALUEPOINT3: return new CNodeDataValuePoint3(pParent,name,this,oldName,newName);
	case CLASS_CNODEDATAVALUEBOOL: return new CNodeDataValueBool(pParent,name,this,oldName,newName);
	case CLASS_CNODEDATAVALUESTRING: return new CNodeDataValueString(pParent,name,this,oldName,newName);
	case CLASS_CNODEDATAVALUEINT: return new CNodeDataValueInt(pParent,name,this,oldName,newName);
	case CLASS_CNODEDATAVALUECOMPOSTTEXTURE: return new CNodeDataValueCompostTexture(pParent,name,this,oldName,newName);
//	case CLASS_CNODEDATAVALUEFILE: - This class is over-ridded
	case CLASS_CNODEDATAVALUEFILEPROJECT:break;
	case CLASS_CNODEDATAVALUEFILEERF: return new CNodeDataValueFileERF(pParent,name,this,oldName,newName);
	case CLASS_CNODEDATAVALUEFILEWAV: return new CNodeDataValueFileWAV(pParent,name,this,oldName,newName);
	case CLASS_CNODEDATAVALUEFILEMW4ANIM: return new CNodeDataValueFileMW4ANIM(pParent,name,this,oldName,newName);
	case CLASS_CNODEDATAVALUEFILETGA: return new CNodeDataValueFileTGA(pParent,name,this,oldName,newName);
	case CLASS_CNODEDATAVALUEFILEPNG: return new CNodeDataValueFilePNG(pParent,name,this,oldName,newName);
	case CLASS_CNODEDATAVALUEFILENOTE: return new CNodeDataValueFileNote(pParent,name,this,oldName,newName);
	case CLASS_CNODEDATAVALUEFILEBSP: return new CNodeDataValueFileBSP(pParent,name,this,oldName,newName);
	case CLASS_CNODEDATAVALUEFILEOBB: return new CNodeDataValueFileOBB(pParent,name,this,oldName,newName);
	case CLASS_CNODEDATAVALUEFILEABL: return new CNodeDataValueFileABL(pParent,name,this,oldName,newName);
	case CLASS_CNODEDATAVALUEFILEFGD: return new CNodeDataValueFileFGD(pParent,name,this,oldName,newName);
	case CLASS_CNODEDATAVALUEFILEMATERIAL: return new CNodeDataValueFileMATERIAL(pParent,name,this,oldName,newName);
	case CLASS_CNODEDATAVALUEFILERAW: return new CNodeDataValueFileRAW(pParent,name,this,oldName,newName);
	case CLASS_CNODEDATAVALUEFILEBID: return new CNodeDataValueFileBID(pParent,name,this,oldName,newName);
	//case CLASS_CNODEDATAVALUEFILERESOURCE: return new CNodeDataValueFileResource(pParent,GetName(),this);
		// Dont clone erf data, just re-load the erf and change the names along the way
	case CLASS_CNODEDATAVALUEERF: return new CNodeDataValueERF(pParent,NULL,this,oldName,newName);
	case CLASS_CNODEDATAVALUEERFGROUPELEMENT: return new CNodeDataValueERFGroupElement(pParent,NULL,this,oldName,newName);
	case CLASS_CNODEDATAVALUEERFLISTELEMENT: return new CNodeDataValueERFListElement(pParent,NULL,this,oldName,newName);
	case CLASS_CNODEDATAVALUEERFGRIDELEMENT: return new CNodeDataValueERFGridElement(pParent,NULL,this,oldName,newName);
	case CLASS_CNODEDATAVALUEERFLODELEMENT: return new CNodeDataValueERFLODElement(pParent,NULL,this,oldName,newName);
	case CLASS_CNODEDATAVALUEERFSHAPELODELEMENT: return new CNodeDataValueERFShapeLODElement(pParent,NULL,this,oldName,newName);
	case CLASS_CNODEDATAVALUEERFSHAPEELEMENT: return new CNodeDataValueERFShapeElement(pParent,NULL,this,oldName,newName);
	case CLASS_CNODEDATAVALUEERFSWITCHELEMENT: return new CNodeDataValueERFSwitchElement(pParent,NULL,this,oldName,newName);
	case CLASS_CNODEDATAVALUEMLRELEMENT: return new CNodeDataValueMLRElement(pParent,NULL,this,oldName,newName);
		{
			break;
		}
	default:
		{
			// unknown type
			assert(false);
		}
	}
	return pClone;
}

bool CNodeObject::IsFile()
{
	switch (GetClassID())
	{
	case CLASS_CNODEDATAVALUEFILE:
	case CLASS_CNODEDATAVALUEFILEPROJECT:
	case CLASS_CNODEDATAVALUEFILEERF:
	case CLASS_CNODEDATAVALUEFILEWAV:
	case CLASS_CNODEDATAVALUEFILEMW4ANIM:
	case CLASS_CNODEDATAVALUEFILETGA:
	case CLASS_CNODEDATAVALUEFILEPNG:
	case CLASS_CNODEDATAVALUEFILENOTE:
	case CLASS_CNODEDATAVALUEFILEBSP:
	case CLASS_CNODEDATAVALUEFILEOBB:
	case CLASS_CNODEDATAVALUEFILEABL:
	case CLASS_CNODEDATAVALUEFILEFGD:
	case CLASS_CNODEDATAVALUEFILEMATERIAL:
	case CLASS_CNODEDATAVALUEFILERAW:
	case CLASS_CNODEDATAVALUEFILEBID:
		return true;
	}
	return false;
}

bool CNodeObject::IsDataValue()
{
	switch (GetClassID())
	{
	case CLASS_CNODEDATAVALUE: 
	case CLASS_CNODEDATAVALUEFLOAT:
	case CLASS_CNODEDATAVALUEPOINT3:
	case CLASS_CNODEDATAVALUEBOOL:
	case CLASS_CNODEDATAVALUESTRING:
	case CLASS_CNODEDATAVALUEINT:
	case CLASS_CNODEDATAVALUECOMPOSTTEXTURE:
	case CLASS_CNODEDATAVALUEFILE: 
	case CLASS_CNODEDATAVALUEFILEPROJECT:
	case CLASS_CNODEDATAVALUEFILEERF: 
	case CLASS_CNODEDATAVALUEFILEWAV:
	case CLASS_CNODEDATAVALUEFILEMW4ANIM:
	case CLASS_CNODEDATAVALUEFILETGA:
	case CLASS_CNODEDATAVALUEFILEPNG:
	case CLASS_CNODEDATAVALUEFILENOTE:
	case CLASS_CNODEDATAVALUEFILEBSP:
	case CLASS_CNODEDATAVALUEFILEOBB:
	case CLASS_CNODEDATAVALUEFILEABL:
	case CLASS_CNODEDATAVALUEERF:
	case CLASS_CNODEDATAVALUEFILEFGD:
	case CLASS_CNODEDATAVALUEFILEMATERIAL:
	case CLASS_CNODEDATAVALUEFILERAW:
	case CLASS_CNODEDATAVALUEFILEBID:
		return true;
	}
	return false;
}

bool CNodeObject::SetVisit(DWORD dwFlag)
{
	bool bret = GetVisit(dwFlag);
	m_dwVisited = (m_dwVisited | dwFlag) & dwFlag;
	return false;
}

bool CNodeObject::GetVisit(DWORD dwFlag)
{
	return m_dwVisited & dwFlag;
}

void CNodeObject::ResetVisit()
{
	this->m_dwVisited = 0;
}

void CNodeObject::ResetVisitAll()
{
	ResetVisit();
	POSITION pos = GetFirstChild();
	while (pos)
	{
		CNodeObject *pChild = GetNextChild(pos);
		pChild->ResetVisitAll();
	}
}

int CNodeObject::Paste(CNodeObject *pClone)
{
	return 0;
}

CString CNodeObject::GetRootPath()
{
	if (GetClassID() == CLASS_CNODEDATAVALUEFILEPROJECT)
	{
		CString str;
		GetName(str);
		return str;
	}
	CNodeObject *pParent = GetParentNode();
	if (pParent)
		return pParent->GetRootPath();
	return "";
}

//////////////////////////////////////////////////////////////////////
// CNodeDisk
//////////////////////////////////////////////////////////////////////

CNodeDisk::CNodeDisk(CNodeObject *pParent,CString path,bool bFindOverride) : CNodeObject(pParent,path)
{
	m_iClassID = CLASS_CNODEDISK;
	// Used for creating generic disk node outside of contents directory - like the project node
	if (bFindOverride)
		m_bFound = true;
	else
		m_bFound = false;
	m_bLoaded = false;
	m_bDirty = false;
	// Extract the deepest subdir from the path, save the prefix as the m_strParentPath
	// save the suffix as m_strName

	// There must be a path here
	if (path.IsEmpty())
	{
		assert(false);
		return;
	}

	// Make sure the end of the path is not trailing a '\' character
	if ('\\'==path[path.GetLength()-1])
	{
		path.SetAt(path.GetLength()-1,'\0');
		SetName(path);
	}

	/*
	// Separate prefix and suffix
	CString prefix;
	int index = path.ReverseFind('\\');
	if (0<=index)
	{
		prefix = path.Left(index);
		path.Delete(0,index+1);
	}*/
	//SetName(path);
}

CNodeDisk::~CNodeDisk()
{

}

CString CNodeDisk::GetPath()
{
	CString str;
	GetName(str);
	CString dir = GetDirectory();
	if (dir.GetLength())
		dir += "\\";
	return dir+str;
}

CString CNodeDisk::GetDirectory()
{
	CNodeObject *pParent = GetParentNode();
	if (pParent && (pParent->GetClassID() == CLASS_CNODEDISKDIRECTORY))
	{
		CString str;
		pParent->GetName(str);
		CString dir = ((CNodeDisk *)pParent)->GetDirectory();
		return (dir.GetLength()?dir+"\\":"")+str;
	}
	return "";
}

CNodeDiskFile *CNodeDisk::DiskCopyFile(CString source,CString dest)
{
	// Create the directory first
	char drive[MAX_PATH],dir[MAX_PATH],fname[MAX_PATH],ext[MAX_PATH];
	_splitpath(dest,drive,dir,fname,ext);

	CString strRoot = this->GetRootPath()+"\\";
	CNodeDisk *pDir = DiskCreateDirectory(dir);
	CString filename = CString(fname)+ext;
	CString fullpath = strRoot+pDir->GetPath()+"\\"+filename;
	bool result;
	if (source.GetLength())
	{
		result = ::CopyFile(source,fullpath,false);
	}
	else
	{
		if (!gos_DoesFileExist(fullpath))
		{
			HGOSFILE file;
			gos_OpenFile(&file,fullpath,READWRITE);
			gos_CloseFile(file);
			result = true;
		}
	}
	
	CNodeDiskFile *pFile = new CNodeDiskFile(pDir,filename);
	pDir->AddChild(pFile);
	return pFile;
}

// Copy the file from memory raw data
CNodeDiskFile *CNodeDisk::DiskCopyFile(LPVOID lpData,DWORD dwSize,CString dest)
{
	// Create the directory first
	char drive[MAX_PATH],dir[MAX_PATH],fname[MAX_PATH],ext[MAX_PATH];
	_splitpath(dest,drive,dir,fname,ext);

	CString strRoot = this->GetRootPath()+"\\";
	CNodeDisk *pDir = DiskCreateDirectory(dir);
	CString filename = CString(fname)+ext;
	CString fullpath = strRoot+pDir->GetPath()+"\\"+filename;
	bool result;
	if (lpData && dwSize)
	{
		HANDLE hFile = CreateFile(fullpath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW ,
			FILE_ATTRIBUTE_NORMAL, NULL);

		if (hFile == INVALID_HANDLE_VALUE)
		{
			if (GetLastError() == ERROR_ALREADY_EXISTS || GetLastError() == ERROR_FILE_EXISTS)
			{
				// File already exists
				int x=1;
			}
			// Error creating file
			int x=1;
		}
		else
		{
			DWORD dwBytesWritten; 
			if (!WriteFile(hFile, lpData, dwSize, & dwBytesWritten, NULL) || dwBytesWritten != dwSize)
			{
				// Failed to write file
				int x=1;
			}
			CloseHandle(hFile);
		}
	}
	else
	{
		if (!gos_DoesFileExist(fullpath))
		{
			HGOSFILE file;
			gos_OpenFile(&file,fullpath,READWRITE);
			gos_CloseFile(file);
			result = true;
		}
	}
	
	CNodeDiskFile *pFile = new CNodeDiskFile(pDir,filename);
	pDir->AddChild(pFile);
	return pFile;
}

CNodeDisk *CNodeDisk::DiskCreateDirectory(CString name)
{
	if (0 == name.GetLength())
		return this;
	if (name[0] == '\\')
		name = name.Right(name.GetLength()-1);

	int index = name.Find("\\",0);
	if (index<0)
		return this;
	CString left = name.Left(index);
	CString right = name.Right(name.GetLength()-index);
	POSITION pos = GetFirstChild();
	while (pos)
	{
		CNodeObject *pChild = GetNextChild(pos);
		switch (pChild->GetClassID())
		{
		case CLASS_CNODEDISKFILE:
			{
				break;
			}
		case CLASS_CNODEDISKDIRECTORY:
			{
				CString s1;
				pChild->GetName(s1);
				CString s2 = left;
				//s1.MakeLower();
				//s2.MakeLower();
				//if (0 == strnicmp(pChild->GetName(),left,left.GetLength()))
				// (s1 == s2)
				if (0 == stricmp(s1,s2))
					return ((CNodeDisk *)pChild)->DiskCreateDirectory(right);
				break;
			}
		default:
			{
				return NULL;
			}
		}
	}
	CString strNewPath = GetPath()+"\\"+left;
	CString strFullPath = this->GetRootPath()+"\\"+strNewPath;
	::CreateDirectory(strFullPath,NULL);
	CNodeDisk *pDir = new CNodeDiskDirectory(this,left);
	AddChild(pDir);
	CNodeDisk *pChildDir = pDir->DiskCreateDirectory(right);
	return pChildDir;
}

//////////////////////////////////////////////////////////////////////
// CNodeData
//////////////////////////////////////////////////////////////////////

CNodeData::CNodeData(CNodeObject *pParent,CString path,CNodeObject *pClone,CString oldName,CString newName) : CNodeObject(pParent,path,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATA;
}

CNodeData::~CNodeData()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDiskDirectory
//////////////////////////////////////////////////////////////////////

CNodeDiskDirectory::CNodeDiskDirectory(CNodeObject *pParent,CString path) : CNodeDisk(pParent,path)
{
	m_iClassID = CLASS_CNODEDISKDIRECTORY;

	// recurse on path to scan the for the children
	CFileFind ffind;

	if (pParent && (pParent->GetClassID() == CLASS_CNODEDISKDIRECTORY))
	{
		CNodeDisk *pDisk = (CNodeDisk *)pParent;
		CString str = pDisk->GetPath();
		path = str+"\\"+path;
	}
	else
	{
		int x=1;
	}
	path += "\\*.*";
	if (ffind.FindFile(path,0))
	{
		m_bFound = true;
		while (ffind.FindNextFile())
		{
			if (!ffind.IsDots())
			{
				CNodeDisk *pChild = NULL;
				if (ffind.IsDirectory())
				{
					// Is a directory
					pChild = new CNodeDiskDirectory(this,ffind.GetFileName());//GetFilePath());
				}
				else
				{
					// Is a file
					pChild = new CNodeDiskFile(this,ffind.GetFileName());//.GetFilePath());
				}
				AddChild(pChild);
			}
		}
		// There is always one more...
		{
			if (!ffind.IsDots())
			{
				CNodeDisk *pChild = NULL;
				if (ffind.IsDirectory())
				{
					// Is a directory
					pChild = new CNodeDiskDirectory(this,ffind.GetFileName());//.GetFilePath());
				}
				else
				{
					// Is a file
					pChild = new CNodeDiskFile(this,ffind.GetFileName());//GetFilePath());
				}
				AddChild(pChild);
			}
		}
	}
	else
	{
		// We are making virtual directories
		int x=1;
	}
	ffind.Close();
}

CNodeDiskDirectory::~CNodeDiskDirectory()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDiskFile
//////////////////////////////////////////////////////////////////////

CNodeDiskFile::CNodeDiskFile(CNodeObject *pParent,CString name) : CNodeDisk(pParent,name)
{
	m_iClassID = CLASS_CNODEDISKFILE;
	// For performance I may want the callee to set m_bFound if it was from CNodeDiskDirectory
	if (CLASS_CNODEDISKDIRECTORY == pParent->GetClassID())
	{
		m_bFound = true;
	}
}

CNodeDiskFile::~CNodeDiskFile()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataPage
//////////////////////////////////////////////////////////////////////

CNodeDataPage::CNodeDataPage(CNodeObject *pParent,Page *page,CString pagename,CString entryname,CString name,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeData(pParent,page?page->GetName():pagename,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAPAGE;

	if (pClone)
		return;	// Cloning handled by superclass

	CNodeDataEntry *pChild=NULL;
	if (page)
	{
		Page::NoteIterator *entries = page->MakeNoteIterator();
		Check_Object(entries);

		Note *entry;
		// Enumerate the entries in the section
		while ((entry = entries->ReadAndNext()) != NULL)
		{
			Check_Object(entry);
			pChild = new CNodeDataEntry(this,entry,"","");
			AddChild(pChild);
		}
		Check_Object(entries);
		delete entries;
	}
	else
	{
		pChild = new CNodeDataEntry(this,NULL,entryname,name);
		AddChild(pChild);
	}
	
}

CNodeDataPage::~CNodeDataPage()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataEntry
//////////////////////////////////////////////////////////////////////
extern CStringMap g_StringMap;

/* Base constructed with string "" so that no bytes are allocated for name, which is pointer to key node*/
CNodeDataEntry::CNodeDataEntry(CNodeObject *pParent,Note *entry,CString keyname,CString valuename,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeData(pParent,/*entry?(char *)entry->GetName():keyname*/"",pClone,oldName,newName)
// Can be constructed either with the Note, or with NULL note and key value pair
{
	m_iClassID = CLASS_CNODEDATAENTRY;

	if (pClone)
	{
		CNodeDataEntry *pCloneEntry = (CNodeDataEntry *)pClone;
		m_szName = (char *)pCloneEntry->GetKeyPos();
		return; // cloning handled by superclass
	}

	const char *pKeyName;
	if (entry)
		pKeyName = (char *)entry->GetName();
	else
		pKeyName = (LPCTSTR)keyname;
	const char *pValueName = (LPCTSTR)valuename;
	if (entry)
		entry->GetEntry(&pValueName);


	// need to determine what kind of data this is
	/*void *value = 0;
	CString strV(pKeyName);
	strV.MakeUpper();
	if (!g_mapKeyType.Lookup(strV,value))
	{
		// This is a new key type, add it to the known key type list
		g_mapKeyType[strV] = 0;
	}*/
	POSITION pos = g_StringMap.Exists(pKeyName);
	if (NULL == pos)
		pos = g_StringMap.Find(pKeyName);
	BYTE bval = g_StringMap.GetValue(pos);

	/*
	{
		VERIFY(bval == (DWORD)value);
		CString str1 = g_StringMap.GetName(pos);
		VERIFY(strV == str1);
	}
*/
	this->m_szName = (char *)pos;
	CNodeData *pChild = CreateChild(this,(int)bval,pValueName);
	AddChild(pChild);
}

CNodeDataEntry::~CNodeDataEntry()
{
	//strcpy(m_szName,"000");
	m_szName = NULL;
}

void CNodeDataEntry::Update()
{
	//void *value = 0;
	//CString name;
	//CNodeData::GetName(name);
	//name.MakeUpper();
	/*if (!g_mapKeyType.Lookup(name,value))
	{
		// This is a new key type, add it to the known key type list
		g_mapKeyType[name] = 0;
	}*/
/*	POSITION pos = g_StringMap.Exists(name);
	if (NULL == pos)
		pos = g_StringMap.Find(name);*/
	BYTE val = GetKeyValue();


	POSITION pos,pos1 = this->GetFirstChild();
	pos = pos1;
	while (pos)
	{
		CNodeDataValue *pNode = (CNodeDataValue *)this->GetNextChild(pos);
		if (val == pNode->GetKeyType())
			pNode->Update();
		else
		{
			CString str;
			pNode->GetName(str);
			// Copy to a temp map
			CMapPtrToPtr map;
			POSITION pos = pNode->m_mapViewHandles.GetStartPosition();
			while (pos)
			{
				HANDLE key;
				HANDLE value;
				pNode->m_mapViewHandles.GetNextAssoc(pos,key,value);
				map[key] = value;
			}	
			CNodeObject *pObj = RemoveChild(pos1);
			pNode = CreateChild(this,(int)val,str);
			// Copy back to new map
			pos = map.GetStartPosition();
			while (pos)
			{
				HANDLE key;
				HANDLE value;
				map.GetNextAssoc(pos,key,value);
				pNode->m_mapViewHandles[key] = value;
			}
			AddChild(pNode);
			SetVisit(VISIT_FLAG1);
		}
		pos1 = pos;
	}
}

int CNodeDataEntry::GetName(char *buf,int buflen)
{
	POSITION pos = (POSITION)m_szName;
	CString str = g_StringMap.GetName(pos);
	strncpy(buf,str,buflen);
	return str.GetLength();
	/*CString key;
	LPVOID value;
	g_mapKeyType.GetNextAssoc(pos,key,&value);
	return key;
	return CNodeData::GetName();*/
}

BYTE CNodeDataEntry::GetKeyValue()
{
	POSITION pos = (POSITION)m_szName;
	return g_StringMap.GetValue(pos);
}

POSITION CNodeDataEntry::GetKeyPos()
{
	return (POSITION)m_szName;
}

CNodeDataValue *CNodeData::CreateChild(CNodeObject *pParent,int key,CString pValueName)
{
	switch (key)
	{
	case KEYTYPE_UNKNOWN:
		{
			return new CNodeDataValue(pParent,pValueName);
			break;
		}
	case KEYTYPE_NOTE:
		{
			return new CNodeDataValueFileNote(pParent,pValueName);
			break;
		}
	case KEYTYPE_MW4ANIM:
		{
			return new CNodeDataValueFileMW4ANIM(pParent,pValueName);
			break;
		}
	case KEYTYPE_ERF:
		{
			return new CNodeDataValueFileERF(pParent,pValueName);
			break;
		}
	case KEYTYPE_WAV:
		{
			return new CNodeDataValueFileWAV(pParent,pValueName);
			break;
		}
	case KEYTYPE_FLOAT:
		{
			return new CNodeDataValueFloat(pParent,pValueName);
			break;
		}
	case KEYTYPE_POINT3:
		{
			return new CNodeDataValuePoint3(pParent,pValueName);
			break;
		}
	case KEYTYPE_BOOL:
		{
			return new CNodeDataValueBool(pParent,pValueName);
			break;
		}
	case KEYTYPE_STRING:
		{
			return new CNodeDataValueString(pParent,pValueName);
			break;
		}
	case KEYTYPE_INT:
		{
			return new CNodeDataValueInt(pParent,pValueName);
			break;
		}
	case KEYTYPE_COMPOSTTEXTURE:
		{
			return new CNodeDataValueCompostTexture(pParent,pValueName);
			break;
		}
	case KEYTYPE_OBB:
		{
			return new CNodeDataValueFileOBB(pParent,pValueName);
			break;
		}
	case KEYTYPE_ABL:
		{
			return new CNodeDataValueFileABL(pParent,pValueName);
			break;
		}
	case KEYTYPE_FGD:
		{
			return new CNodeDataValueFileFGD(pParent,pValueName);
			break;
		}
	case KEYTYPE_MATERIAL:
		{
			return new CNodeDataValueFileMATERIAL(pParent,pValueName);
			break;
		}
	case KEYTYPE_RAW:
		{
			return new CNodeDataValueFileRAW(pParent,pValueName);
			break;
		}
	case KEYTYPE_BID:
		{
			return new CNodeDataValueFileBID(pParent,pValueName);
			break;
		}
	case KEYTYPE_RESOURCE:
		{
			return new CNodeDataValueFileResource(pParent,pValueName);
			break;
		}
	case KEYTYPE_TGA:
		{
			return new CNodeDataValueFileTGA(pParent,pValueName);
			break;
		}
	case KEYTYPE_PNG:
		{
			return new CNodeDataValueFilePNG(pParent,pValueName);
			break;
		}
	case KEYTYPE_BSP:
		{
			return new CNodeDataValueFileBSP(pParent,pValueName);
			break;
		}
	case KEYTYPE_PROJECT:
		{
			// Cannot create a project as a child
			assert(false);
			break;
		}
	default:
		{
		}
	}
	return NULL;
}

//////////////////////////////////////////////////////////////////////
// CNodeDataValue
//////////////////////////////////////////////////////////////////////

CNodeDataValue::CNodeDataValue(CNodeObject *pParent,CString name,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeData(pParent,name,pClone,oldName,newName)
{
	m_iKeyType = KEYTYPE_UNKNOWN;
	m_iClassID = CLASS_CNODEDATAVALUE;
}

CNodeDataValue::~CNodeDataValue()
{

}

HANDLE CNodeDataValue::ViewNode(CTreeCtrl *pCtrl,HTREEITEM hParent,int depth)
{
	HTREEITEM hItem = NULL;
	if ((NULL == hParent) && (KEYTYPE_UNKNOWN == GetKeyType())&&(CLASS_CNODEOBJECT == GetClassID()))
	{
		if (!m_mapViewHandles.Lookup(hParent,(void *&)hItem))
		{
			CString str;
			GetName(str);
			hItem = pCtrl->InsertItem(CString("(Unknown )")+str,hParent);
			m_mapViewHandles[hParent] = hItem;
			pCtrl->SetItemData(hItem,(DWORD)this);
		}
		m_bDirty = false;
	}
	else
		return CNodeObject::ViewNode(pCtrl,hParent,depth);
	return hItem;
}

int CNodeDataValue::Paste(CNodeObject *pClone)
{
	// This is where a file merge should happen to update the values (e.g. names, new note files etc)
	return 0;
}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueFile
//////////////////////////////////////////////////////////////////////

CNodeDisk *CNodeDataValueFile::SetNodeDisk(CNodeDisk *pDisk)
{
	CNodeDisk *pOld = m_pNodeDisk;
	m_pNodeDisk = pDisk;
	return pOld;
}

CNodeDataValueFile::CNodeDataValueFile(CNodeObject *pParent,CString strFileName,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValue(pParent,strFileName,NULL,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEFILE;
	m_pNodeDisk = NULL;
	m_iParentDirs = 0;

	if (pClone)
	{
		//strFileName.MakeLower();
		CString name1;
		GetName(name1);
		//name1.MakeLower();
		//if (strFileName != name1)
		if (stricmp(strFileName,name1))
		{
			// Then this is a node where the file that loaded it needs to be updated
			// Find the file node that is the parent of this node, and mark it's disk as dirty
			CNodeObject *pFileParent = pParent;
			while (pFileParent && !pFileParent->IsFile())
			{
				pFileParent = pFileParent->GetParentNode();
			}
			if (pFileParent)
			{
				CNodeDataValueFile *pNode = (CNodeDataValueFile *)pFileParent;
				pNode->GetNodeDisk()->m_bDirty = true;
			}
		}
	}

	// Get the name in case we did some clone renaming here
	GetName(strFileName);

	//Store the extra data in the name, store the number of parent dirs specified in m_iParentDirs
	{
		delete m_szName;
		m_szName = NULL;

		CString extra;
		int i = strFileName.ReverseFind(',');
		if (i>0)
		{
			extra = strFileName.Right(strFileName.GetLength()-i+1);
			m_szName = strdup(extra);
			strFileName = strFileName.Left(i);
		}
	}



	
	// Load the notefile
	/*int i = strFileName.ReverseFind(',');
	if (i>0)
	{
		strFileName = strFileName.Left(i);
	}*/
	CNodeDisk *pDisk = NULL;
	CNodeDataValueFileDoc *pDoc = NULL;

	{
		CNodeObject *pRoot = pParent;
		while (pRoot && pRoot->GetClassID() != CLASS_CNODEDATAVALUEFILEPROJECT)
			pRoot = pRoot->GetParentNode();
		if (pRoot)
			pDoc = ((CNodeDataValueFileProject *)pRoot)->GetDocument();
		if (pDoc)
		{
			CString strRoot = pDoc->GetRootDir()+"\\content\\";
			if (0 == strnicmp(strFileName,strRoot,strRoot.GetLength()))
				strFileName.Delete(0,strRoot.GetLength());
		}
	}

	bool bReplace = false;
	bool bMerge = false;
	if (pClone)
	{
		// This is a node created from the Clone's parameters
		// If the file already exists, replace or merge?
		// MERGE (Because pClone is passed up as NULL, as a result the notation file is not updated)
		CNodeDataValueFile *pFileClone = (CNodeDataValueFile *)pClone;
		CNodeDisk *pDiskClone = pFileClone->GetNodeDisk();
		// Only replace if the source (pClone) disk is marked as "Copy-Able" - this is to avoid accidental overwrites
		if (pDiskClone->GetVisit(VISIT_FLAG1))
			bReplace = true;

		pDisk = pDoc->FindDirectoryNode(strFileName);
	/*	if (NULL == pDisk)
		{
			CString strPath = pDiskClone->GetPath();
			pDisk = pDoc->FindDirectoryNode(strPath);
		}*/

		if (pDisk)
		{
			// Have we already copied this node?
			if (pDisk->GetVisit(VISIT_FLAG1))
			{
				bReplace = false;
			}
			else
			{
				// TODO: File already exists, merge if it a notefile
				
			/*	if (CLASS_CNODEDATAVALUEFILENOTE == pClone->GetClassID())
				{
					if (pDoc->m_iReplaceAll>=0)
					{
						if (pDoc->m_iReplaceAll)
							bMerge = true;
						else 
							bMerge = false;
					}
					else
					{
						CString str = strFileName+" already exists.  Merge All?";
						bReplace = (IDYES == MessageBox(NULL,str,"File Paste",MB_YESNO));
					}
					if (bMerge)
					{
						pDoc->m_iReplaceAll = 1;
					}
					else
					{
						pDoc->m_iReplaceAll = 0;
					}
				}
				else*/
				if (bReplace)
				{
					if (pDoc->m_iReplaceAll>=0)
					{
						if (pDoc->m_iReplaceAll)
							bReplace = true;
						else 
							bReplace = false;
					}
					else
					{
						CString str = strFileName+" already exists.  Replace All?";
						bReplace = (IDYES == MessageBox(NULL,str,"File Paste",MB_YESNO));
					}
					// if so, delete the old file
					if (bReplace)
					{
						pDoc->m_iReplaceAll = 1;
						CNodeObject *pDiskParent = pDisk->GetParentNode();
						POSITION fpos=NULL,pos = pDiskParent->GetFirstChild();
						while (pos)
						{
							fpos = pos;
							CNodeObject *pChild = pDiskParent->GetNextChild(pos);
							if (pChild == pDisk)
							{
								pos = NULL;
								break;
							}
						}
						CNodeObject *pObj = pDiskParent->RemoveChild(fpos);
						pDisk = NULL;
					}
					else
					{
						pDoc->m_iReplaceAll = 0;
					}
				}
			}
		}

		if (bReplace&&!bMerge)
		{
			CNodeDataValueFile *pFileClone = (CNodeDataValueFile *)pClone;
			CString srcFile = pClone->GetRootPath()+"\\"+pDiskClone->GetPath();
			
			CString dstFile = pDiskClone->GetPath();
			if (strnicmp(dstFile,"content",7)==0)
				dstFile.Delete(0,7);
			//oldName.MakeLower();
			//newName.MakeLower();
			//dstFile.MakeLower();
			int rcount; // = dstFile.Replace(oldName,newName);
			CString output = ReplaceNoCase(dstFile,oldName,newName,&rcount);
			if (rcount)
			{
				int x=1;
			}
			dstFile = output;
			// Create the file
			pDisk = pDoc->GetRootNode()->DiskCopyFile(srcFile,dstFile);
		}
		//Verify(NULL != pDisk);
		// pDisk is null here iff the source file does not exist in the destination but the source file is not
		//	marked as a copy-able file
		if (NULL == pDisk)
			pDisk = new CNodeDiskFile(this,strFileName);

		pDisk->SetVisit(VISIT_FLAG1);
		Paste(pClone);
	}

	if (!pDisk)
	{
		while (pParent && !pParent->IsFile())
			pParent = pParent->GetParentNode();
		bool bFound = false;
		if (pParent)
		{
			CNodeDataValueFile *pFile = (CNodeDataValueFile *)pParent;
			CNodeDisk *pDiskPath = pFile->GetNodeDisk();
			do
			{
				CString strPath = pDiskPath->GetDirectory()+"\\"+strFileName;
				if (strPath[0] == '\\')
					strPath.Delete(0,1);
				pDisk = pDoc->FindDirectoryNode(strPath);
				if (pDisk)
				{
					// Count the number of subdirs specified in strFileName
					int count = 0;
					int result = -1;
					while ((result = strFileName.Find('\\',result+1))>=0)
						count++;
					this->m_iParentDirs = count;

					strFileName = strPath;
					bFound = true;
					break;
				}
				pDiskPath = (CNodeDisk *)pDiskPath->GetParentNode();
			} while (pDiskPath);
		}

		if (!bFound)
		{
			if (!gos_DoesFileExist(strFileName))
			{
				int x=1;
				//char dir[MAX_PATH];
				//GetCurrentDirectory(MAX_PATH,dir);
				//CString str;
				//GetName(str);
				// Note: Not Found should not be actually in the name here
				//SetName(CString("(Not Found) ")+str);
			//	return;
			}
			else
			{
				int x=1;	// We are adding a file that is not in contents folder
				pDisk = m_pNodeDisk = new CNodeDisk(this,strFileName,true);
			}
		}
	}

	if (pDisk)
	{
		if (!pDisk->IsLoaded())
		{
			CMainFrame *pFrame = (CMainFrame*)AfxGetMainWnd();
			pFrame->SetMessageText(strFileName);
		}
		m_pNodeDisk = pDisk;
		pDisk->AddRef(this);
	}

	if (NULL == m_pNodeDisk)
	{
		// We didn't find this file
		m_pNodeDisk = new CNodeDisk(this,strFileName);
		m_pNodeDisk->AddRef(this);
	}

	if (pClone)
	{
		// Cloning of this node NOT already handled by superclass
		// This is so that if it is already loaded, duplicate structures aren't made, but referenced by nodedisk
		if (!m_pNodeDisk->IsLoaded())
		{
			POSITION pos = pClone->GetFirstChild();
			while (pos)
			{
				CNodeObject *pChild = pClone->GetNextChild(pos);
				CNodeObject *pCloneChild = pChild->Clone(this,oldName,newName);
				m_pNodeDisk->AddChild(pCloneChild);
			}
			m_pNodeDisk->SetLoaded();
		}
		else
		{
			if (bMerge)
			{
				// We have to merge because the file already exists
				POSITION posClone = pClone->GetFirstChild();
				/*while (posClone)
				{
					CNodeObject *pChild = pClone->GetNextChild(posClone);
					CNodeObject *pCloneChild = pChild->Clone(this,oldName,newName);

					//m_pNodeDisk->AddChild(pCloneChild);

					// This is the same code from Entry::Update to re-load a node
					POSITION pos1,pos = this->GetFirstChild();
					pos1 = pos;
					while (pos)
					{
						// Find the duplicate node in the existing node to the clone node
						CNodeDataValue *pNode = (CNodeDataValue *)this->GetNextChild(pos);
						CString name1 = pCloneChild->GetName();
						CString name2 = pNode->GetName();
						name1.MakeLower();
						name2.MakeLower();
						if (name1 == name2)
						{
							CString str = pNode->GetName();
							// Copy to a temp map
							CMapPtrToPtr map;
							POSITION pos2 = pNode->m_mapViewHandles.GetStartPosition();
							while (pos2)
							{
								HANDLE key;
								HANDLE value;
								pNode->m_mapViewHandles.GetNextAssoc(pos2,key,value);
								map[key] = value;
							}	
							CNodeObject *pObj = RemoveChild(pos1);
							//pNode = CreateChild(this,(int)value,str);

							// Copy back to new map to the clone
							pos2 = map.GetStartPosition();
							while (pos2)
							{
								HANDLE key;
								HANDLE value;
								map.GetNextAssoc(pos2,key,value);
								pCloneChild->m_mapViewHandles[key] = value;
							}	
							m_pNodeDisk->AddChild(pCloneChild);
							m_pNodeDisk->m_bDirty = true;
						}
						pos1 = pos;
					}
				}*/
			}
		}
	}

	if (m_pNodeDisk->IsLoaded())
	{
		POSITION pos = m_pNodeDisk->GetFirstChild();
		while (pos)
		{
			// Already Loaded - Be sure that subclass checks for that it is loaded before it adds children
			CNodeObject *pChild = m_pNodeDisk->GetNextChild(pos);
			AddChild(pChild);

			// Might need to update this notation file
			if (m_pNodeDisk->m_bDirty)
			{
				// This child will need to be updated by the subclass constructor
				// TODO: This file is either an ERF or notation file (most likely)
				// pChild->m_bDirty = true;

				// The child may or may not be Visited (if it's children are dirty, then it will probably be dirty too
				int x=1;
			}
		}
	}
}

CNodeDataValueFile::~CNodeDataValueFile()
{
	if (m_pNodeDisk)
	{
		CNodeObject *pObj = m_pNodeDisk->RemoveRef(this);
	}
	m_pNodeDisk = NULL;
}

int CNodeDataValueFile::UpdateSelf(CNodeObject *pChild)
{
	Verify(false);
	// Not Implemented
	return 0;
}

int CNodeDataValueFile::GetName(CString &str)
{
	return CNodeDataValue::GetName(str);
}

int CNodeDataValueFile::GetName(char *buf,int buflen)
{
	CString extra;
	if (m_szName)
		extra = m_szName;

	CNodeObject *pDisk = GetNodeDisk();
	CString path;
	if (pDisk)
	{
		pDisk->GetName(path);
		pDisk = pDisk->GetParentNode();
		int count = m_iParentDirs;
		while (count && pDisk)
		{
			CString dir;
			pDisk->GetName(dir);
			count--;
			pDisk = pDisk->GetParentNode();
			//path += ((count && pDisk)?"\\":"")+dir;
			path = dir+"\\"+path;
		}
	}
	path += extra;
	strncpy(buf,path,buflen);
	return path.GetLength();
}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueFloat
//////////////////////////////////////////////////////////////////////

CNodeDataValueFloat::CNodeDataValueFloat(CNodeObject *pParent,CString value,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValue(pParent,value,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEFLOAT;
	m_iKeyType = KEYTYPE_FLOAT;
}

CNodeDataValueFloat::~CNodeDataValueFloat()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValuePoint3
//////////////////////////////////////////////////////////////////////

CNodeDataValuePoint3::CNodeDataValuePoint3(CNodeObject *pParent,CString value,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValue(pParent,value,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEPOINT3;
	m_iKeyType = KEYTYPE_POINT3;
}

CNodeDataValuePoint3::~CNodeDataValuePoint3()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueBool
//////////////////////////////////////////////////////////////////////

CNodeDataValueBool::CNodeDataValueBool(CNodeObject *pParent,CString value,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValue(pParent,value,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEBOOL;
	m_iKeyType = KEYTYPE_BOOL;
}

CNodeDataValueBool::~CNodeDataValueBool()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueString
//////////////////////////////////////////////////////////////////////

CNodeDataValueString::CNodeDataValueString(CNodeObject *pParent,CString value,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValue(pParent,value,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUESTRING;
	m_iKeyType = KEYTYPE_STRING;
}

CNodeDataValueString::~CNodeDataValueString()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueInt
//////////////////////////////////////////////////////////////////////

CNodeDataValueInt::CNodeDataValueInt(CNodeObject *pParent,CString value,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValue(pParent,value,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEINT;
	m_iKeyType = KEYTYPE_INT;
}

CNodeDataValueInt::~CNodeDataValueInt()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueCompostTexture
//////////////////////////////////////////////////////////////////////

CNodeDataValueCompostTexture::CNodeDataValueCompostTexture(CNodeObject *pParent,CString value,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValue(pParent,value,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUECOMPOSTTEXTURE;
	m_iKeyType = KEYTYPE_COMPOSTTEXTURE;
	CNodeObject *pChild1 = CreateChild(this,KEYTYPE_TGA,value);
	AddChild(pChild1);
	CNodeObject *pChild2 = CreateChild(this,KEYTYPE_BID,value);
	AddChild(pChild2);
}

CNodeDataValueCompostTexture::~CNodeDataValueCompostTexture()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueFileProject
//		Notes:  Disk File is a directory, this directory is the 
//		working directory for the project
//				Project cannot be a child of any other node (must be root)				
//////////////////////////////////////////////////////////////////////

CNodeDataValueFileProject::CNodeDataValueFileProject(CNodeDataValueFileDoc *pDoc,CString name) : CNodeDataValueFile(NULL,name)
{
	m_iKeyType = KEYTYPE_PROJECT;
	m_iClassID = CLASS_CNODEDATAVALUEFILEPROJECT;
	m_pDoc = pDoc;
}

CNodeDataValueFileProject::~CNodeDataValueFileProject()
{
}

int CNodeDataValueFileProject::UpdateSelf(CNodeObject *pChild)
{
	Verify(false);
	// Not Implemented
	return 0;
}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueFileERF
//////////////////////////////////////////////////////////////////////

// Dont clone erf data, reload the erf, change the names along the way, and save back out
CNodeDataValueFileERF::CNodeDataValueFileERF(CNodeObject *pParent,CString path,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueFile(pParent,path,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEFILEERF;
	m_iKeyType = KEYTYPE_ERF;
	ElementRenderer::GroupElement *pScene = NULL;

	CNodeDisk *pDisk = GetNodeDisk();
//	ElementRenderer::GroupElement *ErfElement=NULL;
	ElementRenderer::Element *ErfElement=NULL;
	// Check that this is not already loaded
	if (pDisk)
	{
		CString fname = GetRootPath()+"\\"+pDisk->GetPath();

		//if (pClone&&pDisk->m_bDirty)
		if (pDisk->m_bDirty)
		{
			// Gonna need to re-save this erf!
			// Delete all of the children of this ERF
			POSITION pos;
			pos = GetFirstChild();
			POSITION pos1 = pos;
			while (pos)
			{
				CNodeObject *pNode = GetNextChild(pos);
				RemoveChild(pos1);
				pos1 = pos;
			}

			pos1 = pos = pDisk->GetFirstChild();
			while (pos)
			{
				CNodeObject *pNode = pDisk->GetNextChild(pos);
				pDisk->RemoveChild(pos1);
				pos1 = pos;
			}

			DWORD attrib = ::GetFileAttributes(fname);
			if (-1 != attrib)
			{
				if (attrib & FILE_ATTRIBUTE_READONLY)
				{
					attrib &= ~FILE_ATTRIBUTE_READONLY;
					::SetFileAttributes(fname,attrib);
				}
			}
			// The children will remove all references to it automatically, including the disk
			//      But the disk file node will still remain because it has a parent directory
			// So Don't remove the reference to the disk file, it should even have the correct name

			// Then Load the ERF it again, but pass in oldName and newName to CNodeDataValueERF::CreateChild
			//      So that texture names will get changed.
			// Then save the ERF to a .temp name, close the streams, copy the temp erf over the old one, and delete the temp
		}

		// VERY IMPORTANT: erf_file must be open to write out temp_erf_file a file (according to JM)
		CString tempname = fname+".temp";
		if (pDisk->IsFound())
		{
			CPtrList elemList;
			elemList.RemoveAll();
			Stuff::FileStream erf_file;
			Stuff::FileStream temp_erf_file;
			erf_file.Open(fname);
			//erf_file.IgnoreReadOnly(true);
			//erf_file.Open(fname,Stuff::FileStream::WriteOnly);

			//if (!pDisk->IsLoaded() || (pClone &&pDisk->m_bDirty))
			if (!pDisk->IsLoaded() || (pDisk->m_bDirty))
			{
				pScene = new ElementRenderer::GroupElement;
				Check_Object(pScene);
				pScene->SetRootMode();
				pScene->LockBounds();

				int version = ElementRenderer::ReadERFVersion(&erf_file);
				while(erf_file.GetBytesRemaining() > 0)
				{
					ErfElement =
						ElementRenderer::Element::Create(
						&erf_file,
						version
//						ElementRenderer::ReadERFVersion(&erf_file)
						);
//					ErfElement = Cast_Object(
//							ElementRenderer::GroupElement*,
//						ElementRenderer::Element::Create(
//						&erf_file,
//						ElementRenderer::ReadERFVersion(&erf_file)
//						));
					elemList.AddTail(ErfElement);
					ErfElement->LockBounds();
					pScene->AttachChild(ErfElement);
					ErfElement->ClearAlignX();
					ErfElement->SetNeverCullMode();
					ErfElement->SetLocalToParent(Stuff::LinearMatrix4D::Identity);
					// this should also change the texture names if necessary
					CNodeDataValueERF *pChild = CNodeDataValueERF::CreateChild(this,ErfElement,oldName,newName);
					//erf_file.Close();
					AddChild(pChild);
					pDisk->AddChild(pChild);
				}
				pScene->Sync();

			}
			
			pDisk->SetLoaded();

			if (pClone)
			{
				if (pDisk->m_bDirty)
				{
					temp_erf_file.Open(tempname,Stuff::FileStream::WriteOnly);
//					ErfElement->SetRootMode();
					ElementRenderer::WriteERFVersion(&temp_erf_file);
//					ErfElement->Save(&temp_erf_file);
//					ErfElement->SetVolumeCullMode();
//					ErfElement->Sync();
					// loop through the scene and write out the children
					POSITION pos = elemList.GetHeadPosition();
					while (pos && ((ErfElement = Cast_Object(
							ElementRenderer::Element*, elemList.GetNext(pos))) != NULL))
					{
						ErfElement->Save(&temp_erf_file);
					}
					//erf_file.Close();
				}
			}

			// Clean up.  We don't need the scene anymore
			if (pScene)
			{
				Check_Object(pScene);
				delete pScene;
			}
			pScene = NULL;
		}
		if (pClone&&pDisk->m_bDirty)
		{
			::CopyFile(tempname,fname,false);
			::DeleteFile(tempname);
		}
	}
}

CNodeDataValueFileERF::~CNodeDataValueFileERF()
{
}

int CNodeDataValueFileERF::UpdateSelf(CNodeObject *pChild)
{
	Verify(false);
	// Not Implemented
	return 0;
}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueFileWAV
//////////////////////////////////////////////////////////////////////

CNodeDataValueFileWAV::CNodeDataValueFileWAV(CNodeObject *pParent,CString path,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueFile(pParent,path,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEFILEWAV;
	m_iKeyType = KEYTYPE_WAV;
	CNodeDisk *pDisk = GetNodeDisk();
	if (pDisk)
		pDisk->SetLoaded();
}

CNodeDataValueFileWAV::~CNodeDataValueFileWAV()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueFileMW4ANIM
//////////////////////////////////////////////////////////////////////

CNodeDataValueFileMW4ANIM::CNodeDataValueFileMW4ANIM(CNodeObject *pParent,CString value,CNodeObject *pClone,CString oldName,CString newName) 
: CNodeDataValueFile(pParent,pClone?pClone->GetNameStr():value+".mw4anim",pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEFILEMW4ANIM;
	m_iKeyType = KEYTYPE_MW4ANIM;
	CNodeDisk *pDisk = GetNodeDisk();
	if (pDisk)
		pDisk->SetLoaded();
}

CNodeDataValueFileMW4ANIM::~CNodeDataValueFileMW4ANIM()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueFileTGA
//////////////////////////////////////////////////////////////////////

CString CNodeDataValueFileTGA::GetTexturePath()
{
	Stuff::MString name;
	MidLevelRenderer::MLRTexturePool::Instance->GetGOSImagePool()->GetTexturePath(&name);
	CString strName = (char *)name;
	strName.Delete(0,1);
	return strName;
}

CString CNodeDataValueFileTGA::FixName(CString value,CNodeObject *pClone)
{
	CString str;
//	pClone?pClone->GetNameStr():value+((strnicmp(value.Right(4),".tga",4)==0)?"":".tga")
	if (pClone)
	{
		str = pClone->GetNameStr();
	}
	else
	{
		str = value;
	}
	if (strnicmp(str.Right(4),".tga",4))
		str+=".tga";
/*	CString tex = GetTexturePath();
	if (strnicmp(str,tex,tex.GetLength()))
	{
		str = tex+"\\"+str;
	}	*/
	return str;
}

CNodeDataValueFileTGA::CNodeDataValueFileTGA(CNodeObject *pParent,CString value,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueFile(pParent,FixName(value,pClone),pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEFILETGA;
	m_iKeyType = KEYTYPE_TGA;
	CNodeDisk *pDisk = GetNodeDisk();
	if (pDisk)
	{
		if (pDisk->IsFound())
		{
			pDisk->SetLoaded();
		}
		else
		{
			CNodeObject *pRoot = pParent;
			CNodeDataValueFileDoc *pDoc = NULL;
			while (pRoot && pRoot->GetClassID() != CLASS_CNODEDATAVALUEFILEPROJECT)
				pRoot = pRoot->GetParentNode();
			if (pRoot)
				pDoc = ((CNodeDataValueFileProject *)pRoot)->GetDocument();
			CString strFileName;
			pDisk->GetName(strFileName);
			strFileName = GetTexturePath()+"\\"+strFileName;
			CNodeDisk *pNewDisk = pDoc->FindDirectoryNode(strFileName);
			if (pNewDisk)
			{
				pDisk = (CNodeDisk *)pDisk->RemoveRef(this);
				pNewDisk->AddRef(this);
				pNewDisk->SetLoaded();
				SetNodeDisk(pNewDisk);
			}
		}
	}
	int rcount;// = value.Replace(oldName,newName);
	CString output = ReplaceNoCase(value,oldName,newName,&rcount);
	if (rcount)
	{
		int x=1;
	}
}

CNodeDataValueFileTGA::~CNodeDataValueFileTGA()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueFilePNG
//////////////////////////////////////////////////////////////////////

CString CNodeDataValueFilePNG::GetTexturePath()
{
	Stuff::MString name;
	MidLevelRenderer::MLRTexturePool::Instance->GetGOSImagePool()->GetTexturePath(&name);
	CString strName = (char *)name;
	strName.Delete(0,1);
	return strName;
}

CString CNodeDataValueFilePNG::FixName(CString value,CNodeObject *pClone)
{
	CString str;
//	pClone?pClone->GetNameStr():value+((strnicmp(value.Right(4),".png",4)==0)?"":".png")
	if (pClone)
	{
		str = pClone->GetNameStr();
	}
	else
	{
		str = value;
	}
	if (strnicmp(str.Right(4),".png",4))
		str+=".png";
/*	CString tex = GetTexturePath();
	if (strnicmp(str,tex,tex.GetLength()))
	{
		str = tex+"\\"+str;
	}	*/
	return str;
}

CNodeDataValueFilePNG::CNodeDataValueFilePNG(CNodeObject *pParent,CString value,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueFile(pParent,FixName(value,pClone),pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEFILEPNG;
	m_iKeyType = KEYTYPE_PNG;
	CNodeDisk *pDisk = GetNodeDisk();
	if (pDisk)
	{
		if (pDisk->IsFound())
		{
			pDisk->SetLoaded();
		}
		else
		{
			CNodeObject *pRoot = pParent;
			CNodeDataValueFileDoc *pDoc = NULL;
			while (pRoot && pRoot->GetClassID() != CLASS_CNODEDATAVALUEFILEPROJECT)
				pRoot = pRoot->GetParentNode();
			if (pRoot)
				pDoc = ((CNodeDataValueFileProject *)pRoot)->GetDocument();
			CString strFileName;
			pDisk->GetName(strFileName);
			strFileName = GetTexturePath()+"\\"+strFileName;
			CNodeDisk *pNewDisk = pDoc->FindDirectoryNode(strFileName);
			if (pNewDisk)
			{
				pDisk = (CNodeDisk *)pDisk->RemoveRef(this);
				pNewDisk->AddRef(this);
				pNewDisk->SetLoaded();
				SetNodeDisk(pNewDisk);
			}
		}
	}
	int rcount;// = value.Replace(oldName,newName);
	CString output = ReplaceNoCase(value,oldName,newName,&rcount);
	if (rcount)
	{
		int x=1;
	}
}

CNodeDataValueFilePNG::~CNodeDataValueFilePNG()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueFileNote
//////////////////////////////////////////////////////////////////////

CNodeDataValueFileNote::CNodeDataValueFileNote(CNodeObject *pParent,CString value,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueFile(pParent,value,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEFILENOTE;
	m_iKeyType = KEYTYPE_NOTE;

	CStringList listPageName,listPageEntry,listPageValue;
	CStringList listDep;
	CPtrList listPageNum;

	listPageName.RemoveAll();
	listPageEntry.RemoveAll();
	listPageValue.RemoveAll();
	listDep.RemoveAll();
	listPageNum.RemoveAll();

	CNodeObject *pNodeDep = NULL;

	CNodeDisk *pDisk = GetNodeDisk();
	if (pDisk && !pDisk->IsLoaded() && pDisk->IsFound())
	{
		// If this file was found, it may be loaded already
		// Check that this file isn't already loaded
		// First time, not loaded
		CString strRoot = GetRootPath()+"\\";
		CString strFileName = strRoot+pDisk->GetPath();
		NotationFile notefile(strFileName);

		NotationFile::PageIterator *pages = notefile.MakePageIterator();
		Check_Object(pages);

		DWORD pagenum = 0;
		Page *page;
		while((page = pages->ReadAndNext()) != NULL)
		{
			Check_Object(page);

			Page::NoteIterator *notes = page->MakeNoteIterator();
			Check_Object(notes);
			Note *note;
			while (note = notes->ReadAndNext())
			{
				const char *value;
				listPageName.AddTail(page->GetName());
				listPageEntry.AddTail(note->GetName());
				note->GetEntry(&value);
				listPageValue.AddTail(value);

				listPageNum.AddTail((LPVOID)pagenum);
			}
			delete notes;
			pagenum++;

#if 0
			CNodeDataPage *pChild = new CNodeDataPage(this,page,"","","");
			CMainFrame *pFrame = (CMainFrame*)AfxGetMainWnd();
			pFrame->SetMessageText(value);
			AddChild(pChild);
			pDisk->AddChild(pChild);
#endif
		}

		Check_Object(pages);
		delete pages;

		// Load the dependencies
		pNodeDep = new CNodeObject(this,"Dependencies");
		AddChild(pNodeDep);
		pDisk->AddChild(pNodeDep);
		FileDependencies dep(*notefile.GetFileDependencies());
		int length = dep.m_fileNameStream.GetBytesUsed();
		BYTE *data = static_cast<BYTE*>(dep.m_fileNameStream.GetPointer()) - length;
		while (length)
		{
			CString str = CString(data);
			int len = str.GetLength()+1;
			data += len;
			length -= len;
			CString str1 = this->GetRootPath()+"\\"+pDisk->GetPath();
			if (strnicmp(str1,str,(len-1)))
			{
				listDep.AddTail(str);
#if 0
				CNodeObject *pChild = this->CreateChild(pNodeDep,KEYTYPE_NOTE,str);
				pNodeDep->AddChild(pChild);
#endif
			}
		}
		if (pDisk)
			pDisk->SetLoaded();
	}
	
	if (listPageName.GetCount())
	{
		DWORD pagenum = 0;
		CNodeDataPage *pChild = NULL;
		/*
		int count = listPageName.GetCount();
		for (int index = 0;index<count;index++)
		{
			POSITION pos = listPageName.FindIndex(index);
			CString page = listPageName.GetAt(pos);
			pos = listPageEntry.FindIndex(index);
			CString entry = listPageEntry.GetAt(pos);
			pos = listPageValue.FindIndex(index);
			CString value = listPageValue.GetAt(pos);

			pos = listPageNum.FindIndex(index);
			DWORD newpage = (DWORD)listPageNum.GetAt(pos);
			if ((newpage != pagenum) || (NULL == pChild))
			{
				pChild = new CNodeDataPage(this,NULL,page,entry,value);
				AddChild(pChild);
				pDisk->AddChild(pChild);
				pagenum = newpage;
			}
			else
			{
				CNodeDataEntry *pEntry= new CNodeDataEntry(pChild,NULL,entry,value);
				pChild->AddChild(pEntry);
			}
		}*/
		POSITION namepos = listPageName.GetTailPosition();
		POSITION entrypos = listPageEntry.GetTailPosition();
		POSITION valuepos = listPageValue.GetTailPosition();
		POSITION numpos = listPageNum.GetTailPosition();
		while (namepos)
		{
			CString page = listPageName.GetPrev(namepos);
			CString entry = listPageEntry.GetPrev(entrypos);
			CString value = listPageValue.GetPrev(valuepos);
			DWORD newpage = (DWORD)listPageNum.GetPrev(numpos);
			if ((newpage != pagenum) || (NULL == pChild))
			{
				pChild = new CNodeDataPage(this,NULL,page,entry,value);
				AddChild(pChild);
				pDisk->AddChild(pChild);
				pagenum = newpage;
			}
			else
			{
				CNodeDataEntry *pEntry= new CNodeDataEntry(pChild,NULL,entry,value);
				pChild->AddChild(pEntry);
			}
		}
	}

	if (pNodeDep)
	{
		POSITION pos = listDep.GetHeadPosition();
		while (pos)
		{
			CString str = listDep.GetNext(pos);
			CNodeObject *pChild = this->CreateChild(pNodeDep,KEYTYPE_NOTE,str);
			pNodeDep->AddChild(pChild);
		}
	}

	if (pClone)
	{	
		// If the disk node is dirty, then the dirty children need to be updated
		if (pDisk->IsFound() && pDisk->m_bDirty)
		{
			CString strRoot = GetRootPath()+"\\";
			CString strFileName = strRoot+pDisk->GetPath();
			DWORD attrib = ::GetFileAttributes(strFileName);
			if (attrib & FILE_ATTRIBUTE_READONLY)
			{
				attrib &= ~FILE_ATTRIBUTE_READONLY;
				::SetFileAttributes(strFileName,attrib);
			}

			//****** Gonna have to write the whole file over again because we didnt' keep the old page name so 
			// don't know which page to rename if the page name changed
			// Note: Write stuff the pages in reverse order to restore to original order

			NotationFile notefile;

			pDisk->m_bDirty = false;
			POSITION pos = GetFirstChild();
			while (pos)
			{
				CNodeObject *pPage = GetNextChild(pos);
				if (pPage->GetClassID() == CLASS_CNODEDATAPAGE)
				{
					CString str;
					pPage->GetName(str);
					Page *page = notefile.AddPage(str);

					// Get first here because the entry are appended in the page
					POSITION posentry = pPage->GetFirstChild();
					while (posentry)
					{
						CNodeObject *pEntry = pPage->GetNextChild(posentry);
						// First or last here, doesn't matter because each entry should have only one value
						POSITION posvalue = pEntry->GetFirstChild();
						while (posvalue)
						{
							CNodeObject *pValue = pEntry->GetNextChild(posvalue);
							CString str;
							pValue->GetName(str);
							CString str1;
							pEntry->GetName(str1);
							page->AppendEntry(str1,str);
						}
					}
				}
			}
			notefile.SaveAs(strFileName);
		}

		// Update the file by calling virual function this->UpdateSelf()
//				UpdateSelf(pChild);
//				m_pNodeDisk->m_bDirty = false;



		// Don't run this for now - m_bDirty maybe true if this node is renamed
		// TODO: Merge
		/*
		if (pDisk->m_bDirty)
		{
			// This node was merged during the cloning process, and now the file needs to be updated
			CString strFileName = pDisk->GetPath();
			NotationFile notefile(strFileName);
			if (notefile.IsEmpty())
			{
				// This should not happen
			//	assert(false);
				return;
			}

			// make sure all of the children of the pNodeDisk are there
			POSITION pos = pDisk->GetFirstChild();
			while (pos)
			{
				CNodeObject *pChild = pDisk->GetNextChild(pos);
				switch (pChild->GetClassID())
				{
				case CLASS_CNODEDATAPAGE:
					{
						CNodeDataPage *pPage = (CNodeDataPage *)pChild;
						Page *page = notefile.SetPage(pPage->GetName());

						POSITION posEntry = pPage->GetFirstChild();
						while (posEntry)
						{
							CNodeDataEntry *pEntry = (CNodeDataEntry *)pPage->GetNextChild(posEntry);
							POSITION posValue = pEntry->GetFirstChild();
							while (posValue)
							{
								CNodeObject *pValue = pEntry->GetNextChild(posValue);
								// Update/Add pPage,pEntry,pValue in the notefile
								page->SetEntry(pEntry->GetName(),pValue->GetName());
							}
						}
						break;
					}
				case CLASS_CNODEOBJECT:
					{
						// Child is a dependency, these are the !INCLUDE parameters
						POSITION posValue = pChild->GetFirstChild();
						while (posValue)
						{
							CNodeObject *pValue = pChild->GetNextChild(posValue);
							CString strName = pValue->GetName();
							// don't Save a !Include as the pValue file because this should already be there
						}
						break;
					}
				default:
					{
						Verify(false);
					}
				}
			}
			notefile.Save();
		}*/
	}
}

CNodeDataValueFileNote::~CNodeDataValueFileNote()
{

}

int CNodeDataValueFileNote::UpdateSelf(CNodeObject *pChild)
{
	Verify(false);
	// Not Implemented
	return 0;
}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueFileBSP
//////////////////////////////////////////////////////////////////////

CNodeDataValueFileBSP::CNodeDataValueFileBSP(CNodeObject *pParent,CString value,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueFile(pParent,pClone?pClone->GetNameStr():value+((strnicmp(value.Right(4),".bsp",4)==0)?"":".bsp"),pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEFILEBSP;
	m_iKeyType = KEYTYPE_BSP;
	CNodeDisk *pDisk = GetNodeDisk();
	if (pDisk)
		pDisk->SetLoaded();
}

CNodeDataValueFileBSP::~CNodeDataValueFileBSP()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueFileOBB
//////////////////////////////////////////////////////////////////////

CNodeDataValueFileOBB::CNodeDataValueFileOBB(CNodeObject *pParent,CString value,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueFile(pParent,value,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEFILEOBB;
	m_iKeyType = KEYTYPE_OBB;
	CNodeDisk *pDisk = GetNodeDisk();
	if (pDisk)
		pDisk->SetLoaded();
}

CNodeDataValueFileOBB::~CNodeDataValueFileOBB()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueFileABL
//////////////////////////////////////////////////////////////////////

CNodeDataValueFileABL::CNodeDataValueFileABL(CNodeObject *pParent,CString value,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueFile(pParent,value,pClone,oldName,newName)
{
	m_iKeyType = KEYTYPE_ABL;
	m_iClassID = CLASS_CNODEDATAVALUEFILEABL;
	CNodeDisk *pDisk = GetNodeDisk();
	if (pDisk)
		pDisk->SetLoaded();
}

CNodeDataValueFileABL::~CNodeDataValueFileABL()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueFileFGD
//////////////////////////////////////////////////////////////////////
CString CNodeDataValueFileFGD::FixName(CString str)
{
	if (strnicmp(str.Right(4),".fgd",4))
		str += ".fgd";
	return str;
}

CNodeDataValueFileFGD::CNodeDataValueFileFGD(CNodeObject *pParent,CString value,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueFile(pParent,FixName(value),pClone,oldName,newName)
{
	m_iKeyType = KEYTYPE_FGD;
	m_iClassID = CLASS_CNODEDATAVALUEFILEFGD;
	CNodeDisk *pDisk = GetNodeDisk();
	if (pDisk)
		pDisk->SetLoaded();
}

CNodeDataValueFileFGD::~CNodeDataValueFileFGD()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueFileMATERIAL
//////////////////////////////////////////////////////////////////////

CNodeDataValueFileMATERIAL::CNodeDataValueFileMATERIAL(CNodeObject *pParent,CString value,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueFile(pParent,pClone?pClone->GetNameStr():value+((strnicmp(value.Right(9),".material",9)==0)?"":".material"),pClone,oldName,newName)
{
	m_iKeyType = KEYTYPE_MATERIAL;
	m_iClassID = CLASS_CNODEDATAVALUEFILEMATERIAL;
	CNodeDisk *pDisk = GetNodeDisk();
	if (pDisk)
		pDisk->SetLoaded();
}

CNodeDataValueFileMATERIAL::~CNodeDataValueFileMATERIAL()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueFileRAW
//////////////////////////////////////////////////////////////////////

CNodeDataValueFileRAW::CNodeDataValueFileRAW(CNodeObject *pParent,CString value,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueFile(pParent,pClone?pClone->GetNameStr():value+((strnicmp(value.Right(4),".raw",4)==0)?"":".raw"),pClone,oldName,newName)
{
	m_iKeyType = KEYTYPE_RAW;
	m_iClassID = CLASS_CNODEDATAVALUEFILERAW;
	CNodeDisk *pDisk = GetNodeDisk();
	if (pDisk)
		pDisk->SetLoaded();
}

CNodeDataValueFileRAW::~CNodeDataValueFileRAW()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueFileRAW
//////////////////////////////////////////////////////////////////////

CNodeDataValueFileBID::CNodeDataValueFileBID(CNodeObject *pParent,CString value,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueFile(pParent,pClone?pClone->GetNameStr():value+((strnicmp(value.Right(4),".bid",4)==0)?"":".bid"),pClone,oldName,newName)
{
	m_iKeyType = KEYTYPE_BID;
	m_iClassID = CLASS_CNODEDATAVALUEFILEBID;
	CNodeDisk *pDisk = GetNodeDisk();
	if (pDisk)
		pDisk->SetLoaded();
}

CNodeDataValueFileBID::~CNodeDataValueFileBID()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueFileResource
//////////////////////////////////////////////////////////////////////
extern int IdentifyFileType(CString path);
CNodeDataValueFileResource::CNodeDataValueFileResource(CNodeObject *pParent,CString value) : CNodeDataValueFile(pParent,value)
{
	m_iKeyType = KEYTYPE_RESOURCE;
	m_iClassID = CLASS_CNODEDATAVALUEFILERESOURCE;

	CStringList nameList;

	CNodeDisk *pDisk = GetNodeDisk();
	if (pDisk)
	{
		CMainFrame *pFrame = (CMainFrame*)AfxGetMainWnd();
		pFrame->SetMessageText("Loading Resources: "+pDisk->GetPath());

		Check_Object(ResourceManager::Instance);
		ResourceFile *pResourceFile = ResourceManager::Instance->OpenResourceFile(
			pDisk->GetPath(),
			0,
			VER_CONTENTVERSION,
			true,
			true,
			false
		);
		Check_Object(pResourceFile);
//		pResourceFile->First();

		Resource res;
		res.First(pResourceFile);

		while (res.ReadAndNext())
		{
			CNodeObject *pNode = NULL;
			int iKeyType = KEYTYPE_UNKNOWN;

			CString name = CString("Content\\")+res.GetName();
			int index = name.Find('{');
			if (index>=0)
			{
				// We have the Entry name
				CString entryname = name.Right(name.GetLength()-index-1);
				name = name.Left(index);
				int index1 = entryname.Find('}');
				// This should exist
				assert(index1>=0);
				entryname = entryname.Left(index1);

				int pageindex = name.Find('[');
				if (pageindex>=0)
				{
					CString pagename = name.Right(name.GetLength()-pageindex-1);
					name = name.Left(pageindex);
					index1 = pagename.Find(']');
					// This should exist
					assert(index1>=0);
					pagename = pagename.Left(index1);

					pNode = new CNodeDataPage(this,NULL,pagename,entryname,name);
				}
				else
					pNode = new CNodeDataEntry(this,NULL,entryname,name);
				AddChild(pNode);
				pDisk->AddChild(pNode);
			}
			else
			{
				index = name.Find('[');
				if (index>=0)
				{
					name = name.Left(index);
				}
				nameList.AddHead(name);
			}
		}
		pDisk->SetLoaded();
	}
	POSITION pos = nameList.GetHeadPosition();
	while (pos)
	{
		CNodeObject *pNode = NULL;
		int iKeyType = KEYTYPE_UNKNOWN;

		CString str = nameList.GetNext(pos);
		if (KEYTYPE_UNKNOWN == iKeyType)
			iKeyType = IdentifyFileType(str);
		pNode = CreateChild(this,iKeyType,str);
		AddChild(pNode);
		pDisk->AddChild(pNode);
	}
}

CNodeDataValueFileResource::~CNodeDataValueFileResource()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueERF
//////////////////////////////////////////////////////////////////////

CNodeDataValueERF *CNodeDataValueERF::CreateChild(CNodeObject *pParent,ElementRenderer::Element *pElement,CString oldName,CString newName)
{
	if(pElement->GetClassID()== ElementRenderer::CameraElementClassID)
	{
		return NULL;
	}

	CNodeDataValueERF *pChild = NULL;
	switch(pElement->GetClassID())
	{
	/*
	case ElementRenderer::FXElementClassID:
	{
	}
	break;
		*/
	case ElementRenderer::GroupElementClassID:
		{	
			ElementRenderer::GroupElement *group = Cast_Pointer(ElementRenderer::GroupElement *, pElement);
			pChild = new CNodeDataValueERFGroupElement(pParent,group,NULL,oldName,newName);
		}
		break;
	case ElementRenderer::ListElementClassID:
		{
			ElementRenderer::ListElement *group = Cast_Pointer(ElementRenderer::ListElement *, pElement);
			pChild = new CNodeDataValueERFListElement(pParent,group,NULL,oldName,newName);
		}
		break;
		
	case ElementRenderer::GridElementClassID:
		{
			ElementRenderer::GridElement *group = Cast_Pointer(ElementRenderer::GridElement *, pElement);
			pChild = new CNodeDataValueERFGridElement(pParent,group,NULL,oldName,newName);
		}
		break;

	case ElementRenderer::LODElementClassID:
		{
			ElementRenderer::ListElement *group = Cast_Pointer(ElementRenderer::ListElement *, pElement);
			pChild = new CNodeDataValueERFLODElement(pParent,group,NULL,oldName,newName);
		}
		break;

/*	case ElementRenderer::ShapeLODElementClassID:
		{
			ElementRenderer::ListElement *group = Cast_Pointer(ElementRenderer::ListElement *, pElement);
			pChild = new CNodeDataValueERFShapeLODElement(pParent,group,NULL,oldName,newName);
		}
		break;
*/		
	case ElementRenderer::PointCloudElementClassID:
		{
		}
		break;
		
	case ElementRenderer::ScalableShapeElementClassID:
	case ElementRenderer::ShapeElementClassID:
		{
			ElementRenderer::ShapeElement *group = Cast_Pointer(ElementRenderer::ShapeElement *, pElement);
			pChild = new CNodeDataValueERFShapeElement(pParent,group,NULL,oldName,newName);
		}
		break;
		
	case ElementRenderer::ScreenQuadsElementClassID:
		{
		}
		break;
		
	case ElementRenderer::SwitchElementClassID:
		{
			ElementRenderer::ListElement *group = Cast_Pointer(ElementRenderer::ListElement *, pElement);
			pChild = new CNodeDataValueERFListElement(pParent,group,NULL,oldName,newName);
		}
		break;
		
	case ElementRenderer::TriangleCloudElementClassID:
		{
			Verify(false);
		}
		break;
	case ElementRenderer::MultiLODElementClassID:
		{
			ElementRenderer::MultiLODElement *group = Cast_Pointer(ElementRenderer::MultiLODElement *, pElement);
			
			assert(false);

			for(int i=0;i<group->GetActiveCount();i++)
			{
			//	AddErfBranch(tmpitm,group->GetIndexedElement(i));
			}	
		}
		break;
	case ElementRenderer::ShapeLODElementClassID:
		{
			ElementRenderer::ShapeLODElement *group = Cast_Pointer(ElementRenderer::ShapeLODElement *, pElement);
			pChild = new CNodeDataValueERFShapeLODElement(pParent,group,NULL,oldName,newName);
		}
		break;
	}
	return pChild;
}

// either pElement or pClone must be valid
CNodeDataValueERF::CNodeDataValueERF(CNodeObject *pParent,ElementRenderer::Element *pElement,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValue(pParent,pClone?pClone->GetNameStr():CString(pElement->GetClassData()->GetClassName()),pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEERF;


	m_pElement = pElement;

	if (pClone)
	{
		CNodeDataValueERF *pErf = (CNodeDataValueERF *)pClone;
		m_pElement = pErf->GetElement();
		return;
	}
	ElementRenderer::StateChange *pState = pElement->GetStateChange();
	if (pState)
	{
		MidLevelRenderer::MLRState state = pState->GetMLRState();
		MidLevelRenderer::MLRTexture *tex = NULL;		
		if	(MidLevelRenderer::MLRTexturePool::Instance &&
			(state.GetTextureHandle() < MidLevelRenderer::Limits::Max_Number_Textures * (1<<MidLevelRenderer::MLRTexturePool::Instance->GetInstanceDepth()))
			)
		{
			if(state.GetTextureHandle())
			{
				CString strName;
				char name1[MAX_PATH];
				_splitpath(strName,NULL,NULL,name1,NULL);
				if((tex = (*MidLevelRenderer::MLRTexturePool::Instance)[&state]) != NULL)
				{
					strName = CNodeDataValueFileTGA::GetTexturePath()+"\\"+tex->GetTextureName();
					CNodeDataValueFile *pChild = new CNodeDataValueFileTGA(this,strName,pClone,oldName,newName);
					if (pChild->GetNodeDisk()->IsFound())
 						AddChild(pChild);
					else
					{
						delete pChild;
						pChild = new CNodeDataValueFilePNG(this,strName,pClone,oldName,newName);
						AddChild(pChild);
					}
					char name2[MAX_PATH] = "";
					CString str;
					pChild->GetName(str);
					_splitpath(str,NULL,NULL,name2,NULL);
					if (strnicmp(name1,name2,strlen(name1)))
					{
						// The targa file changed names so we need to reflect this int the erf file
						MidLevelRenderer::MLRTexture *pNewTex = (*MidLevelRenderer::MLRTexturePool::Instance)(strName);
						if (NULL == pNewTex)
							pNewTex = MidLevelRenderer::MLRTexturePool::Instance->Add(strName);
						if (NULL == pNewTex)
						{
							// Why isn't this added?
							assert(false);
						}
						state.SetTextureHandle(pNewTex->GetTextureHandle());
						pState->SetMLRState(state);
					}
				}
			}
			else
			{
/*				tstr.Format("%c%c Texture=None",
					(state->GetRenderDeltaMask() & MidLevelRenderer::MLRState::TextureMask) ? 'D' : '0',
					(state->GetRenderPermissionMask() & MidLevelRenderer::MLRState::TextureMask) ? 'P' : '0');
				InfoCtrl->AddString(tstr);*/
			}
		}
		else
		{
			//InfoCtrl->AddString("?? Texture=Error");
		}
	}
}

CNodeDataValueERF::~CNodeDataValueERF()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueERFGroupElement
//////////////////////////////////////////////////////////////////////

CNodeDataValueERFGroupElement::CNodeDataValueERFGroupElement(CNodeObject *pParent,ElementRenderer::GroupElement *pElement,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueERF(pParent,pElement,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEERFGROUPELEMENT;

	if (pClone)
		return;

	Stuff::ChainIteratorOf<ElementRenderer::Element*> *children = pElement->MakeIterator();
	Check_Object(children);
	
	ElementRenderer::Element *child = NULL;
	while ((child = children->ReadAndNext()) != NULL)
	{
		CNodeDataValueERF *pChild = CreateChild(this,child,oldName,newName);
		AddChild(pChild);
	}
	Check_Object(children);
	delete children;	
}

CNodeDataValueERFGroupElement::~CNodeDataValueERFGroupElement()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueERFListElement
//////////////////////////////////////////////////////////////////////

CNodeDataValueERFListElement::CNodeDataValueERFListElement(CNodeObject *pParent,ElementRenderer::ListElement *pElement,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueERF(pParent,pElement,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEERFLISTELEMENT;

	if (pClone)
		return;

	for(int i=0;i<pElement->GetActiveCount();i++)
	{
		CNodeDataValueERF *pChild = CreateChild(this,pElement->GetIndexedElement(i),oldName,newName);
		AddChild(pChild);
	}				
}

CNodeDataValueERFListElement::~CNodeDataValueERFListElement()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueERFGridElement
//////////////////////////////////////////////////////////////////////

CNodeDataValueERFGridElement::CNodeDataValueERFGridElement(CNodeObject *pParent,ElementRenderer::GridElement *pElement,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueERF(pParent,pElement,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEERFGRIDELEMENT;

	if (pClone)
		return;

	unsigned char xSize, zSize;
	pElement->GetSize(&xSize, &zSize);
	while (pParent && !pParent->IsFile())
		pParent = pParent->GetParentNode();

	CString path = ((CNodeDataValueFileERF *)pParent)->GetNodeDisk()->GetPath();
	for(int i=0;i<zSize;i++)
		for(int j=0;j<xSize;j++)
		{
			CString strFileName;
			strFileName += ('A'+(char)i);
			strFileName += ('A'+(char)j);
			CNodeDataValueFileERF *pChild = new CNodeDataValueFileERF(this,strFileName+".erf",pClone,oldName,newName);
			AddChild(pChild);

#if 0
			CNodeDataValueERF *pChild1 = CreateChild(this,pElement->GetIndexedElement(i,j));
			AddChild(pChild1);
#endif
			CNodeDataValueFileBSP *pBspChild = new CNodeDataValueFileBSP(this,strFileName,pClone,oldName,newName);
			AddChild(pBspChild);

			CNodeDataValueFileMATERIAL *pMaterialChild = new CNodeDataValueFileMATERIAL(this,strFileName,pClone,oldName,newName);
			AddChild(pMaterialChild);
		}
/*	for(int i=0;i<pElement->GetActiveCount();i++)
	{
		CNodeDataValueERF *pChild = CreateChild(this,pElement->GetIndexedElement(i));
		AddChild(pChild);
	}				*/
}

CNodeDataValueERFGridElement::~CNodeDataValueERFGridElement()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueERFLODElement
//////////////////////////////////////////////////////////////////////

CNodeDataValueERFLODElement::CNodeDataValueERFLODElement(CNodeObject *pParent,ElementRenderer::ListElement *pElement,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueERF(pParent,pElement,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEERFLODELEMENT;

	if (pClone)
		return;

	for(int i=0;i<pElement->GetActiveCount();i++)
	{
		CNodeDataValueERF *pChild = CreateChild(this,pElement->GetIndexedElement(i),oldName,newName);
		AddChild(pChild);
	}				
}

CNodeDataValueERFLODElement::~CNodeDataValueERFLODElement()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueERFShapeLODElement
//////////////////////////////////////////////////////////////////////

CNodeDataValueERFShapeLODElement::CNodeDataValueERFShapeLODElement(CNodeObject *pParent,ElementRenderer::ShapeLODElement *pElement,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueERF(pParent,pElement,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEERFSHAPELODELEMENT;

	if (pClone)
		return;

	for(int i=0;i<pElement->GetSize();i++)
	{
		MidLevelRenderer::MLRShape *shape;
		const ElementRenderer::LODElement::Entry *entry;
		pElement->GetLOD(i,&shape,&entry);
		CNodeData *pChild1 = new CNodeData(pParent,shape->GetClassString(),pClone,oldName,newName);
		AddChild(pChild1);

		CString str;
		CNodeDataValue *pValue;
		pValue = pChild1->CreateChild(pChild1,KEYTYPE_STRING,"Far Squared");
		pChild1->AddChild(pValue);
		str.Format("%f",entry->m_farSquared);
		CNodeData *pData = pValue->CreateChild(pValue,KEYTYPE_FLOAT,str);
		pValue->AddChild(pData);

		pValue = pChild1->CreateChild(pChild1,KEYTYPE_STRING,"Near Squared");
		pChild1->AddChild(pValue);
		str.Format("%f",entry->m_nearSquared);
		pData = pValue->CreateChild(pValue,KEYTYPE_FLOAT,str);
		pValue->AddChild(pData);

		for(int i=0;i<shape->GetNum();i++)
		{
			CNodeDataValue *pChild = new CNodeDataValueMLRElement(pChild1,shape->Find(i),pClone,oldName,newName);
			pChild1->AddChild(pChild);
		}				

	//	pChild = new CNodeDataValueERFShapeLODElement(pParent,group,entry,NULL,oldName,newName);

		//HTREEITEM hChild = erftree->InsertItem((LPCSTR)(shape->GetClassString()), 0, 1, tmpitm, TVI_LAST);
		//erftree->SetItemData(hChild,(DWORD) shape);

		/*for(int j=0;j<shape->GetNum();j++)
		{
			CNodeObject *pChild1 = AddChild(pParent,shape->Find(j),oldName,newName);
		}*/	
	}

/*	for(int i=0;i<pElement->GetSize();i++)
	{
		CNodeDataValueERF *pChild = CreateChild(this,pElement->Find(i),oldName,newName);
		AddChild(pChild);
	}				*/
}

CNodeDataValueERFShapeLODElement::~CNodeDataValueERFShapeLODElement()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueERFShapeElement
//////////////////////////////////////////////////////////////////////

CNodeDataValueERFShapeElement::CNodeDataValueERFShapeElement(CNodeObject *pParent,ElementRenderer::ShapeElement *pElement,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueERF(pParent,pElement,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEERFSHAPEELEMENT;

	if (pClone)
		return;

	MidLevelRenderer::MLRShape *shape=pElement->GetMLRShape();	
			
	for(int i=0;i<shape->GetNum();i++)
	{
		CNodeDataValue *pChild = new CNodeDataValueMLRElement(this,shape->Find(i),pClone,oldName,newName);
		AddChild(pChild);
	}				
}

CNodeDataValueERFShapeElement::~CNodeDataValueERFShapeElement()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueERFSwitchElement
//////////////////////////////////////////////////////////////////////

CNodeDataValueERFSwitchElement::CNodeDataValueERFSwitchElement(CNodeObject *pParent,ElementRenderer::ListElement *pElement,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValueERF(pParent,pElement,pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEERFSWITCHELEMENT;

	if (pClone)
		return;

	for(int i=0;i<pElement->GetActiveCount();i++)
	{
		CNodeDataValueERF *pChild = CreateChild(this,pElement->GetIndexedElement(i),oldName,newName);
		AddChild(pChild);
	}				
}

CNodeDataValueERFSwitchElement::~CNodeDataValueERFSwitchElement()
{

}

//////////////////////////////////////////////////////////////////////
// CNodeDataValueERFMLRElement
//////////////////////////////////////////////////////////////////////

CNodeDataValueMLRElement::CNodeDataValueMLRElement(CNodeObject *pParent,MidLevelRenderer::MLRPrimitiveBase *pPrim,CNodeObject *pClone,CString oldName,CString newName) 
	: CNodeDataValue(pParent,pClone?pClone->GetNameStr():CString(pPrim->GetClassData()->GetClassName()),pClone,oldName,newName)
{
	m_iClassID = CLASS_CNODEDATAVALUEMLRELEMENT;

	m_pPrimitave = pPrim;

	if (pClone)
	{
		CNodeDataValueMLRElement *pEle = (CNodeDataValueMLRElement *)pClone;
		m_pPrimitave = pEle->GetPrimitave();
		return;
	}

	MidLevelRenderer::MLRState state;
	for(int i=0;i<pPrim->GetNumPasses();i++)
	{
		state = pPrim->GetReferenceState(i);
		MidLevelRenderer::MLRTexture *tex = NULL;		
		if	(MidLevelRenderer::MLRTexturePool::Instance &&
			(state.GetTextureHandle() < MidLevelRenderer::Limits::Max_Number_Textures * (1<<MidLevelRenderer::MLRTexturePool::Instance->GetInstanceDepth()))
			)
		{
			if(state.GetTextureHandle())
			{
				CString strName;
				if((tex = (*MidLevelRenderer::MLRTexturePool::Instance)[&state]) != NULL)
				{
					strName = tex->GetTextureName();

					//strName.MakeLower();
					int rcount;// = strName.Replace(oldName,newName);
					CString output = ReplaceNoCase(strName,oldName,newName,&rcount);
					strName = output;
					if (rcount)
					{
						MidLevelRenderer::MLRTexture *pNewTex = (*MidLevelRenderer::MLRTexturePool::Instance)(strName);
						if (NULL == pNewTex)
							pNewTex = MidLevelRenderer::MLRTexturePool::Instance->Add(strName);
						if (NULL == pNewTex)
						{
							// Why isn't this added?
							assert(false);
						}
						state.SetTextureHandle(pNewTex->GetTextureHandle());
						pPrim->SetReferenceState(state, i);
					}

					CString strFind = "1_0101";
					// Terrain - files are named NAME_XX_#_0#_0#.tga
					CString strRight = strName.Right(6);
					if (strFind == strRight)
					{
						// This is a terrain grid
						char fname[MAX_PATH],path[MAX_PATH];
						_splitpath(strName,NULL,path,fname,NULL);
						CString strFname(fname);
						CString prefix = CString(path)+strFname.Left(strFname.GetLength()-6);
						
						for (int x=0;x<2;x++)
						{
							for (int y=0;y<2;y++)
							{					
								CString strTga;
								strTga.Format("%s1_0%d0%d",prefix,y,x);
								strTga = CNodeDataValueFileTGA::GetTexturePath()+"\\"+strTga;
								CNodeDataValueFile *pChildTga = new CNodeDataValueFileTGA(this,strTga,pClone,oldName,newName);
								if (pChildTga->GetNodeDisk()->IsFound())
									AddChild(pChildTga);
								else
								{
									delete pChildTga;
									pChildTga = new CNodeDataValueFilePNG(this,strTga,pClone,oldName,newName);
									AddChild(pChildTga);
								}
							}
						}
						CString strTga;
						strTga.Format("%s0_0000",prefix);
						strTga = CNodeDataValueFileTGA::GetTexturePath()+"\\"+strTga;
						CNodeDataValueFile *pChildTga = new CNodeDataValueFileTGA(this,strTga,pClone,oldName,newName);
						if (pChildTga->GetNodeDisk()->IsFound())
							AddChild(pChildTga);
						else
						{
							delete pChildTga;
							pChildTga = new CNodeDataValueFilePNG(this,strTga,pClone,oldName,newName);
							AddChild(pChildTga);
						}
					}
					else
					{
						strName = CNodeDataValueFileTGA::GetTexturePath()+"\\"+strName;
						CNodeDataValueFile *pChild = new CNodeDataValueFileTGA(this,strName,pClone,oldName,newName);
						if (pChild->GetNodeDisk()->IsFound())
							AddChild(pChild);
						else
						{
							delete pChild;
							pChild = new CNodeDataValueFilePNG(this,strName,pClone,oldName,newName);
							AddChild(pChild);
						}
					}
				}
			}
			else
			{
/*				tstr.Format("%c%c Texture=None",
					(state->GetRenderDeltaMask() & MidLevelRenderer::MLRState::TextureMask) ? 'D' : '0',
					(state->GetRenderPermissionMask() & MidLevelRenderer::MLRState::TextureMask) ? 'P' : '0');
				InfoCtrl->AddString(tstr);*/
			}
		}
		else
		{
			//InfoCtrl->AddString("?? Texture=Error");
		}
	//MidLevelRenderer::MLRTexturePool::Instance->LoadImages();
	}

}

CNodeDataValueMLRElement::~CNodeDataValueMLRElement()
{

}