// BaseGeoExporter.cpp: implementation of the BaseGeoExporter class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "BaseGeoExport.h"

#include <GameOS\GameOS.hpp>
#include <GameOS\ToolOS.hpp>
#include "MaxProxies\MaxProxyHeaders.hpp"
#include "ExportUtil.h"

#if !defined(DLLPLATFORM_DLLPLATFORM_HPP)
	#include "DLLPlatform\DLLPlatform.hpp"
#endif

// Used by the MLRTexturePoolProxy
extern bool g_bSaveTextureAsPng;
extern CString g_strLogFile;

/*******************************************************************************
/* function name: LoadPlugCfg
/* description: Load exporter settings from plugins.ini from the 3dsmax directory
/*******************************************************************************/
bool BaseGeoExporter::LoadPlugCfg(Interface *i)
{
	TurnOffExceptions();
	m_maxDataPath = i->GetDir(APP_PLUGCFG_DIR);
	TSTR ini_file = m_maxDataPath;
	ini_file += "\\Plugins.ini";

	Check_Pointer(Stuff::FileStreamManager::Instance);
	Stuff::FileStream file_stream(ini_file);

	if (!file_stream.IsFileOpened())
	{
		if (!m_suppress) {
			AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
			ReportError(CString("ERROR: Must have the PlugIns.ini file in ")+m_maxDataPath);
		}
		i->ProgressEnd();
		TurnOnExceptions();
		return false;
	}

    Stuff::NotationFile data_file(&file_stream);
	const char* read_dir;
	Page* page = data_file.FindPage("BRBData");
	if (page)
	{
		page->GetEntry("GameDir", &read_dir);
	}
	else {
		read_dir = "c:\\dev\\mw4";
	}

	m_texturePath = CString(read_dir)+"\\content\\textures\\";
	g_strLogFile = CString(read_dir)+"\\export.log";


	// set default to false, consistent with batch exporter
	m_exportDataFiles = false; 

	page = data_file.FindPage("ExportData");
	if (page)
	{
		if (page->GetEntry("ErfDir", &read_dir))
		{
			m_erfPath = read_dir;
			m_erfPath += "\\";
		}

		if (page->GetEntry("TextureDir", &read_dir) && !m_isBRB)
		{
			m_texturePath = read_dir;
			m_texturePath += "\\";
		}
		page->GetEntry("ExportDataFiles", &m_exportDataFiles);
		page->GetEntry("TextureAsPng", &g_bSaveTextureAsPng);
	}

	// Make sure texture path exists
	bool texture_dir_exists = 
		gos_CreateDirectory(
		m_texturePath
		);

	TurnOnExceptions();
	return true;
}

/*******************************************************************************
/* function name: SaveExportInfo
/* description: 
/*******************************************************************************/
bool BaseGeoExporter::SaveExportInfo(INode *node)
{

	INode *data_node = node;
	ExportInfo savedExportInfo = m_exportInfo;
	bool bNeedToSave = false;

	//
	// first check to see if the data is where it is suppose to be
	//
	if (node->IsRootNode())
	{
		int i = node->NumberOfChildren();			
		if (i>0)
		{
			data_node = node->GetChildNode(0);
			//
			// Grab the app data chunk 
			//
			AppDataChunk *ad = 
				data_node->GetAppDataChunk(
				EXPORTINFO_CLASS_ID, 
				EXPORTINFO_SUPER_CLASS_ID, 
				PERM_DATA_ID);
			
			//
			// if the data is there copy it and move on if not
			// search the tree for it.  If found copy it to where it 
			// should be and remove the old one
			//
			if (ad) 
			{
				size_t size = sizeof(ExportInfo);
				Mem_Copy(&savedExportInfo, ad->data, size, size);
			}
			else 
			{
				bNeedToSave = true;
				INode *find_node = FindChunk(node);
				if (find_node)
				{
					AppDataChunk *ad = 
						find_node->GetAppDataChunk(
						EXPORTINFO_CLASS_ID, 
						EXPORTINFO_SUPER_CLASS_ID, 
						PERM_DATA_ID);
					size_t size = sizeof(ExportInfo);
					Mem_Copy(&savedExportInfo, ad->data, size, size);
					//
					// Remove the chunk if it exists
					//
					find_node->RemoveAppDataChunk(
						EXPORTINFO_CLASS_ID, 
						EXPORTINFO_SUPER_CLASS_ID, 
						PERM_DATA_ID);
					
				}
			}
		}
	}

	if ((bNeedToSave) ||
		(m_exportInfo.exportType != savedExportInfo.exportType) ||
		(m_exportInfo.overwriteTextures != savedExportInfo.overwriteTextures) ||
		(m_exportInfo.outputAmatureFile != savedExportInfo.outputAmatureFile) )
					
	{
		return InternalSaveExportInfo(node);
	}

	return true;
}

/*******************************************************************************
/* function name: InternalSaveExportInfo
/* description: 
/*******************************************************************************/
bool BaseGeoExporter::InternalSaveExportInfo(INode *node)
{
	INode *data_node = node;

	if (node->IsRootNode())
	{
		int i = node->NumberOfChildren();			
		if (i>0)
		{
			data_node = node->GetChildNode(0);
		}
		else
		{
			return false;
		}
	}
	//
	// Remove the chunk if it exists
	//
	data_node->RemoveAppDataChunk(
		EXPORTINFO_CLASS_ID, 
		EXPORTINFO_SUPER_CLASS_ID, 
		PERM_DATA_ID);

	size_t size = sizeof(ExportInfo);
	BYTE *data = new BYTE[size];
	Mem_Copy(data, &m_exportInfo, sizeof(ExportInfo), size);

	//
	// Add a chunk
	//
	data_node->AddAppDataChunk(
		EXPORTINFO_CLASS_ID, 
		EXPORTINFO_SUPER_CLASS_ID, 
		PERM_DATA_ID,
		size, data);
	
	SetSaveRequired(TRUE);
	return true;

}

/*******************************************************************************
/* function name: ExportMaxScene
/* description: Exports a max scene to an erf file
/*******************************************************************************/
int BaseGeoExporter::ExportMaxScene(MAXProxies::MAXScene *max_scene, Interface *ip, const TCHAR *name)
{
	Check_Object(max_scene);

	// Load settings
	m_exportInfo.exportType = EXPORT_SHAPE;
	m_exportInfo.outputAmatureFile = false;
	m_exportInfo.overwriteTextures = true;
	SaveExportInfo(max_scene->GetProxiedScene());
	
	//
	// set up some name and path stuff
	//
	TSTR filename, extension;
	TSTR fullpath = _T(name);
    TSTR directoryPath;
	SplitFilename(fullpath,&directoryPath,&filename,&extension);
	directoryPath += "\\";

	//
	// see if the erf file already exists
	//
	CString erf_file_name = directoryPath + m_erfPath + filename + ".erf";
	bool file_exists = gos_DoesFileExist(erf_file_name);

	if (file_exists)
	{
		AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
		gos_DeleteFile(erf_file_name);
    }

	//
	// if we are exporting the character do the following
	// or fall threw and export a fused mesh called a shape
	//
	TSTR shape_filename = filename + extension;
	CString set_filename =	directoryPath + shape_filename;
	
	ElementProxies::ElementSceneProxy *element_scene = InitElementScene(CString(m_texturePath));
	CopySceneMaxToElement(element_scene,max_scene,true,ip,m_progress,m_suppress);
	FuseElementScene(element_scene,ip,m_progress,m_suppress);
	OptimizeElementScene(element_scene);

	// Set some special modes for lights, 
	// so that they don't pick up fog, and are self-illuminated	
	CString temp(name);
	temp.MakeLower();
	if (temp.Find("light") >= 0)
	{
		SetExplicitAlphaMode(element_scene, MidLevelRenderer::MLRState::AlphaOneMode);
		SetExplicitLightingMode(element_scene, MidLevelRenderer::MLRState::LightingOffMode);
		SetExplicitFogMode(element_scene, StateProxy::LightFogMode);
	}

	return SaveElementScene(element_scene,set_filename);
}

/*******************************************************************************
/* function name: CheckForErrors
/* description: method does the error checking set up by JM
/*******************************************************************************/
bool BaseGeoExporter::CheckForErrors(MAXProxies::MAXScene *scene, Interface *i, bool bProgressEnd) 
{
	//
	// Now check the the data for errors
	//
	TurnOffExceptions();
	if (!m_suppress) i->ProgressUpdate(++m_progress,false,"Checking for errors.");	
	TurnOnExceptions();

	Stuff::NotationFile config_file(Stuff::MString(m_maxDataPath)+"\\PlugIns.ini");
	MAXProxies::FindMAXErrors process_errors(&config_file,i,m_progress,m_suppress,(LPVOID)&ReportError);
	
	if (scene->FindErrors(&process_errors)>0) {
		if (bProgressEnd) {
			TurnOffExceptions();
			i->ProgressEnd();
			TurnOnExceptions();
		}
		if (!m_suppress)
		{
			ReportError(CString(i->GetCurFileName())+": Found Data Errors: EXPORT FAILED!",m_suppress);
		}
		return false;
	}

	if (!m_suppress) 
	{	
		m_progress += 9;
		TurnOffExceptions();
		i->ProgressUpdate(++m_progress,false,"Error checks complete");
		TurnOnExceptions();
	}

	return true;
}

/*******************************************************************************
/* function name: StartExport
/* description: Helper function
/*******************************************************************************/
void BaseGeoExporter::StartExport(Interface *ip, CString& str, bool bSuppressPrompts)
{
    TurnOnExceptions();
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    
    m_suppress = bSuppressPrompts;
	m_progress = 0;
	
	LPVOID arg = NULL;
	if (!m_suppress)
	{
		TurnOffExceptions();
		ip->ProgressStart(str.GetBuffer(0), false, fn, arg);
		str.ReleaseBuffer();
		ip->ProgressUpdate(++m_progress,false,"");	
		TurnOnExceptions();
	}
}

/*******************************************************************************
/* function name: EndExport
/* description: Helper function
/*******************************************************************************/
void BaseGeoExporter::EndExport(Interface *ip)
{
	TurnOffExceptions();
	if (!m_suppress) 
	{
		ip->ProgressEnd();
	}
}

/*******************************************************************************
/* function name: UpdateProgress
/* description: Helper function
/*******************************************************************************/
void BaseGeoExporter::UpdateProgress(Interface *ip, int progress, CString& str)
{
	if (!m_suppress)
	{
		TurnOffExceptions();
		m_progress = progress;
		ip->ProgressUpdate(m_progress, false, str.GetBuffer(0));
		str.ReleaseBuffer();
		TurnOnExceptions();
	}
}

/*******************************************************************************
/* function name: FindChunk
/* description: 
/*******************************************************************************/
INode *BaseGeoExporter::FindChunk(INode *node)
{
	for (int c = 0; c < node->NumberOfChildren(); c++) 
	{
		FindChunk(node->GetChildNode(c));
		INode *child = node->GetChildNode(c);
		TCHAR *name = child->GetName();
		AppDataChunk *ad = 
			child->GetAppDataChunk(
				EXPORTINFO_CLASS_ID, 
				EXPORTINFO_SUPER_CLASS_ID, 
				TEMP_DATA_ID
			);
		if (ad) return child;
	}
	return NULL;
}
