//
// Tools_Entity_Template_Object.h
//
// Created by Richard Rice - 05/04/2004
// 
// Copyright (C) 2004 Rebellion, All Rights Reserved.
//


#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef _TOOLS_ENTITY_TEMPLATE_OBJECT_H_
#define _TOOLS_ENTITY_TEMPLATE_OBJECT_H_

#include "Entity/Tools_Entity_Object.h"
class Asura_Dialog;

//////////////////////////////////////////////////////////////////////////////////////////////////
/*------------------------------**
** Tools_Entity_Template_Object **
**------------------------------*/

class Tools_Entity_Template_Object : public Tools_Entity_Object
{
	typedef Tools_Entity_Object PARENT;

protected :
	Tools_Entity_Template_Object(Asura_Entity* pxEntity)
	:Tools_Entity_Object(pxEntity) { s_xList.AddToList(this); };

public :
	~Tools_Entity_Template_Object()
	{
		s_xList.RemoveFromList(this);
	}

	static Tools_Object* CreateToolsObject(Asura_Entity* pxEntity);

	static Tools_Entity_Template_Object* FindEntity(Asura_Guid uGuid)
    {
	    return s_xList.FindEntity(uGuid);
    }

	virtual void Destroy();
	virtual bool OwnsThisMessageBlock(unsigned short uMessageBlockID);
	virtual bool GetEventDescForMessageBlock(unsigned short usMessageBlockID,Asura_String& xOutputDesc);

	virtual bool HandlesThisMessage(int iMessageID);

	const char* GetInputNameFromHash(Asura_Hash_ID uNameHash) const;
	const char* GetOutputNameFromHash(Asura_Hash_ID uNameHash) const;

	static void AddOverlayControls_TemplateTrigger(struct Asura_StaticMessage* pxMessage,class Asura_Overlay* pxOverlay,class Asura_Vector_2& xOffset);

	static void EditTriggerInputMessage(Asura_StaticMessage* pxMessage);
	static void EditTriggerOutputMessage(Asura_StaticMessage* pxMessage);

	const char* GetTemplateName() const;

protected :
	static Asura_Hashed_List<Tools_Entity_Template_Object> s_xList;

	//prompt for an input to be chosen , returns index of selection , or -1
	int SelectInputIndex(const char* pszMessage);
	Asura_Hash_ID SelectInputHash(const char* pszMessage);

	//prompt for an output to be chosen , returns index of selection , or -1
	int SelectOutputIndex(const char* pszMessage);
	Asura_Hash_ID SelectOutputHash(const char* pszMessage);

	static void EditTriggerInputMessage(int iMessage);
	static void EditTriggerOutputMessage(int iMessage);
};


//////////////////////////////////////////////////////////////////////////////////////////////////
/*------------------------------------**
** Tools_Entity_TemplateMaster_Object **
**------------------------------------*/
class Tools_Entity_TemplateMaster_Object : public Tools_Entity_Template_Object
{
	typedef Tools_Entity_Template_Object PARENT;

	public :
		Tools_Entity_TemplateMaster_Object(Asura_Entity* pxEntity);
		~Tools_Entity_TemplateMaster_Object();

		//create master template controller for template file , if it doesn't exist already
		//(this won't create the tools object , since it will be called before tools objects
		//are created)
		static void Create();

		
		//virtual function overides
		virtual const char* GetTypeDescription(){return "Template Master";}

		virtual void AddOverlayControls(class Asura_Overlay* pxOverlay,class Asura_Vector_2& xOffset);
		virtual void UpdatePositionInAsuraData(bool bUpdateLinkedObjects);



		//master can't be destroyed since there must always be one in a template file
		virtual bool CanBeDestroyed(){return false;}
		virtual bool CanBeRenamed(){return false;}

		static void UpdateChildListInEntity();
		static void ExportSelectedAsTemplate();

		virtual u_short* AddCustomEvent();

	protected:

		static void UpdateChildListInEntity(class Asura_ServerEntity_Template* pxTemplateEntity,Tools_Entity_TemplateMaster_Object* pxTemplateObject,bool bSelectedOnly);

		static void UpdateChildList_Entity(Asura_ServerEntity_Template* pxTemplateEntity,Tools_Entity_TemplateMaster_Object* pxTemplateObject,bool bSelectedOnly);
		static void UpdateChildList_Phonon(Asura_ServerEntity_Template* pxTemplateEntity);
		static void UpdateChildList_Light(Asura_ServerEntity_Template* pxTemplateEntity);
		static void UpdateChildList_Corona(Asura_ServerEntity_Template* pxTemplateEntity);
		static void UpdateChildList_Attractor(Asura_ServerEntity_Template* pxTemplateEntity, bool bSelectedOnly);
		static void UpdateChildList_StreamingSound(Asura_ServerEntity_Template* pxTemplateEntity);
		

		static void CreateInput(int iThis){((Tools_Entity_TemplateMaster_Object*)iThis)->CreateInput();}
		bool CreateInput();

		static void DeleteInput(int iThis){((Tools_Entity_TemplateMaster_Object*)iThis)->DeleteInput();}
		void DeleteInput();

		static void CreateOutput(int iThis){((Tools_Entity_TemplateMaster_Object*)iThis)->CreateOutput();}
		void CreateOutput();
		
		static void DeleteOutput(int iThis){((Tools_Entity_TemplateMaster_Object*)iThis)->DeleteOutput();}
		void DeleteOutput();

		static void EditInput(int iIndex);

		static bool CanDeleteInput();
		static bool CanDeleteOutput();



		static List<Tools_Entity_TemplateMaster_Object*> s_xObjectList;
		List<Asura_Guid> m_xBadGuidList;
};

//////////////////////////////////////////////////////////////////////////////////////////////////
/*--------------------------------------**
** Tools_Entity_TemplateInstance_Object **
**--------------------------------------*/
class Tools_Entity_TemplateInstance_Object : public Tools_Entity_Template_Object
{
	typedef Tools_Entity_Template_Object PARENT;
	friend class Tools_Overlay_Template;

	public :
		Tools_Entity_TemplateInstance_Object(Asura_Entity* pxEntity);
		~Tools_Entity_TemplateInstance_Object();


		
		//virtual function overides
		virtual const char* GetTypeDescription(){return "Template Instance";}

		virtual void AddOverlayControls(class Asura_Overlay* pxOverlay,class Asura_Vector_2& xOffset);
		virtual void UpdatePositionInAsuraData(bool bUpdateLinkedObjects);

		virtual void Destroy();

		//virtual void Copy(const Tools_Object* pxObject);
		virtual void PrintInfo(float& x,float& y);

		virtual void Copy(const Tools_Object* pxObject);
		virtual bool CanBeCopied() const {return Type == TOT_Entity_TemplateInstance;}
		virtual Tools_Object* CreateObjectOfThisType() const;

		virtual void AddContextMenuItems(class Tools_ContextMenu& xMenu, const class Tools_ContextMenu_Context& xContext);

		virtual Asura_Vector_3 GetSnapPoint(const Asura_Vector_3& xPos) const;
		virtual void GetBoundingBoxForSnapToVertex(Asura_Bounding_Box& xOutputBB) const;

		virtual void OnSelection();
		virtual void OnDeselection();
		virtual void OnGroupDeselection();
		virtual void OnUpdateFromTemplate();

		virtual bool ShouldBeRendered();//does some culling to determine if Render() should be called
		virtual bool ShouldTestForLOS();
		virtual void Update();

		virtual void ReferencedObjectIsBeingDeleted(Tools_Object* pxObject);

		void FindChildren();

		//Adds an object to the list of children , and flags it so that it will be moved along
		//with the rest of the template.
		void AddChild(Tools_Object* pxObject);

		virtual void ListChildObjects(List<Tools_Object*>& xObjectList,bool bRecurse) const;

		static void UpdateAllTemplates();

		//static members for the instance creation overlay
		static void ToggleTemplateOverlay();
		static void CreateTemplateOverlay();
		static void CloseTemplateOverlay();
		static void UpdateTemplateOverlay();

		static bool TemplateOverlayIsOn();

		//Flags all entities/sounds/lights that belong to template instances.
		//This works regardless of whether the Tools_Objects currently exist
		static void FlagAllTemplateInstanceMembers();

		virtual void SetHiddenFlagIncludingChildren(int iHideFlag,bool bHide);

		static Asura_Dialog* CreateHideTemplateTriggersTickBox( Asura_Vector_2 &xOffset );

		virtual u_short* AddCustomEvent();


	protected :
		static void AddOutput(int iThis){((Tools_Entity_TemplateInstance_Object*)iThis)->AddOutput();}
		bool AddOutput();
		
		static void RemoveOutput(int iThis){((Tools_Entity_TemplateInstance_Object*)iThis)->RemoveOutput();}
		void RemoveOutput();

		static void EditOutput(int iIndex);

		static bool CanAddOutput();
		static bool CanRemoveOutput();

		static void Detemplatify();
		static bool CanDetemplatify();

		static void ClearupTemplateOverlay(bool bClosedByUser);

		#define OVERLAY_VOID_CALLBACK(__FnName)\
		static void __FnName(int iThis){((Tools_Entity_TemplateInstance_Object*)iThis)->__FnName();}\
		void __FnName();
		#define OVERLAY_BOOL_CALLBACK(__FnName)\
		static bool __FnName(int iThis){return ((Tools_Entity_TemplateInstance_Object*)iThis)->__FnName();}\
		bool __FnName();

		OVERLAY_VOID_CALLBACK(AddTriggeredInput)
		OVERLAY_VOID_CALLBACK(RemoveTriggeredInput)

		OVERLAY_BOOL_CALLBACK(CanAddTriggeredInput)
		OVERLAY_BOOL_CALLBACK(CanRemoveTriggeredInput)

		#undef OVERLAY_VOID_CALLBACK
		#undef OVERLAY_BOOL_CALLBACK
		

		void UnflagTemplateInstanceMembers();
	

		void UpdateFromTemplate();
		void DestroyChildren();

		void DestroyChildren_Entity();
		void DestroyChildren_Phonon();
		void DestroyChildren_Light();
		void DestroyChildren_Corona();
		void DestroyChildren_Attractor();
		void DestroyChildren_StreamingSound();

		void FindChildren_Entity();
		void FindChildren_Phonon();
		void FindChildren_Light();
		void FindChildren_Corona();
		void FindChildren_Attractor();
		void FindChildren_StreamingSound();

		void EmptyChildList();


		virtual void SetBeingDestroyed();

		void UpdateMesh();


		static void DeleteDisowned_Phonon();
		static void DeleteDisowned_Light();
		static void DeleteDisowned_Corona();
		static void DeleteDisowned_Attractor();
		static void DeleteDisowned_StreamingSound();

		static void FlagTemplateInstanceMembers_Entity(Asura_ServerEntity_Template* pxTemplate);
		static void FlagTemplateInstanceMembers_Phonon(Asura_ServerEntity_Template* pxTemplate);
		static void FlagTemplateInstanceMembers_Light(Asura_ServerEntity_Template* pxTemplate);
		static void FlagTemplateInstanceMembers_Corona(Asura_ServerEntity_Template* pxTemplate);
		static void FlagTemplateInstanceMembers_Attractor(Asura_ServerEntity_Template* pxTemplate);
		static void FlagTemplateInstanceMembers_StreamingSound(Asura_ServerEntity_Template* pxTemplate);

		void UnflagTemplateInstanceMembers_Entity();
		void UnflagTemplateInstanceMembers_Phonon();
		void UnflagTemplateInstanceMembers_Light();
		void UnflagTemplateInstanceMembers_Corona();
		void UnflagTemplateInstanceMembers_Attractor();
		void UnflagTemplateInstanceMembers_StreamingSound();


		virtual bool SetParameter(Asura_Hash_ID uParamID,const class Tools_Parameter* pxParam);
		virtual bool GetParameter(Asura_Hash_ID uParamID,class Tools_Parameter* pxParam) const;



		//create an instance of a template
		static void CreateInstance();
		static void CreateInstance_DoubleClick(int iJunk){CreateInstance();}
		static Tools_Object* CreateInstance(const char* pszTemplateName);
		static void ApplyTemplate();
		static void ApplyTemplate(const char* pszTemplateName);
		static bool CanUseTemplate(const char* pszTemplateName);

		static void EditTemplate();
		static void EditTemplate(const char* pszTemplateName);
		static void ReloadTemplates();
		static void ForceUpdate();


		static void BuildTemplateStrings(const char* pszDirectory);
		static void DeleteTemplateStrings();
		static int GetLinesForTemplateList();
		static void BuildDirectoryStrings();
		static void DeleteDirectoryStrings();
		static void UpdateTemplateStrings();
		static void BuildTemplateFilenameArray();
		static void DeleteTemplateFilenameArray();

		//right click selection
		static void ContextMenu_SelectTemplate(void* pObject, u_int uMode);

		// hide / show template triggers
		static void HideTriggersTickboxClicked();
		void HideTriggers( const bool bHide );
		void HideTriggersRecursive(const bool bHide, bool& bAnyPermanentlyVisible);
		void UpdateTriggerVisibility( void )					{ HideTriggers( !IsSelected() ); }


		void UpdateInputList();
		void DeleteInputList();

		void UpdateInputToTriggerList();
		void DeleteInputToTriggerList();
		
		void CopyTriggeredInputListToSelection();

		int m_iInputListSize;
		int m_iInputSelection;
		char** m_pszInputList;

		int m_iInputToTriggerListSize;
		int m_iInputToTriggerSelection;
		char** m_pszInputToTriggerList;
		Asura_List_Dialog* m_pxInputToTriggerListDialog;

		//Used when the template instance is being hidden as a result of hiding triggers , instead
		//of hiding it fully. This allows the template instance to appear in the find object overlay.
		bool m_bHiddenForLOSAndRender;

		bool m_bForceUpdate;


		List<Tools_Object*> m_xChildList;

		static List<Tools_Entity_TemplateInstance_Object*> s_xObjectList;

	public :
		static bool s_bHideTriggers;
		static bool s_bTemplateOverlayOpen;
		static Asura_Vector_2 s_xTemplateOverlayPosition;
		static Asura_Vector_2 s_xTemplateListSize;
		static bool s_bShowTemplatesInSubDirs;

};


#endif //_TOOLS_ENTITY_TEMPLATE_OBJECT_H_
