////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
//  File name:   resourcecompiler.h
//  Version:     v1.00
//  Created:     4/11/2002 by Timur.
//  Compilers:   Visual Studio.NET
//  Description: 
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////

#ifndef __resourcecompiler_h__
#define __resourcecompiler_h__
#pragma once

#include "IRCLog.h"
#include "IResCompiler.h"
#include "Config.h"
#include "ExtensionManager.h"

#include <map>										// stl multimap<>
#include <string>									// stl string




/** Implementation of IResCompiler interface.
*/
class ResourceCompiler :
	public IResourceCompiler,
	public IRCLog,
	public IConfigKeyRegistry
{
public:
	// constructor
	ResourceCompiler();
	// destructor
	~ResourceCompiler();

	//! e.g. print dependencies
	void PostBuild();

	// interface IConfigKeyRegistry --------------------------------------------

	virtual void VerifyKeyRegistration( const char *szKey );

	// interface IResourceCompiler ---------------------------------------------

	virtual void RegisterKey( const char *key, const char *helptxt );
	virtual void EnsureDirectoriesPresent( const char *path );
	virtual void RegisterConvertor( IConvertor *conv );
	virtual FILE*	OpenFile( const char *filename,const char *mode );
	bool GetFileTime( const char *filename,FILETIME *ftimeModify, FILETIME*ftimeCreate =NULL );

	// returns the file unix time - the latest of modification and creation times
	DWORD GetFileUnixTimeMax (const char* filename);

	// returns the file unix time - the earliest of modification and creation times
	DWORD GetFileUnixTimeMin (const char* filename);

	bool CompileFile(Platform platform, IConfig* config, const char *filename, const char *outroot, const char *filepath, ICompiler* compiler, std::vector<CFileStats>* fileStats);

	//! Load and parse the Crytek Chunked File into the universal (very big) structure
	//! The caller should then call Release on the structure to free the mem
	//! @param filename Full filename including path to the file
//	virtual CryChunkedFile* LoadCryChunkedFile (const char* szFileName);
	
	virtual IRCLog *GetIRCLog();

	virtual void AddDependencyMaterial( const char *inszSrcFilename, const char *inszMatName, const char *inszScriptName );
	virtual void AddDependencyFile( const char *inszSrcFilename, const char *inszPathFileName );
	//virtual void AddFileStats( const char *inszPathFileName, const size_t SrcFileSize, const size_t DstFileSize, const char *inszPreset, const char *inszInfo );

	virtual void DeInit();
		
	virtual ICfgFile *CreateCfgFile();

	// interface IRCLog ---------------------------------------------

	virtual void LogLine( const ELogType ineType, const char* szText );
	virtual void AddCallback( ILogCallback *pCallback ) { assert(0); } // no implemented
	virtual void RemoveCallback( ILogCallback *pCallback ) { assert(0); } // no implemented

	//////////////////////////////////////////////////////////////////////////
	// Resource compiler implementation.
	//////////////////////////////////////////////////////////////////////////
	bool Compile( Platform platform,IConfig* config,const char *filespec );
	bool CompileFilesSingleThreaded(const CString& path, const CString& targetroot, Platform platform,IConfig* config,const std::vector<CString>&files,IConvertor* convertor, std::vector<CString>& nonConvertedFiles);
	bool CompileFilesMultiThreaded(int threadCount, const CString& path, const CString& targetroot, Platform platform,IConfig* config,const std::vector<CString>&files,IConvertor* convertor, std::vector<CString>& nonConvertedFiles);
	bool CompileFileArray(const CString& path, const CString& targetroot, Platform platform,IConfig* config,const std::vector<CString>&files,ICompiler* compiler, std::vector<CString>& nonConvertedFiles, std::vector<CString>& outOfMemoryFiles, std::vector<CFileStats>* fileStats);
	const char* GetSectionName( Platform platform ) const;

	//! call this if user asks for help
	void show_help();

	//! Returns the main application window
	HWND GetHWnd();
	HWND GetEmptyWindow();

	//////////////////////////////////////////////////////////////////////////
	void QueryVersionInfo();
	SFileVersion& GetFileVersion() { return m_fileVersion; }

	void AutoDetection();
	void SortLogFiles();
	void AddFileStats(ConvertContext* pCC, const char *inszPathFileName, const size_t SrcFileSize, const size_t DstFileSize, const char *inszPreset, const char *inszInfo);

	bool													m_bQuiet;							//!< true= don't log anything to console, otherwise false

private:

	// private structures

	typedef std::multimap<string,string>		CFileDepMap;
	typedef std::pair<string,string>				CFileDepPair;

	class CMatDep
	{
		public:
			string				m_sMatName;				//!<
			string				m_sScriptName;		//!<

			bool operator==( const CMatDep &inRhS ) const
			{
				return(inRhS.m_sMatName==m_sMatName && inRhS.m_sScriptName==m_sScriptName);
			}
	};


	// helper to get order for CMatDep
	struct CMatDepOrder: public std::binary_function< CMatDep, CMatDep, bool>
	{
		bool operator() ( const CMatDep &a, const CMatDep &b ) const
		{
			// first sort by m_sScriptName (neccessary for printout)
			if(a.m_sScriptName<b.m_sScriptName)return(true);
			if(a.m_sScriptName>b.m_sScriptName)return(false);

			// then by m_sMatName
			if(a.m_sMatName<b.m_sMatName)return(true);
			if(a.m_sMatName>b.m_sMatName)return(false);

			return(false);
		}
	};

	// helper to get uint32 sorted with bigger values first
	struct CInvOrder: public std::binary_function< uint32, uint32, bool>
	{
		bool operator() ( const uint32 &a, const uint32 &b ) const
		{
			if(a>b)return true;
			if(a<b)return false;

			return false;
		}
	};

	typedef std::multimap<CMatDep,string,CMatDepOrder>	CMatDepMap;
	typedef std::pair<CMatDep,string>										CMatDepPair;

	//typedef std::multimap<string,uint32>								CPresetMap;
	//typedef std::pair<string,uint32>										CPresetPair;

	//typedef std::map<string,uint32>											CFileStatsMap;
	//typedef std::pair<string,uint32>										CFileStatsPair;

	//typedef std::multimap<uint32,uint32,CInvOrder>			CFileSizeMap;
	//typedef std::pair<uint32,uint32>										CFileSizePair;

	// ------------------------------------------------



	ExtensionManager				m_extensionManager;			//!<

	CFileDepMap							m_FileDependencies;			//!< key=dependency e.g. nm.dds   value=file that is using it e.g. ball.cgf
	CMatDepMap							m_MaterialDependencies;	//!< key=materialname+scriptmaterialname  value=file that is using it
	//CPresetMap							m_PresetUsage;					//!< key=presetname, value= file statistics index
	//CFileStatsMap						m_FileStats;						//!< key=file that is using it, value= file statistics index
	//CFileSizeMap						m_FileSizes;						//!< key=dest file size in KB, value= file statistics index
	std::vector<CFileStats> m_Files;								//!< [index] = file statistics

	// log files
	FILE *									m_hLogFile;							//!< for all messages, might be 0 (no file logging)
	FILE *									m_hWarningLogFile;			//!< for all warnigns only, might be 0 (no file logging)
	FILE *									m_hErrorLogFile;				//!< for all errors only, might be 0 (no file logging)

	ICfgFile *							m_presets;

	//
	bool										m_bWarningHeaderLine;		//!< true= header was already printed, false= header needs to be printed
	bool										m_bErrorHeaderLine;			//!< true= header was already printed, false= header needs to be printed
	bool										m_bStatistics;					//!< true= show statistics.
	bool                    m_bWarningsAsErrors;    //!< true= Treat any warning as error.
	unsigned int						m_iThreads;							//!< number of supported threads 
	string									m_sHeaderLine;					//!<
	SFileVersion            m_fileVersion;
	SFileVersion            m_productVersion;
	string                  m_exePath;
	std::map<string,string>	m_KeyHelp;							// [lower key] = help, created from RegisterKey

	HWND m_hEmptyWindow;

	//
	void ShowFileDependencies();
	//
//	void ShowMaterialDependencies();
	//
	void ShowPresetUsage();
	// in format that can be easily read from Excel
	void ShowXLSFileSizes();
	// to remove old files for less confusion
	void RemoveOutputFiles();
	//
	void SetHeaderLine( const char *inszLine );

	void InitializeLogThreadNumbering();
	int GetThreadNumber();
	DWORD m_threadNumberTLSIndex;

	static unsigned int WINAPI ThreadFunc(void* threadDataMemory);

	void SortLogFileByThread(FILE* file);
};

#endif // __resourcecompiler_h__
