// NodeDataValueFileDoc.cpp : implementation file
//

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

#include <stuff\database.hpp>

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

CString g_szbrowsepath;
int CALLBACK BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
	RECT rect;
	//
	//Center the browse dialog on the screen...
	//
	switch (uMsg)
	{
	case BFFM_INITIALIZED:
		{
			SendMessage(hWnd,BFFM_SETSELECTION,TRUE,(LPARAM)(LPCTSTR)g_szbrowsepath);
	
			if (GetWindowRect(hWnd, &rect))
			{
				SetWindowPos(hWnd, 
							 HWND_TOP,
							 (GetSystemMetrics(SM_CXSCREEN) - (rect.right - rect.left)) >> 1,
							 (GetSystemMetrics(SM_CYSCREEN) - (rect.bottom - rect.top)) >> 1,
							 0,
							 0,
							 SWP_NOSIZE);
			}
		}
	}
	return 0;
}

CString BrowseDirectory(const char *strCurrent,CWnd *pWnd)
{
	CString str;
	TCHAR        szBuffer[MAX_PATH];
	LPITEMIDLIST pidlBrowse,pidlRoot;
	BROWSEINFO   bi;

	LPMALLOC lpMalloc;
	SHGetMalloc(&lpMalloc);
	ASSERT(lpMalloc);
	bi.hwndOwner = pWnd->GetSafeHwnd();
	// Get the ID for the "My Computer" root folder
	SHGetSpecialFolderLocation(pWnd->GetSafeHwnd(),CSIDL_DRIVES,&pidlRoot);

	bi.pidlRoot  = pidlRoot;
	bi.pszDisplayName = szBuffer;

	// Localize the descriptive text
	bi.lpszTitle = "Select a MW4 Game Root folder.  This folder should should have a Contents subdirectory.";

	// BIF_EDITBOX and BIF_VALIDATE are for versions 4.71 and later, they
	// might be ignored by older versions
	bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT;// | BIF_EDITBOX;// | BIF_USENEWUI;// | BIF_VALIDATE;
	bi.lParam = (LPARAM)pWnd;
	bi.iImage = NULL;
	bi.lpfn = BrowseCallbackProc;
	bi.lParam = (LPARAM)strCurrent;
	g_szbrowsepath = strCurrent;
	//
	//Call the Windows shell folder browsing routine...
	//
	pidlBrowse = SHBrowseForFolder(&bi);
	if (NULL != pidlBrowse)
	{
		if (SHGetPathFromIDList(pidlBrowse, szBuffer))
		{
			if ('\\' == szBuffer[lstrlen(szBuffer)-1])
				szBuffer[lstrlen(szBuffer)-1] = '\0';
			str = CString(szBuffer);
		}
		else
			str = "";
		//
		//Free up shell memory used...
		//
		lpMalloc->Free(pidlBrowse);
	}
	else
		str = "";
	lpMalloc->Free(pidlRoot);
	lpMalloc->Release();
	return str;
}

/////////////////////////////////////////////////////////////////////////////
// CNodeDataValueFileDoc

IMPLEMENT_DYNCREATE(CNodeDataValueFileDoc, CContentTrackDoc)

CNodeDataValueFileDoc::CNodeDataValueFileDoc()
{
	m_pNodeDataValueFileProject = NULL;
	m_pNodeDirectory = NULL;
	m_pActiveChild = NULL;
	m_iReplaceAll = -1;
}

BOOL CNodeDataValueFileDoc::OnNewDocument()
{
	if (!CContentTrackDoc::OnNewDocument())
		return FALSE;

/*	CFileDialog dlg(false,"*.project",NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,"*.project",NULL);
	if (IDOK == dlg.DoModal())
	{
		m_pNodeDataValueFileProject = new CNodeDataValueFileProject(NULL,dlg.GetPathName());
		return TRUE;
	}*/
	char buf[MAX_PATH];
	GetCurrentDirectory(MAX_PATH,buf);
	CString path = BrowseDirectory(buf,NULL);
	if (path.GetLength())
	{
		CString contentpath = path+"\\content";
		DWORD attrib = ::GetFileAttributes(contentpath);
		if (-1 == attrib)
		{
			// File does not exist
			CString str = "Game root folder "+path+" does not have a Contents directory.  Do you want to continue? A Contents directory will be created.";
			if (IDNO == MessageBox(NULL,str,"Create New Workspace",MB_YESNO))
				return false;
		}

		// Scan the content directory
		SetCurrentDirectory(path);
		m_strRoot = path;
		// Scan the content directory
		CreateDirectory(contentpath,NULL);
		CFrameWnd *pFrame = (CFrameWnd *)AfxGetMainWnd();
		pFrame->SetMessageText("Scanning Content directory...");
		this->m_pNodeDirectory = new CNodeDiskDirectory(NULL,/*path+"\\*/"content");

		m_pNodeDataValueFileProject = new CNodeDataValueFileProject(this,path);
		m_pNodeDirectory->SetParentNode(m_pNodeDataValueFileProject);

		return TRUE;
	}
	return FALSE;
}

CNodeDataValueFileDoc::~CNodeDataValueFileDoc()
{
	if (m_pNodeDataValueFileProject)
		delete m_pNodeDataValueFileProject;
	m_pNodeDataValueFileProject = NULL;

	if (m_pNodeDirectory)
		delete m_pNodeDirectory;
	m_pNodeDirectory = NULL;
}


BEGIN_MESSAGE_MAP(CNodeDataValueFileDoc, CContentTrackDoc)
	//{{AFX_MSG_MAP(CNodeDataValueFileDoc)
	ON_COMMAND(ID_ADDROOT, OnAddroot)
	ON_COMMAND(ID_FILE_SAVE, OnFileSave)
	ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
	ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
	ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
	ON_COMMAND(ID_EDIT_PASTE_RENAME, OnEditPasteRename)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CNodeDataValueFileDoc diagnostics

#ifdef _DEBUG
void CNodeDataValueFileDoc::AssertValid() const
{
	CContentTrackDoc::AssertValid();
}

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

/////////////////////////////////////////////////////////////////////////////
// CNodeDataValueFileDoc serialization

void CNodeDataValueFileDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: add storing code here
	}
	else
	{
		// TODO: add loading code here
	}
}

/////////////////////////////////////////////////////////////////////////////
// CNodeDataValueFileDoc commands

extern int IdentifyFileType(CString path);

BOOL CNodeDataValueFileDoc::OnOpenDocument(LPCTSTR lpszPathName) 
{
//	if (!CContentTrackDoc::OnOpenDocument(lpszPathName))
//		return FALSE;
	CFrameWnd *pFrame = (CFrameWnd *)AfxGetMainWnd();
	if (this->m_pNodeDataValueFileProject)
	{
		this->m_pActiveChild = NULL;
		pFrame->SetMessageText("Updating...");
		m_pNodeDataValueFileProject->Update();
		m_pNodeDataValueFileProject->ResetVisitAll();
		this->UpdateAllViews(NULL,NULL,NULL);
		pFrame->SetMessageText("Ready.");
		//TODO: Clear the dirty bits
		return TRUE;
	}

	NotationFile notefile(lpszPathName);
	Page *page = notefile.GetPage("Project");
	if (NULL == page)
		return FALSE;
	Check_Object(page);

	const char *path;
	if (!page->GetEntry("Path",&path))
		return FALSE;

	SetCurrentDirectory(path);
	m_strRoot = path;
	// Scan the content directory
	CreateDirectory(CString(path)+"\\content",NULL);
	pFrame->SetMessageText("Scanning Content directory...");
	this->m_pNodeDirectory = new CNodeDiskDirectory(NULL,/*CString(path)+"\\*/"content");

	m_pNodeDataValueFileProject = new CNodeDataValueFileProject(this,path);
	m_pNodeDirectory->SetParentNode(m_pNodeDataValueFileProject);

	page = notefile.GetPage("Roots");
	if (page)
	{
		Check_Object(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);

			if (0 == (strnicmp(entry->GetName(),"Path",4)))
			{
				const char *newpath;
				entry->GetEntry(&newpath);
				CString fullpath = CString(path)+"\\"+newpath;
				CNodeObject *pNode = CNodeData::CreateChild(m_pNodeDataValueFileProject,IdentifyFileType(fullpath),newpath);
				m_pNodeDataValueFileProject->AddChild(pNode);
			}
		}
		Check_Object(entries);
		delete entries;
	}
	return TRUE;
}

CNodeDisk *CNodeDataValueFileDoc::FindDirectoryNode(CString strName)
{
	return FindDirectoryNode(strName,GetRootNode());
}

CNodeDisk *CNodeDataValueFileDoc::FindDirectoryNode(CString strName,CNodeDisk *pNode)
{
#if 0
	if (strName.GetLength() ==0)
		return NULL;
	if (strName[0] == '\\')
		strName.Delete(0,1);
	CString strDir = pNode->GetName();
	int iLen = strDir.GetLength();
	if (strnicmp(strDir,strName,iLen)==0)
	{
		strName.Delete(0,iLen);
		if (strName.IsEmpty())
			// we found it
			return pNode;
		strName.Delete(0,1);
		POSITION pos = pNode->GetFirstChild();
		while (pos)
		{
			if (out_pos)
				*out_pos = pos;
			CNodeDisk *pChild = (CNodeDisk *)pNode->GetNextChild(pos);
			CNodeDisk *pRet = FindDirectoryNode(strName,pChild,out_pos);
			if (pRet)
				return pRet;
		}
	}
	return NULL;
#endif

	char *src_name = (char *)(LPCTSTR)strName;
//	int src_size = strName.GetLength();
	char dir_name[MAX_PATH];
	//char *dir_name = (char *)(LPCTSTR)pNode->GetName();
	pNode->GetName(dir_name,MAX_PATH);
//	int dir_size = pNode->GetName().GetLength();

	// this isn't really necessary since the last character in src_name is '\0'
	// and the loop below will exit there too
//	if (src_size < dir_size)
//		return NULL;

	//for (int x=0;x<dir_size;x++)
	for (char *dn = dir_name;*dn;++dn,++src_name)
	{
		// 0x5f mask makes the ascii character uppercase
		if ( (*src_name&0x5f) != (*dn&0x5f))
			return NULL;
		//src_name++;
	}

	if (src_name[0])
	{
		if ('\\' == src_name[0])
		{
			src_name++;
			POSITION pos = pNode->GetFirstChild();
			while (pos)
			{
				CNodeDisk *pChild = (CNodeDisk *)pNode->GetNextChild(pos);
				CNodeDisk *pRet = FindDirectoryNode(src_name,pChild);
				if (pRet)
					return pRet;
			}
		}
		// We found some other characters in the name, so it doesn't match.
		return NULL;
	}
	// Means the names match and we found the right node
	return pNode;
}

void CNodeDataValueFileDoc::OnAddroot() 
{
	CFileDialog dlg(true);
	CString str;
	this->m_pNodeDataValueFileProject->GetName(str);
	dlg.m_ofn.lpstrInitialDir = str;
	if (IDOK == dlg.DoModal())
	{
		//m_pNodeDataValueFileProject = new CNodeDataValueFileProject(NULL,dlg.GetPathName());
		CString path = dlg.GetPathName();
		CString dir;
		m_pNodeDataValueFileProject->GetName(dir);
		if (strnicmp(dir,path,dir.GetLength()))
		{
			// Error - the new root file must be in a subdir of the project path
			MessageBox(NULL,"Error: The new root file must be in a subdir of the project path!","Error",MB_OK);
			return;
		}
		CString newpath = path.Right(path.GetLength()-dir.GetLength()-1);

		SetCurrentDirectory(dir);
		CNodeObject *pNode = CNodeData::CreateChild(m_pNodeDataValueFileProject,IdentifyFileType(path),newpath);
		m_pNodeDataValueFileProject->AddChild(pNode);

	//	m_pNodeDataValueFileProject->Update();
		this->UpdateAllViews(NULL,NULL,NULL);
	}
}

void CNodeDataValueFileDoc::OnFileSave() 
{
	CString fname = GetPathName();
	if (0 == fname.GetLength())
	{
		OnFileSaveAs();
		return;
	}
	NotationFile notefile;
	Page *page = notefile.AddPage("Project");
	CString str;
	m_pNodeDataValueFileProject->GetName(str);
	page->AppendEntry("Path",str);

	page = notefile.AddPage("Roots");
	POSITION pos = m_pNodeDataValueFileProject->GetFirstChild();
	while (pos)
	{
		CNodeObject *pnode = m_pNodeDataValueFileProject->GetNextChild(pos);
		CString str;
		pnode->GetName(str);
		page->AppendEntry("Path",str);
	}
	notefile.SaveAs(GetPathName());
}

void CNodeDataValueFileDoc::OnFileSaveAs() 
{
	CFileDialog dlg(false);
	if (IDOK == dlg.DoModal())
	{
		this->SetPathName(dlg.GetPathName());
		OnFileSave();
	}
}

void CNodeDataValueFileDoc::OnEditCopy() 
{
	((CContentTrackApp *)AfxGetApp())->m_pNodeSelected = m_pActiveChild;
}

void CNodeDataValueFileDoc::OnEditPaste() 
{
	CNodeObject *pSelected = ((CContentTrackApp *)AfxGetApp())->m_pNodeSelected;
	CNodeObject *pClone = _OnEditPaste(pSelected);
	if (pClone)
		this->UpdateAllViews(NULL,NULL,NULL);
}

CNodeObject *CNodeDataValueFileDoc::_OnEditPaste(CNodeObject *pSelected,CString oldName,CString newName)
{
	this->m_iReplaceAll = -1;
	// Paste the copied node as a child of the selected node
	CNodeObject *pChild = m_pActiveChild?m_pActiveChild:this->GetNodeProject();
	CNodeObject *pClone = NULL;
	if (pSelected&&pChild)
	{
		pClone = pSelected->Clone(pChild,oldName,newName);
		pChild->AddChild(pClone);
		this->GetRootNode()->ResetVisitAll();
	}
	return pClone;
}

int VisitTreeFiles(CNodeObject *pNode)
{
	int count = 0;
	if (NULL == pNode)
		return 0;

	bool bvisited = false;
	if (pNode->IsFile())
	{
		CNodeDisk *pDisk= ((CNodeDataValueFile*)pNode)->GetNodeDisk();
		bvisited = pDisk->GetVisit(VISIT_FLAG1);
		if (!bvisited)
		{
			pDisk->SetVisit(VISIT_FLAG1);
			count++;
		}
	}
	if (!bvisited)
	{
		POSITION pos = pNode->GetFirstChild();
		while (pos)
		{
			CNodeObject *pChild = pNode->GetNextChild(pos);
			count += VisitTreeFiles(pChild);
		}
	}
	return count;
}

void CNodeDataValueFileDoc::OnEditPasteRename() 
{
	CNodeObject *pSelected = ((CContentTrackApp *)AfxGetApp())->m_pNodeSelected;

	CDialogPasteRename dlg;
	if (pSelected&&(IDOK == dlg.DoModal()))
	{
		CString newName = dlg.m_strNew;
		CString oldName = dlg.m_strOld;

		CNodeObject *pNode = pSelected;
		while (pNode && (!pNode->IsFile()))
			pNode = pNode->GetParentNode();
		VisitTreeFiles(pNode);

		CNodeObject *pClone = _OnEditPaste(pSelected,oldName,newName);
		this->UpdateAllViews(NULL,NULL,NULL);
	}
}
