///////////////////////////////////////////////////////////////////////////////
//
// File: Tools_Entity_Container.h
//
// Created by Martin G.Harris (6/5/2008)
// 
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef __TOOLS_ENTITY_CONTAINER_H__
#define __TOOLS_ENTITY_CONTAINER_H__

#ifdef ASURA_USE_CONTAINER_SYSTEM

// Includes
#include "Entity/Container/Asura_ContainerState.h"
#include "Entity/Tools_Entity_Object.h"
#include "Misc/list_tem.hpp"

// Forward declarations
class Asura_ServerEntity_Container;
class Tools_Container;
class Asura_ClientContainerInstance;
class Tools_ContainerStateMachine;


////////////////////////////
// Tools_Entity_Container //
////////////////////////////
class Tools_Entity_Container : public Tools_Entity_Object
{
	typedef Tools_Entity_Object PARENT;

public:
	Tools_Entity_Container(Asura_Entity* pxEntity);
	virtual ~Tools_Entity_Container();

	virtual void Destroy();
	virtual void Update();
    virtual void Render();
    virtual void RenderPreFSFX();

	virtual bool ShouldHideWithinTemplate() const { return false; }

	void CreateInstance();
	void DestroyInstance();
	void RefreshMinorChange();

	const Asura_ClientContainerInstance* GetClientInstanceRoot() const { return m_pxInstance; }

	// Returns whether the object's associated game data is valid.
	// bAutomatic signifies whether the verification has been automatically or manually requested.
	virtual bool Verify( const bool bAutomatic );

	// Fix up errors caused by renaming states automatically.
	void FixUpErrors(bool bLogFixes = true);

	// Make sure server position/orientation is updated.
	virtual void UpdatePositionInAsuraData(bool bUpdateLinkedObjects);

	virtual const char* GetTypeDescription() { return "Container Entity"; }

	virtual void AddOverlayControls(Asura_Overlay* pxNewOverlay, Asura_Vector_2& xOffset);
	virtual void AddProjectOverlayControls(Asura_Overlay* pxOverlay, Asura_Vector_2& xOffset) {}
	void RefreshDialogue();
	void RefreshStateDialogue();
	void ResizeOverlay();
	
	virtual void PrintInfo(float& x,float& y);

	virtual void OnSelection();
	virtual void OnGroupDeselection();
	virtual void UpdateWhileSelected();

	// Tools LOS functions
	virtual bool ObjectIsInLOS(const Asura_Vector_3& xAlpha, const Asura_Vector_3& xBeta, float& fLowest);
	virtual bool GetPolygonAndPositionUnderCursor(int& iPolygonIndex, Asura_Vector_3& xPosition);
	virtual bool GetPolygonNormalAndPositionUnderCursor(Asura_Vector_3& xNormal, Asura_Vector_3& xPosition);

	virtual bool ShouldHideDuringCutscene() { return false; }

	// Get the nearest snap point in world space for this object, for use in snap to vertex	
	virtual Asura_Vector_3 GetSnapPoint(const Asura_Vector_3& xPos) const;

	// Bounding box to use when snapping this object to environment.
	virtual void GetBoundingBoxForSnapToVertex(Asura_Bounding_Box& xOutputBB) const;

    // Message/event handling.
    virtual bool HandlesThisMessage(int iMessageID);
	virtual bool HandlesThisEvent(int iEventID) const;

    // virtual overrides to add required files to tools export
    virtual void AddFilesToExportList(List<Asura_String>& xNameList) const;
	
	// Load any files needed for tools.
	void LoadRequiredFiles();

	virtual bool CanBeCopied() const { return Type == TOT_Entity_Container; }
	virtual bool UseStreamCopy() const { return true; }

	virtual const char* GetMyNamePrefix() { return Tools_Entity_Container::GetNamePrefix(); }

	// Remove any waypoints blocked by the container entity.
	void RemoveBlockedWaypoints() const;
	bool ShouldBlockWaypointGeneration() const { return m_bBlocksWaypointGeneration; }
	// Reduce waypoint radii.
	void ReduceWaypointRadius(class Tools_Nav_Vertex* pxNavVertex) const;

	// Recalculates waypoint link blocking.
	void RecalculateWaypointLinkBlocks();

	// Get functions
	Asura_ServerEntity_Container* GetServerEntity() const { return m_pxServerEntity; }
	Tools_Container* GetToolsContainer() const;
	Asura_Hash_ID GetContainerHash() const;
	const Asura_Container_InputState& GetInputState() const;

	// Create
	static void Create();
	static void Create(Asura_Entity* pxEntity);

	static bool IsContainerValid();

	static void Refresh();
	static void RefreshContainerModified(const Asura_Hash_ID uContainerChanged, bool bMinorChange);
	static void RefreshMinorChangeAllInstances();
	static void ChangedNumberOfInputs(const Asura_Hash_ID uContainerChanged, u_int uNumInputs);

	static void DestroyAllInstances();
	static void CreateAllInstances();

	static u_int GetOutlineColour() { return s_uOutlineColour; }
	static void SetOutlineColour(u_int uColour) { s_uOutlineColour = uColour; }

	// Get the name of the container state for the given entity.
	static const char* GetStateName(Asura_Guid uGuid, Asura_Hash_ID uStateHash);

	static void BeginCullWaypointLinks();
	static void EndCullWaypointLinks();

	static const char* GetNamePrefix() { return "Cont_"; }

protected:
	static void SelectContainer_Callback();
	static void EditContainer_Callback();
	static void SetNameFromContainer_Callback();

	void SelectContainer(const Asura_Hash_ID uNewContainerHash, const Asura_Container_InputState& xNewInputState);
	void CopyStateChangeToOthersSelected();
	void SetNameFromContainer();
	void SetToolsName(const char* szName);
	const char* GetToolsName() const;
	bool ShouldAutoRename() const;

protected:
	Asura_ServerEntity_Container* m_pxServerEntity;
	Asura_String m_xContainerName; // Dialogue string.

	Asura_ClientContainerInstance* m_pxInstance; // Instance for rendering in tools.

	mutable bool m_bBlocksWaypointGeneration; // Cached variable.
	bool m_bChangeInputState;

	static u_int s_uOutlineColour;

	// List members
public:
	static Tools_Entity_Container* FindEntity(Asura_Guid uGuid) { return s_xList.FindEntity(uGuid); }
    static const Asura_Hashed_List<Tools_Entity_Container>* GetList() { return &s_xList; }
private:
	static Asura_Hashed_List<Tools_Entity_Container> s_xList;
};


//////////////////////////////////////////////
// Tools_ContainerState_DropDownList_Dialog //
//////////////////////////////////////////////
// Drop down list dialogue of state hashes for a container.
// Set bAlwaysAddOnOff if you always want "on" and "off" states,
// even if the user has removed them from the state machine.
class Tools_ContainerState_DropDownList_Dialog : public Asura_Hash_DropDownList_Dialog
{
public:
	Tools_ContainerState_DropDownList_Dialog(const char* szName,
											 const Asura_Vector_2& xOffset,
											 const Asura_Hash_ID* puContainerHash,
											 Asura_Hash_ID* puStateHash,
											 bool* pbChanged,
											 bool bAlwaysAddOn,
											 bool bAlwaysAddOff,
											 bool bAlwaysAllowNone,
											 u_int uInputIndex,
											 const u_int* puInputIndex);

	~Tools_ContainerState_DropDownList_Dialog();

	virtual u_int GetNumberOfHashValues() const { return m_uNumStates; }
	virtual const char* GetNameByIndex(int iIndex) const;
	virtual int GetListValidID() const { return m_iValidCount; }

	void Refresh();

	virtual void PerFrameUpdate();

	// Don't add a *None* entry, unless there are no states at all, or it is specifically enabled.
	virtual bool GetAllowNoneEntry() const { return m_bAlwaysAllowNone || m_uNumStates == 0; }

	// The states may have changed refresh all of the dialogues.
	static void RefreshAllDialogues();

protected:
	void InitialiseFromContainer();

protected:
	const Asura_Hash_ID* m_puContainerHash;
	u_int m_uNumStates;
	const Tools_ContainerStateMachine* m_pxStateMachine;
	int m_iValidCount;

	bool m_bAlwaysAddOn;
	bool m_bAlwaysAddOff;
	bool m_bAlwaysAllowNone;
	int m_iOnIndex;
	int m_iOffIndex;

	u_int m_uInputIndex;			// Current input index
	const u_int* m_puInputIndex;	// Location of input index to monitor for changes.

	// List of drop down list dialogues.
	static Asura_List<Tools_ContainerState_DropDownList_Dialog> s_xList;
};


////////////////////////////////////////////////
// Tools_ContainerState_MessageEditing_Dialog //
////////////////////////////////////////////////
// Drop down dialogue for selecting container state in Tools message editing.
class Tools_ContainerState_MessageEditing_Dialog : public Tools_ContainerState_DropDownList_Dialog
{
public:
	// For ASURA_MSG_CONTAINER_CHANGE_STATE
	Tools_ContainerState_MessageEditing_Dialog (const char* szName,
												Asura_Vector_2& xOffset,
												Asura_Guid uEntity,
												Asura_Hash_ID* puStateHash);

	// For ASURA_MSG_CONTAINER_CHANGE_STATE_EXTENDED
	Tools_ContainerState_MessageEditing_Dialog (const char* szName,
												Asura_Vector_2& xOffset,
												Asura_Guid uEntity,
												Asura_Hash_ID* puStateHash,
												const u_int* puInputIndex);


protected:
	Asura_Hash_ID* GetContainerHashPointer(Asura_Guid uEntity);

protected:
	Asura_Hash_ID m_uContainerHash;
};

//////////////////////////////////////////
// Tools_Container_MultipleState_Dialog //
//////////////////////////////////////////
// Add dialogues for multiple container input states to the overlay.
class Tools_Container_MultipleState_Dialog : public Asura_Dialog
{
public:
	// szBaseName: base name e.g. "State"
	// xOverlay: overlay to which we add the dialogues.
	// xOffset: offset, which is updated with the new y-coord.
	// puContainerHash: pointer to container hash.
	// uNumInputStates: size of array of input state hashes.
	// puStateHash: pointer to an array of state hashes.
	// pbChanged: pointer to boolean that is set if the dialogue is changed.
	// bInstanceOverlay: true if the dialogue is on the instance overlay; false if it is the entity overlay.
	Tools_Container_MultipleState_Dialog(const char* szBaseName,
										 Asura_Overlay& xOverlay,
										 Asura_Vector_2& xOffset,
										 const Asura_Hash_ID* puContainerHash,
										 const u_int uNumInputStates,
										 Asura_Hash_ID* puStateHash,
										 bool* pbChanged,
										 bool bInstanceOverlay);


	Tools_Container_MultipleState_Dialog(Asura_Subwindow_Dialog* pxSubwindowDialog,
										 bool bEnabled,
										 Asura_Vector_2& xOffset,
										 const Asura_Hash_ID* puContainerHash,
										 const u_int uNumInputStates,
										 Asura_Hash_ID* puStateHash);

	virtual void PerFrameUpdate();

	// Maximum x coord of the dialogues created.
	float GetMaxCoordX() const { return m_fMaxCoordX; }

	// Have any of the children changed state?
	bool HasChanged() const { return *m_pbChanged; }

	void SetHelpTextForChildren(const char* szHelpText);

protected:
	float m_fMaxCoordX;	// Maximum x coord of all the sub-dialogues.
	bool* m_pbChanged;	// Pointer to changed boolean.

	bool m_bInstanceOverlay; // Is dialogue on the instance overlay?
	bool m_bChanged;		 // Internal changed boolean, used if there is no user-supplied one.

	Asura_List<Asura_Dialog> m_xChildDialogueList;
};

#endif //ifdef ASURA_USE_CONTAINER_SYSTEM

#endif //__TOOLS_ENTITY_CONTAINER_H__

