/***************************************************************************
*                                                                           *
*                           3DS Max Test Plugin                             *
*                                                                           *
***************************************************************************
*                                                                           *
* Version : 1.0ß, March 11th, 1998                                          *
*                                                                           *
* Written By Loic Baumann from Fatal Design, specially for Gamasutra        *
*                                                                           *
***************************************************************************
*                                                                           *
* This Plugin demonstrates how to write a simple 3DS MAX Plugin, using MFCs *
*                                                                           *
***************************************************************************/
 
#include "stdafx.h"

#ifdef STRICT							// Already defined by stdafx,
#undef STRICT							// so we avoid warning linking msg
#endif
#ifdef _MBCS							// The same as above
#undef _MBCS
#endif

#include <DLLPlatform\DLLPlatform.hpp>

#include "MissionImp.h"
#include "ExportUtil.h"

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

#include <direct.h>
#include "ExportUtil.h"
//#include "mapsizedlg.h"

//===========================================================================//
int MissionImp::DoImport(const TCHAR *name, ImpInterface *ii,Interface *i, BOOL suppressPrompts)
{
	int return_value;
	__try
	{
		m_ip = i;
		m_suppress = suppressPrompts?true:false;
		return_value = ImportMission(name);
		//return_value = true;
		GetSystemSetting(SYSSET_CLEAR_UNDO);
		Verify(!theHold.Holding());
	}
	__except(ProcessException(GetExceptionInformation()))
	{
	}

	return return_value;
}

// in maxpolygonmesh.cpp
Quat ConvertMWToMax(UnitQuaternion &quat);
Point3 ConvertMWToMax(Stuff::Point3D &pnt);

/*******************************************************************************
/* function name: ImportVideo
/* description: Import .video files
/*******************************************************************************/
int MissionImp::ImportVideo(const char *name,Quat maxrot,Point3 maxtrans)
{
	CString filename = GetGamePath(m_ip) + "content\\"+name;
	NotationFile videofile(filename);
	Page *page = videofile.FindPage("LOD");
	if (page)
	{
		const char *entry;
		if (page->GetEntry("Geometry",&entry))
		{
			char path[MAX_PATH];
			_splitpath(name,NULL,path,NULL,NULL);

			CString path1(path);
			// trim "armaturevideo from the tail of the path
			path1.MakeLower();
			int index = path1.Find("armaturevideo");
			if (index>0)
			{
				path1 = path1.Left(index);
			}

			CString erfpath = GetGamePath(m_ip) + "content\\";
			erfpath+=path1;
			erfpath+=entry;

			if (m_ip->ImportFromFile(erfpath,false))
			{
				// Move any node with name not starting with "_" to the rotation/translation coordinates
				Matrix3 axis(MAT_IDENT);
				INode *pWorld = m_ip->GetRootNode();
				for (int x=0;x<pWorld->NumberOfChildren();x++)
				{
					INode *pChild = pWorld->GetChildNode(x);
					CString name = pChild->GetName();
					if (strnicmp(name,"_",1))
					{
						name = CString("_")+name;//name;
						pChild->SetName((char *)(LPCTSTR)name);
						pChild->Rotate(0,axis,maxrot);
						pChild->Move(0,axis,maxtrans);
			
						Quat fixrot(0.0,0.0,PI/2.0,0.0);
						// Now move and rotate to the terrain's coordinate system
//						pChild->Move(0,axis,fixtrans);
						pChild->Rotate(0,axis,fixrot);
					}
				}
				return 1;
			}
		}									
	}
	return 0;
}

/*******************************************************************************
/* function name: ImportModel
/* description: Import .data files
/*******************************************************************************/
int MissionImp::ImportModel(const char *name,Quat maxrot,Point3 maxtrans)
{
	CString filename = GetGamePath(m_ip) + "content\\"+name;
	NotationFile modelfile(filename);
	Page *page = modelfile.FindPage("Renderers");
	if (page)
	{
		const char *entry;
		if (page->GetEntry("VideoRenderer",&entry))
		{
			char path[MAX_PATH];
			_splitpath(name,NULL,path,NULL,NULL);
			CString filename(path);
			// trim "armaturedata from the tail of the path
			filename.MakeLower();
			int index = filename.Find("armaturedata");
			if (index>0)
			{
				filename = filename.Left(index);
			}
			filename+=entry;
			return ImportVideo(filename,maxrot,maxtrans);
		}
	}
	return 0;
}

struct ARMNODE
{
	ARMNODE *parent;
	CString name;
	const char *model;
	Quat rot;
	Point3 trans;
};

/*******************************************************************************
/* function name: ImportArmature
/* description: Import .armature files
/*******************************************************************************/
int MissionImp::ImportArmature(const char *name,Quat maxrot,Point3 maxtrans)
{
	CString filename = GetGamePath(m_ip) + "content\\"+name;
	NotationFile armfile(filename);
	NotationFile::PageIterator *pages = armfile.MakePageIterator();

	CMapStringToPtr mapNode;

	ARMNODE *pRoot = NULL;
	Page *page;
	while (page = pages->ReadAndNext())
	{
		ARMNODE *pNode = new ARMNODE;
		if (NULL == pRoot)
			pRoot = pNode;

		pNode->name = page->GetName();
		pNode->name.MakeLower();
		mapNode[pNode->name] = pNode;
		pNode->parent = NULL;
		pNode->rot.Identity();
		pNode->trans = Point3(0,0,0);
		pNode->model = NULL;
	}
	delete pages;

	pages = armfile.MakePageIterator();
	while (page = pages->ReadAndNext())
	{
		CString name = page->GetName();
		name.MakeLower();

		ARMNODE *pNode = (ARMNODE *)mapNode[name];
		Page::NoteIterator *notes = page->MakeNoteIterator();
		Note *note;
		while (note = notes->ReadAndNext())
		{
			if (0==stricmp(note->GetName(),"rotation"))
			{
				YawPitchRoll ypr;
				note->GetEntry(&ypr);
				{
					UnitQuaternion rotation;
					rotation = ypr;	
					pNode->rot = ConvertMWToMax(rotation);
				}
			}

			if (0==stricmp(note->GetName(),"translation"))
			{
				Point3D translation;
				note->GetEntry(&translation);
				{
					pNode->trans = ConvertMWToMax(translation);
				}
			}

			if (0==stricmp(note->GetName(),"child"))
			{
				const char *child;
				note->GetEntry(&child);
				{
					CString str(child);
					str.MakeLower();
					
					ARMNODE *pChild = (ARMNODE *)mapNode[str];
					Check_Pointer(pChild);
					pChild->parent = pNode;
					if (pChild == pRoot)
						pRoot= pNode;
				}
			}

			if (0==stricmp(note->GetName(),"model"))
			{
				const char *model;
				note->GetEntry(&model);
				{
					pNode->model = model;
				}
			}
		}
		delete notes;
	}
	delete pages;
	
	int count = 0;
	POSITION pos = mapNode.GetStartPosition();
	while (pos)
	{
		CString key;
		LPVOID value;
		mapNode.GetNextAssoc(pos,key,value);
		ARMNODE *pNode = (ARMNODE *)value;
		if (pNode->model)
		{
			Quat q = pNode->rot;
			Point3 p = pNode->trans;
			
			ARMNODE *pParent = pNode->parent;
			while (pParent)
			{
				q+=pParent->rot;
				p+=pParent->trans;
				pParent = pParent->parent;
			}

			q+=maxrot;
			p+=maxtrans;

			char path[MAX_PATH];
			_splitpath(name,NULL,path,NULL,NULL);
			CString filename(path);
			filename+=pNode->model;
			count += ImportModel(filename,q,p);
		}
	}

	pos = mapNode.GetStartPosition();
	while (pos)
	{
		CString key;
		LPVOID value;
		mapNode.GetNextAssoc(pos,key,value);
		ARMNODE *pNode = (ARMNODE *)value;
		delete pNode;
	}
	mapNode.RemoveAll();
	return count;
}

/*******************************************************************************
/* function name: ImportPage
/* description: Import an object from a mission contents file
/*******************************************************************************/
int MissionImp::ImportPage(Page *page)
{
	Quat maxrot;
	Point3 maxtrans;
	maxrot.Identity();
	maxtrans = Point3(0,0,0);

	YawPitchRoll ypl;
	if (page->GetEntry("rotation",&ypl))
	{
		UnitQuaternion rotation;
		rotation = ypl;
		maxrot = ConvertMWToMax(rotation);
	}

	Point3D translation;
	if (page->GetEntry("translation",&translation))
	{
		maxtrans = ConvertMWToMax(translation);	
	}

	// Now import the buildings only
	const char *entry;
	if (page->GetEntry("armature",&entry))
	{
		if (0==strnicmp(entry,"buildings",9))
			return ImportArmature(entry,maxrot,maxtrans);
	}

	if (page->GetEntry("model",&entry))
	{
		if (0==strnicmp(entry,"buildings",9))
			return ImportModel(entry,maxrot,maxtrans);
	}
	
	return 0;
}

/*******************************************************************************
/* function name: ImportMission
/* description: Import a mission .contents file
/*******************************************************************************/
int MissionImp::ImportMission(const CString& fileName)
{
	Point3 fixtrans;
	fixtrans.x = 0;
	fixtrans.y = 0;
	Quat fixrot(0.0,0.0,PI/2.0,0.0);
	
	INode *pWorld = m_ip->GetRootNode();
	for (int x=0;x<pWorld->NumberOfChildren();x++)
	{
		INode *pChild = pWorld->GetChildNode(x);
		CString name = pChild->GetName();
		if (strnicmp(name,"_",1))
		{
			name = CString("_")+name;//name;
			pChild->SetName((char *)(LPCTSTR)name);
		}
	}
	
	// Change directory to game path
	CString gamepath = GetGamePath(m_ip);
	char tpath[MAX_PATH];		
	getcwd(tpath,MAX_PATH);		
	chdir(gamepath);
	NotationFile notefile(fileName);
	
	m_ip->ProgressStart((char *)(LPCTSTR)(CString("Importing ")+fileName),false,fn,NULL);
	
	Page *page;
	NotationFile::PageIterator *pages = notefile.MakePageIterator();
	Check_Object(pages);
	
	int count = 0;
	int progress = 0;
	int maxcount = pages->GetSize();
	while (page = pages->ReadAndNext())
	{
		progress++;
		m_ip->ProgressUpdate((int)(((float)progress/(float)maxcount)*100.0f),false,(char *)page->GetName());
		count += ImportPage(page);
	}
	m_ip->ProgressEnd();
	delete pages;
	
	chdir(tpath);
	return true;
}

