/**
*
* \file Asura_ServerEntity_AdvancedLight.h
*
* Created by Richard May - 07/01/2003 10:08:30
*
* Copyright (C) 2002 Rebellion, All Rights Reserved.
*
* \brief
*
**/


#ifdef ASURA_USE_PRAGMA_ONCE
	#pragma once
#endif

#ifndef __ASURA_SERVERENTITY_ADVANCEDLIGHT_H__
#define __ASURA_SERVERENTITY_ADVANCEDLIGHT_H__

#ifndef ASURA_TARGET_SM3

/************/
/* Includes.*/
/************/

#include "Entity/PhysicalObject/Asura_ServerEntity_DestructibleLight.h"

/************/
/* Classes. */
/************/

/*************************************************************
 *
 * Class Name    : Asura_ServerEntity_AdvancedLight
 *
 * Author        : Richard May
 *
 * Description   : This is a light class that can utilise various
 *				   flicker/strobe and light timing effects, as well
 *				   as variable light volumes, etc. This is derived
 *				   from Asura_ServerEntity_DestructibleLight although
 *				   it may be in actuality and invulnerable light
 *
 *************************************************************/
class Asura_ServerEntity_AdvancedLight : public virtual Asura_ServerEntity_DestructibleLight
{

	friend class Asura_Message_AdvancedLight_ClientUpdate;
	friend class Asura_Message_AdvancedLight_Create;
	friend class Tools_Entity_AdvancedLight;

protected:

	/* Constructors/destructor. */
	Asura_ServerEntity_AdvancedLight	();
	virtual ~Asura_ServerEntity_AdvancedLight	();

	// ChunkData
	struct ChunkData
	{
		enum {CURRENT_VERSION = 4};

		// flicker & strobe
		float m_fMinTimeOff;
		float m_fMaxTimeOff;
		float m_fMinTimeOn;
		float m_fMaxTimeOn;

		// colour fade 
		float m_fEndColourR;
		float m_fEndColourG;
		float m_fEndColourB;
		
		float m_fStartColourR;
		float m_fStartColourG;
		float m_fStartColourB;
		
		float m_fMaxFadeDownDuration;
		float m_fMinFadeDownDuration;
		float m_fMaxFadeUpDuration;
		float m_fMinFadeUpDuration;
		
		float m_fMinStartColourTime;
		float m_fMaxStartColourTime;
		float m_fMinEndColourTime;
		float m_fMaxEndColourTime;

		// radius change 
		float m_fStartRadius;
		float m_fEndRadius;
				
		float m_fMaxRadiusDownDuration;
		float m_fMinRadiusDownDuration;
		float m_fMaxRadiusUpDuration;
		float m_fMinRadiusUpDuration;
		
		float m_fMinStartRadiusTime;
		float m_fMaxStartRadiusTime;
		float m_fMinEndRadiusTime;
		float m_fMaxEndRadiusTime;
		
		union
		{
			unsigned int m_uFlags;
			struct
			{
				// NOTE: These bit's are written out, adding any new bits means
				// ~~~~~ that you will need to add those bits to the bitfield
				//       preparation code in "WriteToChunkStream".
				unsigned int m_uLoopFade : 1,
							 m_uLoopRadius : 1,
							 m_uUseMasterOrient : 1,
							 m_uActive : 1, // on/off boolean
							 Unused : 28;
			};
		};
		// attached entity stuff
		Asura_Guid m_uMasterEntity;
		Asura_Vector_3 m_xOffsetFromMaster;
		Asura_Hash_ID m_uMasterMarker;
	};
	
	// ChunkData
	struct ChunkData_v3
	{

		// flicker & strobe
		float m_fMinTimeOff;
		float m_fMaxTimeOff;
		float m_fMinTimeOn;
		float m_fMaxTimeOn;

		// colour fade 
		float m_fEndColourR;
		float m_fEndColourG;
		float m_fEndColourB;
		
		float m_fStartColourR;
		float m_fStartColourG;
		float m_fStartColourB;
		
		float m_fMaxFadeDownDuration;
		float m_fMinFadeDownDuration;
		float m_fMaxFadeUpDuration;
		float m_fMinFadeUpDuration;
		
		float m_fMinStartColourTime;
		float m_fMaxStartColourTime;
		float m_fMinEndColourTime;
		float m_fMaxEndColourTime;

		// radius change 
		float m_fStartRadius;
		float m_fEndRadius;
				
		float m_fMaxRadiusDownDuration;
		float m_fMinRadiusDownDuration;
		float m_fMaxRadiusUpDuration;
		float m_fMinRadiusUpDuration;
		
		float m_fMinStartRadiusTime;
		float m_fMaxStartRadiusTime;
		float m_fMinEndRadiusTime;
		float m_fMaxEndRadiusTime;
		
		union
		{
			unsigned int m_uFlags;
			struct
			{
				unsigned int m_uLoopFade : 1,
							 m_uLoopRadius : 1,
							 m_uUseMasterOrient : 1,
							 m_uActive : 1, // on/off boolean
							 Unused : 28;
			};
		};
		// attached entity stuff
		Asura_Guid m_uMasterEntity;
		Asura_Vector_3 m_xOffsetFromMaster;
	};
	
	// ChunkData
	struct ChunkData_v2
	{
		// flicker & strobe
		float m_fMinTimeOff;
		float m_fMaxTimeOff;
		float m_fMinTimeOn;
		float m_fMaxTimeOn;
		
		// colour fade 
		float m_fEndColourR;
		float m_fEndColourG;
		float m_fEndColourB;
		
		float m_fStartColourR;
		float m_fStartColourG;
		float m_fStartColourB;
		
		float m_fMaxFadeDownDuration;
		float m_fMinFadeDownDuration;
		float m_fMaxFadeUpDuration;
		float m_fMinFadeUpDuration;
		
		float m_fMinStartColourTime;
		float m_fMaxStartColourTime;
		float m_fMinEndColourTime;
		float m_fMaxEndColourTime;
		
		// radius change 
		float m_fStartRadius;
		float m_fEndRadius;
		
		float m_fMaxRadiusDownDuration;
		float m_fMinRadiusDownDuration;
		float m_fMaxRadiusUpDuration;
		float m_fMinRadiusUpDuration;
		
		float m_fMinStartRadiusTime;
		float m_fMaxStartRadiusTime;
		float m_fMinEndRadiusTime;
		float m_fMaxEndRadiusTime;
		
		union
		{
			unsigned int m_uFlags;
			struct
			{
				unsigned int m_ucLoopFade : 1;
				unsigned int m_ucLoopRadius : 1;
				unsigned int m_ucUseMasterOrient : 1;
			};
		};		
		
		// attached entity stuff
		Asura_Guid m_uMasterEntity;
		Asura_Vector_3 m_xOffsetFromMaster;
	};


public:
	/* Public interface functions. */
	virtual void Update();
	virtual bool HandleMessage(const Asura_Message* pxMessage);
	
//	virtual	bool	IsFilledFromChunkBuffer		(void) const;

	virtual	int		GetChunkBufferSize			(void)	{ return sizeof(ChunkData) + sizeof(int) + Asura_ServerEntity_DestructibleLight::GetChunkBufferSize(); }
	virtual	void	FillInChunkBuffer			(char*& pcChunkBuffer);
	virtual void	InitialiseFromChunkBuffer	(const char*& pcChunkBuffer);

	virtual	void	WriteToChunkStream			(Asura_Chunk_Stream& xStream) const;
	virtual	void	ReadFromChunkStream			(Asura_Chunk_Stream& xStream);

	void SetStrobe( float fMaxOn, float fMinOn, float fMaxOff, float fMinOff );
	
	void SetFadeColours( float fStartR, float fStartG, float fStartB, float fEndR, float fEndG, float fEndB );
	void SetFadeDurations( float fMaxDownTime, float fMinDownTime, float fMaxUpTime, float fMinUpTime );
	void SetFadeEndColourDurations( float fMaxStartTime, float fMinStartTime, float fMaxEndTime, float fMinEndTime );
	void SetFadeLoop( bool bLoop );

	void SetRadii( float fStartRadius, float fEndRadius );
	void SetRadiusChangeDurations( float fMaxDownTime, float fMinDownTime, float fMaxUpTime, float fMinUpTime );
	void SetRadiusEndDurations( float fMaxStartTime, float fMinStartTime, float fMaxEndTime, float fMinEndTime );
	void SetRadiusChangeLoop( bool bLoop );

	#ifdef ASURA_TOOLS
	virtual void ApplyChangesForTemplateInstance(class Tools_EntityTemplateInstance* pxInstance);
	#endif

	bool GetStartsActive() const { return m_uActive; }

	static Asura_ServerEntity_AdvancedLight* FindEntity( Asura_Guid uGUID ) { return s_xList.FindEntity( uGUID ); }
	static const Asura_Hashed_List<Asura_ServerEntity_AdvancedLight>* GetList( void ) { return &s_xList; }

protected:
	/* Helper functions. */
	virtual void MakeClientUpdateMessage();
	virtual bool GetHasCreateMessage() const { return true; }
	virtual void MakeCreateMessage(Asura_Guid uRequestingClient, bool bSendGuaranteed = false);

protected:
	/* Data. */

	// on/off params (for flicker & strobe)
	float m_fMinTimeOff;
	float m_fMaxTimeOff;
	float m_fMinTimeOn;
	float m_fMaxTimeOn;

	// colour fade params
	float m_fEndColourR;
	float m_fEndColourG;
	float m_fEndColourB;
	
	float m_fStartColourR;
	float m_fStartColourG;
	float m_fStartColourB;

	float m_fMaxFadeDownDuration;
	float m_fMinFadeDownDuration;
	float m_fMaxFadeUpDuration;
	float m_fMinFadeUpDuration;

	float m_fMinStartColourTime;
	float m_fMaxStartColourTime;
	float m_fMinEndColourTime;
	float m_fMaxEndColourTime;

	
	// radius change 
	float m_fStartRadius;
	float m_fEndRadius;
				
	float m_fMaxRadiusDownDuration;
	float m_fMinRadiusDownDuration;
	float m_fMaxRadiusUpDuration;
	float m_fMinRadiusUpDuration;
	
	float m_fMinStartRadiusTime;
	float m_fMaxStartRadiusTime;
	float m_fMinEndRadiusTime;
	float m_fMaxEndRadiusTime;
	
	union
	{
		u_int	m_uAdvLightFlags;

		struct
		{
			// NOTE: These bit's are written out, adding any new bits means
			// ~~~~~ that you will need to add those bits to the bitfield
			//       preparation code in "WriteToChunkStream".
			unsigned int m_uLoopRadius : 1;
			unsigned int m_uLoopFade : 1;
			unsigned int m_uUseMasterOrient : 1;
			unsigned int m_uActive : 1;
		};
	};

	// attached entity stuff
	Asura_Guid m_uMasterEntity;
	Asura_Vector_3 m_xOffsetFromMaster;
	Asura_Hash_ID m_uMasterMarker;//optional marker point on master to attach this light to

private:
	typedef Asura_ServerEntity_DestructibleLight PARENT;

	static Asura_Hashed_List<Asura_ServerEntity_AdvancedLight> s_xList;
};
/* end of class Asura_ServerEntity_AdvancedLight */


/************/
/* Messages */
/************/

class Asura_Message_AdvancedLight_ClientUpdate : public Asura_Message_DestructibleLight_ClientUpdate
{	
public:
	
	union 
	{
		u_char m_ucAdvLightFlags;
		struct 
		{
			u_char m_bActive:1;
		};
	};

    void FillAdvancedLight(const class Asura_ServerEntity_AdvancedLight* pxObject)
    {
		FillDestructibleLight(pxObject);
		m_bActive = pxObject->m_uActive;
	}

#ifdef ASURA_SUPPORT_NETMSG_SYSTEM
	static void RegisterFields(u_short usMsgID, u_short usEntityClassification);
	static void RegisterFields(class Asura_NetMsg* pxNetMsg);
	static u_char GetNumFields() { return static_cast< u_char >( 1 + Asura_Message_DestructibleLight_ClientUpdate::GetNumFields() ); }
#endif//#ifdef ASURA_SUPPORT_NETMSG_SYSTEM
};

/// Richard May - 16/01/2003 16:10:32 - Note that the create message sneakily inherits from
/// the destructible lights client update message _on purpose_, as otherwise the data
/// you need for creating the AdvancedLight will not be there. Creating destructible lights
/// can be done from the ClientUpdate, which is why there is no DestructibleLight_Create message 
/// to inherit from
class Asura_Message_AdvancedLight_Create : public Asura_Message_DestructibleLight_ClientUpdate
{
public:
	// flicker
	float m_fMinTimeOff;
	float m_fMaxTimeOff;
	float m_fMinTimeOn;
	float m_fMaxTimeOn;

	// colour fade
	float m_fEndColourR;
	float m_fEndColourG;
	float m_fEndColourB;
	
	float m_fStartColourR;
	float m_fStartColourG;
	float m_fStartColourB;
	
	float m_fMaxFadeDownDuration;
	float m_fMinFadeDownDuration;
	float m_fMaxFadeUpDuration;
	float m_fMinFadeUpDuration;
	
	float m_fMinStartColourTime;
	float m_fMaxStartColourTime;
	float m_fMinEndColourTime;
	float m_fMaxEndColourTime;
	

	// radius change 
	float m_fStartRadius;
	float m_fEndRadius;
				
	float m_fMaxRadiusDownDuration;
	float m_fMinRadiusDownDuration;
	float m_fMaxRadiusUpDuration;
	float m_fMinRadiusUpDuration;
	
	float m_fMinStartRadiusTime;
	float m_fMaxStartRadiusTime;
	float m_fMinEndRadiusTime;
	float m_fMaxEndRadiusTime;

	// Attached entity stuff
	Asura_Guid m_uMasterEntity;
	Asura_Vector_3 m_xOffsetFromMaster;
	Asura_Hash_ID m_uMasterMarker;

	unsigned int m_uLoopFade : 1;
	unsigned int m_uLoopRadius : 1;
	unsigned int m_uUseMasterOrient : 1;
	unsigned int m_uActive : 1;

    void FillAdvancedLight(const class Asura_ServerEntity_AdvancedLight* pxObject)
    {
		FillDestructibleLight(pxObject);
		
		// flicker & strobe
		m_fMinTimeOff = pxObject->m_fMinTimeOff;
		m_fMaxTimeOff = pxObject->m_fMaxTimeOff;
		m_fMinTimeOn  = pxObject->m_fMinTimeOn;
		m_fMaxTimeOn  = pxObject->m_fMaxTimeOn;

		// colour fade
		m_fEndColourR = pxObject->m_fEndColourR;
		m_fEndColourG = pxObject->m_fEndColourG;
		m_fEndColourB = pxObject->m_fEndColourB;
		
		m_fStartColourR = pxObject->m_fStartColourR;
		m_fStartColourG = pxObject->m_fStartColourG;
		m_fStartColourB = pxObject->m_fStartColourB;
		
		m_fMaxFadeDownDuration = pxObject->m_fMaxFadeDownDuration;
		m_fMinFadeDownDuration = pxObject->m_fMinFadeDownDuration;
		m_fMaxFadeUpDuration = pxObject->m_fMaxFadeUpDuration;
		m_fMinFadeUpDuration = pxObject->m_fMinFadeUpDuration;
		
		m_fMinStartColourTime = pxObject->m_fMinStartColourTime;
		m_fMaxStartColourTime = pxObject->m_fMaxStartColourTime;
		m_fMinEndColourTime = pxObject->m_fMinEndColourTime;
		m_fMaxEndColourTime = pxObject->m_fMaxEndColourTime;

		m_uLoopFade = pxObject->m_uLoopFade;
		
		// radius change 
		m_fStartRadius = pxObject->m_fStartRadius;
		m_fEndRadius = pxObject->m_fEndRadius;
		
		m_fMaxRadiusDownDuration = pxObject->m_fMaxRadiusDownDuration;
		m_fMinRadiusDownDuration = pxObject->m_fMinRadiusDownDuration;
		m_fMaxRadiusUpDuration = pxObject->m_fMaxRadiusUpDuration;
		m_fMinRadiusUpDuration = pxObject->m_fMinRadiusUpDuration;
		
		m_fMinStartRadiusTime = pxObject->m_fMinStartRadiusTime;
		m_fMaxStartRadiusTime = pxObject->m_fMaxStartRadiusTime;
		m_fMinEndRadiusTime = pxObject->m_fMinEndRadiusTime;
		m_fMaxEndRadiusTime = pxObject->m_fMaxEndRadiusTime;
		
		m_uLoopRadius = pxObject->m_uLoopRadius;

		// Attached entity stuff
		m_uMasterEntity = pxObject->m_uMasterEntity;
		m_xOffsetFromMaster = pxObject->m_xOffsetFromMaster;
		m_uUseMasterOrient = pxObject->m_uUseMasterOrient;
		m_uMasterMarker = pxObject->m_uMasterMarker;
		m_uActive = pxObject->m_uActive;
    }
};


/****************/
/* End of file. */
/****************/
#endif // #ifndef ASURA_TARGET_SM3

#endif//__ASURA_SERVERENTITY_ADVANCEDLIGHT_H__
