////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2001-2006.
// -------------------------------------------------------------------------
//  File name:   MeshCompiler.h
//  Version:     v1.00
//  Created:     6/22/2004 by Alexey Medvedev.
//  Compilers:   Visual Studio.NET 2005
//  Description: 
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////

#ifndef __AnimationCompiler_h__
#define __AnimationCompiler_h__
#pragma once

#include "IConvertor.h"
#include "cgf/CGFLoader.h"

#include "CryThread.h"
#include "AnimationInfoLoader.h"

struct ConvertContext;
class CContentCGF;
class CChunkFile;
class ICryXML;
class ILoaderCGFListener;
class CSkeletonInfo;
struct SAnimationDesc;
class CTrackStorage;

//struct SCompilerStatistics 
//{
//	int m_iCount;
//	float m_fAverage;
//	float m_fTotal;
//
//	SCompilerStatistics() {
//		m_iCount = 0;
//		m_fAverage = 0;
//		m_fTotal = 0;
//	}
//};
//

bool GetFileTime( const char *filename,FILETIME *ftimeModify, FILETIME*ftimeCreate );

struct SCompilerBehavior
{
	bool m_bNeedCalculate; // that means we need recalculate compressed data. We need an uncompressed data
	bool m_bNeedLoadDBA; // that means - we use .dba file as reference 
	bool m_bNeedSaveDBA; // that means - we nned save the .dba file
	bool m_bNeedDeleteUncompressedData; // that means - we need delete only uncompressed chuncks
	bool m_bNeedDeleteAllData; // we need delete all data
	bool m_bNeedUpdateOnlyNew; // we need update only new file
	bool m_bNeedSwapEndian;
	bool m_bCheckLocomotion;
	bool m_bUseMultiThreading;
	int	 m_iSupportedThreads;

	SCompilerBehavior() 
	{
		m_bNeedCalculate = false;
		m_bNeedLoadDBA = false;
		m_bNeedSaveDBA = false;
		m_bNeedDeleteUncompressedData = false;
		m_bNeedDeleteAllData = false;
		m_bNeedUpdateOnlyNew = false; 
		m_bNeedSwapEndian = false;
		m_bCheckLocomotion = false;
		m_bUseMultiThreading = false;
		m_iSupportedThreads = 0;

	}
};

class CAnimationCompiler;
//struct SAnimationDesc;

struct ThreadCompiler //: public CrySimpleThread<>
{
	void Run();
	void Cancel();

	CSkeletonInfo * currentSkeleton;
	std::string animFile;
	std::string destFile; 
	ILoaderCGFListener * listener;
	ConvertContext cc;
	SAnimationDesc pDesc;
	int oldsize;
	CAnimationCompiler * pCompiler;
	int resSize;
	int id;
};


//typedef CrySimpleThread<ThreadCompiler> RCThreadCompiler;

class CAnimationCompiler :
	public IConvertor,
	public ICompiler
{
public:
	CAnimationCompiler(ICryXML * pXML);
	virtual ~CAnimationCompiler(void);

	class Error
	{
	public:
		Error (int nCode);
		Error (const char* szFormat, ...);
		const char* c_str()const {return m_strReason.c_str();}
	protected:
		string m_strReason;
	};

	virtual void Release();

	//! Initialize the convertor.
	// @param cc is the context of conversion; it contains valid directory and may contain fallback instruction.
	virtual void Init(IConfig* config, IRCLog* log, const char* exePath) {}

	//! Finalize the convertor.
	// @param cc is the context of conversion; it contains valid directory and may contain fallback instruction.
	virtual void DeInit() {}

	//! Process file
	//! \return success
	virtual bool Process( ConvertContext &cc );

	//! Construct the name of the file that will be produced from the source file.
	//! Put this name into outputFile field, if successful
	//! Returns true if successful or false if can't convert this file
	// @param cc is the context of conversion; it contains valid sourceFile and may or may not contain outputFile
	virtual bool GetOutputFile(ConvertContext &cc);

	//! Return an object that will do the actual processing. For some implementations, this may be
	//! the original object. Should not be called more than once if SupportsMultithreading() returns false.
	//! Otherwise multiple compilers can be called and run from separate threads.
	virtual ICompiler* CreateCompiler();

	//! Check whether the convertor supports multithreading. See CreateCompiler() for more details.
	virtual bool SupportsMultithreading() const;

	//! Return platforms supported by this convertor.
	virtual int GetNumPlatforms() const { return 2; };
	//! Get supported platform.
	//! @param index Index of platform must be in range 0 < index < GetNumPlatforms().
	virtual Platform GetPlatform( int index ) const { 

		if (index == 0)
			return PLATFORM_PC; 
		if (index == 1)
			return PLATFORM_XBOX;

		return PLATFORM_UNKNOWN;
	};

	//! Get number of supported extensions.
	virtual int GetNumExt() const { return 1; };
	//! Get supported extension.
	//! @param index Index of extension must be in range 0 < index < GetNumExt().
	virtual const char* GetExt( int index ) const { return "cba";};

	// this should retrieve the timestamp of the convertor executable:
	// when it was created by the linker, normally. This date/time is used to
	// compare with the compiled file date/time and even if the compiled file
	// is not older than the source file, it will be recompiled if it's older than the
	// convertor
	virtual DWORD GetTimestamp() const { return GetTimestampForLoadedLibrary(g_hInst);};

	void ReportMode(ConvertContext &cc, int iReportMode, const char * singleFile, ILoaderCGFListener* listener);

	void  FillFileList(std::vector<std::string>& list, const char * path, const char * ext, bool bRecursive);

	int ProcessSingleAnimation(CSkeletonInfo* currentSkeleton, const std::string& animFile, const std::string& destFile, ILoaderCGFListener * listener,
		ConvertContext &cc, SAnimationDesc& pDesc, int oldsize);//, bool bCleanup, bool bOnlyNew );

	const SCompilerBehavior & GetBehavior() const
	{
		return m_Behavior;
	}

	// tack stack initialisation
	void PrepareThreads();
	// return timesteps


public:
	ICryXML*	m_pXMLParser;

	bool m_bStatistics;
	uint32 m_TotalShared;
	uint32 m_TotalMemoryShared;
	uint32 m_TotalTracks;
	uint32 m_TotalMemory;

	int m_iCount;
	float m_fAverage;
	float m_fTotal;

	//int m_iThreads;
	std::vector<ThreadCompiler*> m_vThreads;

	std::auto_ptr<CTrackStorage> m_pTrackStorage;
	SCompilerBehavior m_Behavior;
	int m_refCount;
};

extern CAnimationCompiler * g_pAnimationCompiler;

#define SWAP 	if (g_pAnimationCompiler->GetBehavior().m_bNeedSwapEndian) 

/*
template <class T>
void swappod(T& t)
{
	if (g_pAnimationCompiler->GetBehavior().m_bNeedSwapEndian)
	{

		char * p = (char *)&t;
		for (uint32 i = 0; i < sizeof(t); i +=2)
		{
			std::swap(*(p + i), *(p + i + 1));	
		}
	}
}
*/


#endif