///////////////////////////////////////////////////////////////////////////////
//
// File: Tools_Container_Collection.h
//
// Created by Martin G.Harris (3/7/2008)
// 
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef __TOOLS_CONTAINER_COLLECTION_H__
#define __TOOLS_CONTAINER_COLLECTION_H__

#ifdef ASURA_USE_CONTAINER_SYSTEM

// Includes
#include "Interface/Asura_Tree_Dialog.h"

#include "Entity/Container/Tools_Container.h"
#include "Entity/Container/Tools_ContainerState.h"


// Forward declarations
class Asura_Subwindow_Dialog;
class Tools_RemoveDamageOverride_Callback_Data;


////////////////////////////////
// Tools_Container_Collection //
////////////////////////////////
class Tools_Container_Collection : public Tools_Container
{
	typedef Tools_Container PARENT;

public:
	Tools_Container_Collection();
	virtual ~Tools_Container_Collection();

	virtual void AddOverlayControls(Asura_Overlay& xNewOverlay, Asura_Vector_2& xOffset);
	virtual void PerFrameOverlayUpdate();
	
	virtual	void ReadFromChunkStream(Asura_Chunk_Stream& xStream);
	virtual	void WriteToChunkStream(Asura_Chunk_Stream& xStream) const;

	virtual void PostLoadInitialise();
	virtual void PostCreateInitialise();
	virtual void CopyDataToAsura();
	virtual void Verify(bool bRecurse) const;
	virtual void FixUpErrors();
	
	// Add a child with the specified hash. Doesn't check that the child exists.
	// Nor does it check for circular references (calling code should prevent this).
	virtual void AddChild(Asura_Hash_ID uChildHash);

	// Add a child chosen from a modal overlay.
	virtual void AddChildFromList() { AddChild(); }

	// Can we add a new child?
	virtual bool CanAddChild() const { return true; }

	// Remove specified child. Return true if succeeded.
	virtual bool RemoveChild(Asura_Hash_ID uChildHash);

	// Return true if the remove succeeded.
	virtual bool ReplaceChild(Asura_Hash_ID uOldChildHash, Asura_Hash_ID uNewChildHash);

	// Set up the child iterator.
	virtual void FillChildIterator(Tools_Container_ChildIterator& xIterator) const;

	// Return hash of state selected for editing.
	static bool IsStateSelected();
	static Asura_Hash_ID GetStateSelectedForEditing() { return s_uStateHashForEdit; }
	static u_int GetStateIndexForEditing() { return s_uStateIndexForEdit; }
	static u_int GetNumInputsForEditing() { return s_pxThis ? s_pxThis->GetNumInputs() : 1; }

	// State machine
	virtual		  Tools_ContainerStateMachine* GetStateMachine()	   { return &m_xStateMachine; }
	virtual const Tools_ContainerStateMachine* GetStateMachine() const { return &m_xStateMachine; }
	virtual u_int GetNumInputs() const { return m_xStateMachine.GetNumInputs(); }

	// The state machine has been modified.
	virtual void SetModifiedStates()
	{
		m_bNeedToCopyStates = true;
		CopyDataToAsura();
		SetModified();
	}

	// Force the child hashes to be copied back to Asura.
	virtual void CopyChildHashDataToAsura()
	{
		m_bNeedToCopyHashes = true;
		CopyDataToAsura();
	}

	// Preview state was changed on the instance overlay.
	static void ChangedPreviewStateFromDialogue(Asura_Hash_ID uContainerToEdit,
												const Asura_Container_InputState& xInputState,
												const Asura_Container_InputState& xInputStateOld);

	// Preview state was changed on the collection overlay's state editing dialogue.
	static void ChangedPreviewStateFromStateDialogue(Asura_Hash_ID uContainerToEdit,
													 Asura_Hash_ID uStateHashToPreview,
													 u_int uInputIndex);

protected:
	void RefreshDialogue();
	void RefreshStateDialogues();
	void RefreshStateChildOverlay();
	void SetToDefaultState();

	Asura_Subwindow_Dialog* AddDamageOverrideOverlay(Asura_Overlay& xNewOverlay, Asura_Vector_2& xOffset);
	Asura_Subwindow_Dialog* AddStateChildOverlay(Asura_Overlay& xNewOverlay, Asura_Vector_2& xOffset);
	Asura_Subwindow_Dialog* AddInputOverlay(Asura_Overlay& xNewOverlay, Asura_Vector_2& xOffset);


	void AddChild();

	// Callbacks
	#define OVERLAY_VOID_CALLBACK(__FnName)\
	static void __FnName(int iThis) {((Tools_Container_Collection*)iThis)->__FnName();}\
	void __FnName();

	OVERLAY_VOID_CALLBACK(CreateState);
	OVERLAY_VOID_CALLBACK(RenameState);
	OVERLAY_VOID_CALLBACK(DeleteState);
	OVERLAY_VOID_CALLBACK(AddDamageOverride);
	OVERLAY_VOID_CALLBACK(AddInput);
	OVERLAY_VOID_CALLBACK(RemoveInput);
	
	#undef OVERLAY_VOID_CALLBACK

	static bool CanAddInput();
	static bool CanRemoveInput();
	void UpdateNumberOfInputs();

	void RemoveDamageOverride(Tools_RemoveDamageOverride_Callback_Data xData);

	// Check that one of the children has the specified marker (children of non-marker attachments are checked too).
	bool CheckMarkerExistsForAttachment(Asura_Hash_ID uMarkerHash, Asura_Hash_ID uAttachmentHash, Asura_String& xStateName, u_int uNumInputs) const;
	bool CheckMarkerExistsForState(Asura_Hash_ID uMarkerHash, const Tools_ContainerState* pxState) const;

	void VerifySharedPhysics() const;
	bool VerifyNumberOfSharedPhysicsObjects(const Tools_ContainerState* pxState) const;

	// Add entry to child iterator.
	static bool AddEntry_Callback(Asura_Hash_ID uHash, int const* piData, void* pUserData);

protected:
	Asura_TemplateHashTree<int> m_xChildren; // Hashes of children with stored multiplicity
	bool m_bNeedToCopyHashes;				 // Need to copy to Asura_Container?
	bool m_bNeedToCopyStates;
	bool m_bChangedInputMask;

	Tools_ContainerStateMachine m_xStateMachine; // Stores states for the collection.

	Asura_String m_xNumStatesDialogue;		 // String displayed on dialogue.
	Asura_String m_xNumInputsDialogue;		 // String displayed on dialogue.

	static Asura_Hash_ID s_uContainerHashForEdit;   // Hash of container that tree represents.	
	static Asura_Hash_ID s_uStateHashForEdit;		// Hash of state that is selected for state child editing.
	static u_int s_uStateIndexForEdit;				// Input slot number that we are editing.

	static Asura_Vector_2 s_xDimensionsDamage;
	static Asura_Vector_2 s_xDimensionsState;
	static Asura_Vector_2 s_xDimensionsInput;

	static Tools_Container_Collection* s_pxThis;


	// Friends
	friend class Tools_RemoveDamageOverride_Callback_Data;
};


//////////////////////////////////////////////
// Tools_RemoveDamageOverride_Callback_Data //
//////////////////////////////////////////////
class Tools_RemoveDamageOverride_Callback_Data
{
public:
	Tools_RemoveDamageOverride_Callback_Data(Tools_Container_Collection* pxThis, u_int uOverrideIndex)
		: m_pxThis(pxThis)
		, m_uOverrideIndex(uOverrideIndex)
	{
	}

	static void Callback(Tools_RemoveDamageOverride_Callback_Data xData)
	{
		if (xData.m_pxThis)
		{
			xData.m_pxThis->RemoveDamageOverride(xData);
		}
	}

	Tools_Container_Collection* m_pxThis;
	u_int m_uOverrideIndex;
};


#endif //#ifdef ASURA_USE_CONTAINER_SYSTEM

#endif //__TOOLS_CONTAINER_COLLECTION_H__
