//
// Asura_ServerEntity_Template.h
//
// Created by Richard Rice - 31/03/2004
// 
// Copyright (C) 2004 Rebellion, All Rights Reserved.
//

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef __ASURA_SERVERENTITY_TEMPLATE_H__
#define __ASURA_SERVERENTITY_TEMPLATE_H__

#include "Core/Asura_Hash.h"
#include "Core/Asura_HashedList.h"
#include "Core/Asura_HeapArray.h"
#include "Entity/Asura_Entity.h"

#ifdef ASURA_TOOLS
#include "Entity/Asura_Entity_Classification.h"
#endif

struct Asura_TemplateEntityMessage;


#ifdef ASURA_TOOLS
//enumeration of types of thing that can be included in a template
enum Tools_EntityTemplate_ChildType
{
	Tools_EntityTemplate_ChildType_Entity = 0,
	Tools_EntityTemplate_ChildType_Phonon = 1,
	Tools_EntityTemplate_ChildType_Light = 2,
	Tools_EntityTemplate_ChildType_Corona = 3,
	Tools_EntityTemplate_ChildType_Attractor = 4,
	Tools_EntityTemplate_ChildType_StreamingSound = 5,
};

//class for storing the IDs/Guids of a particular type of object
class Tools_EntityTemplate_ChildIDArray
{
public :
	Tools_EntityTemplate_ChildIDArray(int iType);
	~Tools_EntityTemplate_ChildIDArray();

	int GetType() const {return m_iType;}

	int m_iNumIDs;
	u_int* m_puIDs;
private :
	int m_iType;

};

//Class for storing IDs/Guids of all the child objects in a template
class Tools_EntityTemplate_ChildIDHandler
{
public :
	~Tools_EntityTemplate_ChildIDHandler();

	Tools_EntityTemplate_ChildIDArray* GetArray(Tools_EntityTemplate_ChildType eType,bool bCreate = false);
	const Tools_EntityTemplate_ChildIDArray* GetArray(Tools_EntityTemplate_ChildType eType) const;

	void InitialiseFromChunkStream(Asura_Chunk_Stream& xStream ,int iVersion);
	void WriteToChunkStream(Asura_Chunk_Stream& xStream) const;
	int GetChunkBufferSize() const;

	void Clear();

	void SetIDList(Tools_EntityTemplate_ChildType eType,const List<u_int>& xIDList);
	bool Contains(Tools_EntityTemplate_ChildType eType,u_int uID) const;

private :
	List<Tools_EntityTemplate_ChildIDArray*> m_xTypeList;
};
#endif //ASURA_TOOLS

//Messageblock information for one input or output
struct Asura_TemplateEntityMessage
{
	Asura_Hash_ID m_uNameHash;//hashed value of name (which is stored elswhere
	u_short m_usMessageBlock;
};

class Asura_ServerEntity_Template : public Asura_Entity_Server
{
typedef Asura_Entity_Server PARENT;

friend class Tools_Entity_Template_Object;
friend class Tools_Entity_TemplateMaster_Object;
friend class Tools_Entity_TemplateInstance_Object;
friend class Tools_EntityTemplateInstanceMain;

public :
	Asura_ServerEntity_Template(Asura_Guid uGuid = ASURA_GUID_UNREGISTERED);
	~Asura_ServerEntity_Template();

	static void CreateFromChunkStream(Asura_Guid uGuid, Asura_Chunk_Stream& xStream);

	//constructor from load
	Asura_ServerEntity_Template(Asura_Guid uGuid,const char*& pcChunkBuffer);

	// override of HasClientEntities() - we don't have any.
	virtual bool HasClientEntities() const { return false; }

	virtual bool HandleMessage(const Asura_Message* pxMessage);

	virtual void Update();

	const Asura_HeapArray< Asura_Guid >& GetChildGuids() const { return m_xChildGuids; }

#ifdef ASURA_TOOLS
	bool IsMaster() const{return m_bMaster;}

	//gets a more detailed description of input/output triggers
	static const char* GetMessageDescription(const struct Asura_StaticMessage* pxMessage);
#endif

#ifdef ASURA_TOOLS
	virtual void ApplyChangesForTemplateInstance(class Tools_EntityTemplateInstance* pxInstance);
	virtual bool CanBeIncludedInTemplate() const {return Classification == AsuraEntityClass_Template;}

	void UpdateInputsAndOutputs(class Tools_EntityTemplateInstance* pxInstance,const struct Tools_EntityTemplateInfo* pxTemplate);

	//forces this instance to be updated from its template , the next time updates are done
	void FlagForUpdate(){if(!IsMaster() && m_iTemplateVersion>=0) m_iTemplateVersion = 0;}
	//For de-templatifying a template instance. Sets template version to special
	//value to indicate that it should never be updated again
	void FlagForNeverUpdate(){if(!IsMaster()) m_iTemplateVersion = -1;}
	bool ShouldNeverUpdate(){return m_iTemplateVersion==-1;}

	//returns true if the guid is in the list of child entities
	bool EntityBelongsToTemplate(Asura_Guid uGuid) const;
	bool AttractorBelongsToTemplate(u_int uID) const;

	const Asura_Vector_3& GetPosition() const {return m_xPosition;}

	Asura_Hash_ID GetReplacementSkinID() const {return m_uReplacementSkinID;}
	void SetReplacementSkinID(Asura_Hash_ID uSkinID) {m_uReplacementSkinID = uSkinID;}

	void SetMergeWithEnvironment(bool bSet) {m_bMergeWithEnvironment = bSet;}
#endif

	#ifdef ASURA_TOOLS
	virtual bool SupportsCustomEvents() const { return true; }
	virtual int GetNumCustomEvents() const;
	virtual unsigned short* GetCustomEvent(int iIndex);
	virtual void GetCustomEventName(int iEventIndex, Asura_String& xEventName);
	#endif


	#ifdef ASURA_TOOLS
	int GetNumInputNames() { return m_iNumInputNames; }
	Asura_String* GetInputNames() { return m_pxInputNames; }

	int GetNumOutputNames() { return m_iNumOutputNames; }
	Asura_String* GetOutputNames() { return m_pxOutputNames; }
	#endif

protected :
	//virtual function overides for saving
	virtual bool CanBeSavedToChunk() const {return true;}
//		int GetChunkBufferSize();
//		void FillInChunkBuffer(char*& chunkBuffer);

	virtual	bool IsFilledFromChunkBuffer(void) const { return false; }

	//virtual function overides for saving
	virtual	void ReadFromChunkStream(Asura_Chunk_Stream& xStream);
	virtual	void WriteToChunkStream(Asura_Chunk_Stream& xStream) const;


#ifdef ASURA_TOOLS
	//get size of tools specific chunk data
	int GetToolsDataSize() const;
	//recreate m_xChildGuids which exists outside tools from the tools data.
	void UpdateGuidListFromToolsData();
	// set each child's version of the template active flag.
	void UpdateChildrenTemplateActiveFlag();
#endif

	// overrides of OnEntityActivate()/OnEntityDeactivate() - called when active status changes or is initialised. 
	// Derived classes should always call parent versions if they override them. 
	virtual	void OnEntityActivate(void);
	virtual	void OnEntityDeactivate(void);

	//Sends the messages associated with an input
	void TriggerInput(Asura_Hash_ID uInput) const;

	//Inputs send messages to entities within the template
	//These are only editable on the template masters
	int m_iNumInputs;
	Asura_TemplateEntityMessage* m_pxInputs;

	//Outputs send messages to entities in the level
	//The message blocks for these are only editable on template instances
	int m_iNumOutputs;
	Asura_TemplateEntityMessage* m_pxOutputs;

	// duplicate of a small part of the tools data in game-friendly format (could be refactored but no harm having it twice)
	Asura_HeapArray<Asura_Guid> m_xChildGuids;

	//Inputs to be triggered during the first frame to set the initial state of the template
	Asura_HeapArray<Asura_Hash_ID> m_xInitialInputsToTrigger;
	
	//tools specific data
#ifdef ASURA_TOOLS
	Asura_String m_xName;
	Asura_Vector_3 m_xPosition;
	Asura_Matrix_3x3 m_xOrient;

	Tools_EntityTemplate_ChildIDHandler m_xChildIDHandler;


	//version number used to determine whether a template instance needs to be updated
	//from the master template
	mutable int m_iTemplateVersion;

	//input name array should always match up with the inputs above
	int m_iNumInputNames;
	Asura_String* m_pxInputNames;

	//output name array won't directly correspond with the outputs , since the
	//outputs array will only contain the outputs that are actually used.
	int m_iNumOutputNames;
	Asura_String* m_pxOutputNames;

	Asura_Hash_ID m_uReplacementSkinID;//Skin ID to use on member physical object instead of the one defined in the template
#endif //ASURA_TOOLS


	bool m_bMaster;//Is master template entity (should be one per template file)

	union
	{
		u_int m_uFlags;
		struct
		{
			u_int m_bSentInitialMessages : 1;//Indicates whether the initial inputs have been triggered yet
			u_int m_bMergeWithEnvironment : 1;//sets the merge with environment flag in child physics objects
		};
	};


public:
	static Asura_ServerEntity_Template* FindEntity(Asura_Guid uGuid)
	{
		return s_xList.FindEntity(uGuid);
	}

	static const Asura_Hashed_List<Asura_ServerEntity_Template>* GetList()
	{
		return &s_xList;
	}


private:
	static Asura_Hashed_List<Asura_ServerEntity_Template> s_xList;
};

#ifdef ASURA_TOOLS
struct Tools_EntityTemplateInfo
{
	Tools_EntityTemplateInfo(const char* pcChunkBuffer);
	~Tools_EntityTemplateInfo();
	
	bool m_bValid;

	Asura_String m_xName;
	Asura_Vector_3 m_xPosition;
	Asura_Matrix_3x3 m_xOrient;

	Tools_EntityTemplate_ChildIDHandler m_xChildIDHandler;

	int m_iTemplateVersion;

	//Inputs send messages to entities within the template
	//These are only editable on the template masters
	int m_iNumInputs;
	Asura_TemplateEntityMessage* m_pxInputs;

	//Outputs send messages to entities in the level
	//The message blocks for these are only editable on template instances
	int m_iNumOutputs;
	Asura_TemplateEntityMessage* m_pxOutputs;

	//input name array should always match up with the inputs above
	int m_iNumInputNames;
	Asura_String* m_pxInputNames;

	//output name array won't directly correspond with the outputs , since the
	//outputs array will only contain the outputs that are actually used.
	int m_iNumOutputNames;
	Asura_String* m_pxOutputNames;

};
#endif



//This message is saved out to static message system , so care needs to be taken about altering it
struct Asura_Message_Template_Trigger 
{
	Asura_Hash_ID m_uNameHash;//hash ID of input/output to trigger
};

#endif //__ASURA_SERVERENTITY_TEMPLATE_H__


