//
// Asura_FSFX_System.h
//
// Created by JGP 02/02/06
// 
// Copyright (C) 2006 Rebellion (Derby), All Rights Reserved.
//

#ifdef ASURA_USE_PRAGMA_ONCE
#pragma once
#endif

#ifdef ASURA_USE_FSFX

#ifndef __ASURA_FSFX_SYSTEM_H__
#define __ASURA_FSFX_SYSTEM_H__

#include "Core/Asura_LinkList.h"
#include "Core/Asura_String.h"
#include "Core/Asura_TemplateTree.h"
#include "Core/Resources/Asura_ResourceSet.h"
#include "Core/Resources/Asura_ResourceSetWithOverride.h"
#include "FSFX/Asura_FSFX_Template.h"
#include "Network/Asura_Guid.h"


// Forward declarations...
class Asura_Chunk_Stream;
class Asura_NetMsg;

/*
	Message structure
*/
struct Asura_FSFX_Message
{
	Asura_Hash_ID m_xID;
	float m_fValue;
	float m_fTime;

#ifdef ASURA_NETMSG_PACK_ALL_DATA
	void RegisterFields(Asura_NetMsg* pxNetMsg) const;
	static u_char GetNumFields() { return 3; }
#endif
};

typedef Asura_ResourceSetWithOverride<Asura_FSFX_Template>								Asura_FSFX_Template_ResourceSet;

#ifdef ASURA_TOOLS
typedef Asura_ResourceSetOverrideMap<Asura_FSFX_Template>								Asura_FSFX_Template_OverrideMap;

typedef Asura_ResourceSetOverride<Asura_FSFX_Template>									Asura_FSFX_Template_OverrideEntry;

// Iterate over a Resource set to enumerate the resources
typedef Asura_ResourceSetWithOverride_ResourceIterator<Asura_FSFX_Template>				Asura_FSFX_Template_ResourceSet_ResourceIterator;

typedef Asura_ResourceSetWithOverride_ConstResourceIterator<Asura_FSFX_Template>		Asura_FSFX_Template_ResourceSet_ConstResourceIterator;

// Iterate over a Resource set to enumerate the override maps
typedef Asura_ResourceSetWithOverride_ConstOverrideMapIterator<Asura_FSFX_Template>		Asura_FSFX_Template_ResourceSet_ConstMapIterator;

typedef Asura_ResourceSetWithOverride_OverrideMapIterator<Asura_FSFX_Template>			Asura_FSFX_Template_ResourceSet_MapIterator;

// Iterate over an override map to enumerate the overrides
typedef Asura_ResourceSetOverrideMap_ConstIterator<Asura_FSFX_Template>					Asura_FSFX_Template_ConstIterator;

typedef Asura_ResourceSetOverrideMap_Iterator<Asura_FSFX_Template>						Asura_FSFX_Template_Iterator;

#endif



////////////////////////////////////////////////////////////////////////////////
// Class        : Asura_FSFX_HandlerItem
// Author       : Andy Tate
// Date         : 26-Jun-2008
//
// Description  : Class used to store the current data for a particular FSFX
//				  template for a given handler.
////////////////////////////////////////////////////////////////////////////////

class Asura_FSFX_HandlerItem
{
public:
	// Public functions...
	Asura_FSFX_HandlerItem(void)																{ Reset(); }
	Asura_FSFX_HandlerItem(Asura_Hash_ID xTemplateHash, Asura_Chunk_Stream& xStream)	{ ReadFromChunkStream(xStream); }
	//~Asura_FSFX_HandlerItem();

	// Manipulation functions...
	void	Reset(void);
	void	Update(const float fTimeStep);

	// Chunk-stream functions...
	void WriteToChunkStream(Asura_Chunk_Stream& xStream) const;
	void ReadFromChunkStream(Asura_Chunk_Stream& xStream);

	// Accessor functions...
	void SetTarget(const float fValue, const float fTime)
	{
		m_fCurrentTime		= 0.0f;
		m_fInitialValue		= m_fCurrentValue;
		m_fSustainValue		= m_fFinalValue		= fValue;
		m_fAttackEndTime	= m_fSustainEndTime	= m_fDecayEndTime	= fTime;
	}

	void SetTargetAttackSustainDecay(const float fSustainValue, const float fReleaseValue,
									 const float fAttackDuration, const float fSustainDuration, const float fDecayDuration)
	{
		m_fCurrentTime		= 0.0f;
		m_fInitialValue		= m_fCurrentValue;
		m_fSustainValue		= fSustainValue;
		m_fFinalValue		= fReleaseValue;
		m_fAttackEndTime	= fAttackDuration;
		m_fSustainEndTime	= m_fAttackEndTime + fSustainDuration;
		m_fDecayEndTime		= m_fSustainEndTime + fDecayDuration;
	}

	void SetValue(const float fValue)
	{
		SetTarget(fValue, 0.0f);
	}

	float GetValue(void) const
	{
		return(m_fCurrentValue);
	}


protected:
	// Protected variables...

	// Protected functions...


private:
	// Private variables...
	float	m_fCurrentTime;		// The time we've been used for this item.
	float	m_fCurrentValue;	// The current value of this item.

	float	m_fInitialValue;	// The initial value of this item.
	float	m_fSustainValue;	// The value to sustain for a given period of time.
	float	m_fFinalValue;		// The final value of this item.

	float	m_fAttackEndTime;	// The time when we've finished ramping up the value.
	float	m_fSustainEndTime;	// The time when we've finished keeping the value the same.
	float	m_fDecayEndTime;	// The time when we've finished ramping down the value.

	// Private functions...
	Asura_FSFX_HandlerItem(const Asura_FSFX_HandlerItem& xOther);

	Asura_FSFX_HandlerItem&	operator=(const Asura_FSFX_HandlerItem& xOther);

};   // End of class 'Asura_FSFX_HandlerItem'.



/*
	Handler class
*/
class Asura_FSFX_Handler
{

public:

	Asura_FSFX_Handler( const Asura_Guid xOwnerGuid );
	//~Asura_FSFX_Handler();

	// Manipulation functions...
	void Update();
	void Render() const;

	void ResetAllTemplates();
	void ResetEnvironmentalTemplates();
	void ResetValue(const Asura_Hash_ID uNameHash);
	void SetValue( const Asura_Hash_ID uNameHash, const float fValue, const float fTime = 0.0f );
	void SetAttackSustainDecayValues(const Asura_Hash_ID uNameHash, const float fSustainValue, const float fReleaseValue, const float fAttackDuration, const float fSustainDuration, const float fDecayDuration);

	bool GetValue( const Asura_Hash_ID uNameHash, float &fReturnValue  );	// Return true if the value was found.

	// Chunk-stream functions...
	void WriteToChunkStream(Asura_Chunk_Stream& xStream) const;
	void ReadFromChunkStream(Asura_Chunk_Stream& xStream);

	// Accessor functions...
	Asura_Guid GetOwnerGuid() const	{ return(m_xOwnerGuid); }


private:
	// Private typedefs...
	typedef Asura_TemplateTree<Asura_Hash_ID, Asura_FSFX_HandlerItem> TemplateContainer;
	typedef Asura_TemplateTree_Iterator<Asura_Hash_ID, Asura_FSFX_HandlerItem> TemplateIterator;
	typedef Asura_TemplateTree_ConstIterator<Asura_Hash_ID, Asura_FSFX_HandlerItem> TemplateConstIterator;

	// Private variables...
	Asura_Guid			m_xOwnerGuid;
	TemplateContainer	m_xTemplateContainer;

	// Private functions...
	static int	CompareTemplates(const Asura_Hash_ID& xTemplate1, const Asura_Hash_ID& xTemplate2);
};


/*
	System class
*/

// Note that all templates are held in memory all the time, in case ASURA_TOOLS is defined. Othervise, the templates are loaded and discarded depending on the current level.
class Asura_FSFX_System
{

public:

	friend class Asura_FSFX_Handler;
#ifdef ASURA_TOOLS
	friend class Tools_FSFX_System;
#endif

	// singleton access

	static void Initialise();
	static void Reset();
	static void Shutdown();

	// render
	static void Update();
	static void Render();

	// templates
	static bool							AddTemplate( Asura_FSFX_Template* const pxTemplate );
	static u_int						GetNumTemplates()	{ return(s_xTemplateContainer.GetNumResources()); }

#ifdef ASURA_TOOLS
	static Asura_FSFX_Template*			GetTemplateByIndex( const u_int uIndex );
	static Asura_FSFX_Template* const	FindTemplate( const char* const szName );
	static Asura_FSFX_Template* const	FindTemplateWithoutOverride( const char* const szName );
	static void							DeleteTemplate( const Asura_Hash_ID uResourceHash );
	static void							RelocateTemplate(const Asura_Hash_ID uOldResourceHash, const Asura_Hash_ID uNewResourceHash);
	static Asura_FSFX_Template*			FindTemplate( const Asura_Hash_ID uTemplateHash );
	static Asura_FSFX_Template*			FindTemplateWithoutOverride( const Asura_Hash_ID uTemplateHash );

	// caller is responsible for delete[]ing pxNameArray!
	static void GetTemplateNames(Asura_String* &pxNameArray, int &iNumEntries);
#else

	static const Asura_FSFX_Template*	FindTemplate( const Asura_Hash_ID uTemplateHash );

#endif


	// handlers
	static void							ClearAllHandlerTemplates(void);
	static Asura_FSFX_Handler*			AddHandler( const Asura_Guid xOwnerGuid );
	static Asura_FSFX_Handler*			FindHandler( const Asura_Guid xOwnerGuid );
	static void							RemoveHandler( Asura_FSFX_Handler* const pxHandler );

	static void	SetValueForAllHandlers(const Asura_Hash_ID uTemplateHash, const float fValue, const float fTime = 0.0f);

	static float GetFirstValueFromAllHandlers(const Asura_Hash_ID uTemplateHash );


	static void EnableOverrideMap(Asura_Hash_ID uHash, bool bDisableAllPreviouslyEnabledMaps = true) { s_xTemplateContainer.EnableOverrideMap(uHash, bDisableAllPreviouslyEnabledMaps);}
	static void DisableOverrideMap(Asura_Hash_ID uHash) { s_xTemplateContainer.DisableOverrideMap(uHash);}
	static bool IsOverrideMapEnabled(Asura_Hash_ID uHash)	{ return s_xTemplateContainer.IsOverrideMapEnabled(uHash); }
	static void DisableAllOverrideMaps()					{ s_xTemplateContainer.DisableAllOverrideMaps();	}

	static Asura_ResourceSetOverrideMap<Asura_FSFX_Template> *	AllocateOverrideMap(Asura_Hash_ID uHash)	{ return s_xTemplateContainer.AllocateOverrideMap(uHash); }
	static Asura_ResourceSetOverrideMap<Asura_FSFX_Template>*	GetOverrideMapByHash(Asura_Hash_ID uHash)	{ return s_xTemplateContainer.GetOverrideMapByHash(uHash); }
	static void FreeOverrideMap(Asura_Hash_ID uHash)										{ s_xTemplateContainer.FreeOverrideMap(uHash); }
	static void FreeAllOverrideMaps()														{ s_xTemplateContainer.FreeAllOverrideMaps(); }

	static u_int GetNumOverrideMaps()		{ return s_xTemplateContainer.GetNumOverrideMaps();}
	static u_int GetNumEnabledOverrideMaps(){ return s_xTemplateContainer.GetNumEnabledOverrideMaps();}

	static Asura_Hash_ID GetOverride(Asura_Hash_ID uHash) { return s_xTemplateContainer.GetOverride(uHash);}

	static Asura_FSFX_Template_ResourceSet &GetResourceSet() {return s_xTemplateContainer;}

private:
	// Private typedefs...
	typedef Asura_ListElt<Asura_FSFX_Handler*> HandlerContainerElement;
	typedef Asura_LinkList<Asura_FSFX_Handler*> HandlerContainer;
	typedef Asura_LinkList_It<Asura_FSFX_Handler*> HandlerIterator;
	typedef Asura_LinkList_ConstIt<Asura_FSFX_Handler*> HandlerConstIterator;

	typedef Asura_FSFX_Template_ResourceSet TemplateContainer;
	typedef Asura_ResourceSetWithOverride_ResourceIterator<Asura_FSFX_Template> TemplateIterator;
	typedef Asura_ResourceSetWithOverride_ConstResourceIterator<Asura_FSFX_Template> TemplateConstIterator;

	// private functions

	static void Platform_Initialise();
	static void Platform_Reset();
	static void Platform_Shutdown();
	static void Platform_BeginRender();
	static void Platform_EndRender();

	static void PlatformProject_Initialise();
	static void PlatformProject_Reset();
	static void PlatformProject_Shutdown();

//	static void ClearTemplates();



	// variables
	static TemplateContainer	s_xTemplateContainer;	// Note that all templates are held in memory all the time, in case ASURA_TOOLS is defined.
	static HandlerContainer		s_xHandlerContainer;

};


#endif // __ASURA_FSFX_SYSTEM_H__

#endif // ASURA_USE_FSFX
