
///////////////////////////////////////////////////////////////////////////////
//
// File   : Asura_Streaming_ZoneHandler.h
// Author : Andy Tate
// Date   : 19-Apr-2006
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

// RJT NOTE: Required for GCC builds as the file list generation doesn't account for VC project exclusion from build
#ifdef ASURA_USE_STREAMING

#ifdef ASURA_USE_PRAGMA_ONCE
	#pragma once
#endif   // ifdef ASURA_USE_PRAGMA_ONCE

#ifndef __ASURA_STREAMING_ZONEHANDLER_H__
#define __ASURA_STREAMING_ZONEHANDLER_H__

////////////////////////////////////////////////////////////////////////////////
// Include files...
////////////////////////////////////////////////////////////////////////////////

#include "Core/Asura_HashTree.h"
#include "Streaming/Asura_Streaming_Zone.h"


////////////////////////////////////////////////////////////////////////////////
// Forward class declarations...
////////////////////////////////////////////////////////////////////////////////

class Asura_MemoryBank;
class Asura_Streaming_ZoneCache;


////////////////////////////////////////////////////////////////////////////////
// Class declaration...
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Class        : Asura_Streaming_ZoneHandler
// Author       : Andy Tate
// Date         : 19-Apr-2006
//
// Description  : Handles the allocation of individual zones given pre-defined
//				  numbers of high and low-detail zones.
////////////////////////////////////////////////////////////////////////////////

class Asura_Streaming_ZoneHandler
{
public:
	// Typedefs
	typedef void TraverseZoneCallback (Asura_Hash_ID uHash, Asura_Streaming_Zone* pxZone);

	// Public functions...
	Asura_Streaming_ZoneHandler  (const u_int uFirstUniqueIndex, const bool bEveryZoneCreatedIsUnique, const Asura_Hash_ID uParentHandlerHash, const u_int* puNumDataIndices, const u_int* puFirstDataIndex);
	~Asura_Streaming_ZoneHandler ();

	// Creation/destruction functions...	
	Asura_Streaming_Zone*			CreateZone						(const Asura_String& xFilename, const bool bAllowEnvironment)	{ return(CreateZone(xFilename.GetString(), bAllowEnvironment)); }
	Asura_Streaming_Zone*			CreateZone						(const char* szFilename, const bool bAllowEnvironment);

	bool							AllocateFreeZoneIndex			(Asura_Streaming_ZoneDataState& xZoneDataState);
	bool							DeallocateFreeZoneIndex			(Asura_Streaming_ZoneDataState& xZoneDataState);

	bool							CommenceEmptyCreation			(const Asura_Streaming_Zone::DataState eDataState, Asura_Streaming_Zone& xZone, const bool bBlocking);
	bool							CommenceLoad					(const Asura_Streaming_Zone::DataState eDataState, Asura_Streaming_Zone& xZone, const bool bBlocking);
	bool							CommenceDestruction				(const Asura_Streaming_Zone::DataState eDataState, Asura_Streaming_Zone& xZone, const bool bBlocking);

	bool							DestroyZone						(const Asura_Hash_ID uHash);
	void							DestroyAllZones					(void);

	bool							ReloadZone						(const Asura_Streaming_Zone::DataState eDataState, Asura_Streaming_Zone& xZone, const bool bBlocking);

	void							DestroySavedEntities			(void)								{ m_xZoneHashTree.Traverse(DestroySavedEntitiesZoneCallback); }

	// MGH 15/11/2006: Function to allow projects to pre-fill the unique index hash tree.
	// This allows them to ensure that zones always have the same unique index
	// (which is used to modify GUIDs). Hence allowing such things as messaging between zones.
	void AddToUniqueIndexHashTree(const Asura_Hash_ID uHash);

	// Update functions...
	void							Update							(const Asura_Vector_3* pxCurrentPosition, const bool bBlocking);

	void							UpdateEntitiesForAllZones		(void)								{ m_xZoneHashTree.Traverse(UpdateEntitiesZoneCallback); }

	// Module functions...		
	void							PreModuleUpdateUpdateForAllZones(void)								{ m_xZoneHashTree.Traverse(PreModuleUpdateUpdateZoneCallback); }

	// Render functions...
	void							PreRenderUpdateForAllZones		(void)								{ m_xZoneHashTree.Traverse(PreRenderUpdateZoneCallback); }

	void							RenderEntitiesForAllZones		(void)								{ m_xZoneHashTree.Traverse(RenderEntitiesZoneCallback); }
	void							RenderEnvironmentForAllZones	(void)								{ m_xZoneHashTree.Traverse(RenderEnvironmentZoneCallback); }

	// Client update functions...
	void ResetPeriodicClientUpdateListForAllZones()		{ m_xZoneHashTree.Traverse(ResetPeriodicClientUpdateListZoneCallback); }
	void FinishPeriodicClientUpdatesForAllZones()		{ m_xZoneHashTree.Traverse(FinishPeriodicClientUpdatesZoneCallback); }
	void DoSomePeriodicClientUpdatesForAllZones()		{ m_xZoneHashTree.Traverse(DoSomePeriodicClientUpdatesZoneCallback); }

	void ResetConstantClientUpdateListForAllZones()		{ m_xZoneHashTree.Traverse(ResetConstantClientUpdateListZoneCallback); }
	void DoConstantClientUpdatesForAllZones()			{ m_xZoneHashTree.Traverse(DoConstantClientUpdatesZoneCallback); }

	// Calculates offsets to and from the zone...
	 void							CalculateOffsets				(Asura_Streaming_Zone* pxZone);

	// Query functions...
	Asura_Streaming_Zone*			FindZone						(const Asura_Hash_ID uHashID) const	{ return(m_xZoneHashTree.GetDataByHash(uHashID)); }
	

#if defined(ASURA_RESOURCE_ALLOCATOR_USES_MEMORY_BANK)
	// Memory-bank typedef...
	typedef Asura_MemoryBank* MemoryBankAllocationFunction (const Asura_Streaming_Zone::DataState eDataState, const u_int uIndex, const char* szName);

	// Memory-bank functions...
	void							AllocateMemoryBanks				(const char** pszFormatText, MemoryBankAllocationFunction* pfnCreateMemoryBank);
	void							DeallocateMemoryBanks			(void);

	Asura_MemoryBank*				GetMemoryBankFromDataIndex		(const u_int uDataIndex) const;
#endif	// defined(ASURA_RESOURCE_ALLOCATOR_USES_MEMORY_BANK)

	// Accessor functions...
	Asura_Streaming_Zone**			MakeArrayOfZones				(int& iNumZones) const						{ iNumZones = m_xZoneHashTree.GetNumberOfNodes(); return(m_xZoneHashTree.MakeDataList()); }

	void							SetCurrentZone					(const Asura_Hash_ID uHash, const Asura_Streaming_Zone::DataState eDataState, const bool bAllowDeletion);
	void							SetCurrentZone					(const Asura_Hash_ID uHash)					{ SetCurrentZone(uHash, Asura_Streaming_Zone::HIGH_DETAIL_DATA, false); }
	void							ResetCurrentZone				(void)										{ m_pxCurrentZone = NULL; }
	Asura_Streaming_Zone*			GetCurrentZone					(void) const								{ return(m_pxCurrentZone); }
	u_int							GetNumZones						(void) const								{ return(m_xZoneHashTree.GetNumberOfNodes()); }

	bool							AreAllZonesEmpty				(void) const								{ return(m_bAllZonesEmpty); }
	bool							AreAllZonesFull					(void) const								{ return(m_bAllZonesFull); }
	
	int								GetUniqueIndexForZone			(const Asura_Streaming_Zone& xZone) const	{ return(GetUniqueIndexForZone(xZone.GetHashID())); }
	int								GetUniqueIndexForZone			(const Asura_Hash_ID uHash) const;

	u_int							GetResetGroupFromDataIndex		(const u_int uDataIndex);

	// Traverse all of the zones in the zonehandler, calling the user-defined callback.
	void TraverseZones(TraverseZoneCallback* pfnCallback) { m_xZoneHashTree.Traverse(pfnCallback); }

protected:
	// Protected variables...


	// Protected functions...


private:
	// Private typedefs...
	typedef Asura_HashTree IndexHashTree;
	typedef Asura_TemplateHashTree<Asura_Streaming_Zone> ZoneHashTree;

	// Private variables...
			Asura_Hash_ID					m_uParentHandlerHash;										// Hash-ID of the parent sub-system handlers to be used.

			ZoneHashTree					m_xZoneHashTree;											// Shortcut to find zone indices from hash-IDs.
			u_int							m_uFirstUniqueIndex;										// Offset to be applied to indices retrieved from the index hash-tree.
			IndexHashTree*					m_pxUniqueIndexHashTree;									// Tree containing the unique hash-indices for each zone.

			u_int							m_auFirstDataIndex[Asura_Streaming_Zone::MAX_DATA_STATES];	// The first data index to be used for these zones.
			u_int							m_auMaxDataIndices[Asura_Streaming_Zone::MAX_DATA_STATES];	// The number of data indices allowed for this zone.
			u_int							m_auZonesUsed[Asura_Streaming_Zone::MAX_DATA_STATES];		// Bits for the zone indices currently used.

			bool							m_bAllZonesFull;											// Flag to indicated whether all of the zones present are full.
			bool							m_bAllZonesEmpty;											// Flag to indicated whether all of the zones present are empty.

			Asura_Streaming_Zone*			m_pxCurrentZone;											// Pointer to the current zone.

#if defined(ASURA_RESOURCE_ALLOCATOR_USES_MEMORY_BANK)
	// Memory-banks to be used by the zones currently loaded...
			Asura_MemoryBank**				m_appxZoneMemoryBanks[Asura_Streaming_Zone::MAX_DATA_STATES];
#endif	// defined(ASURA_RESOURCE_ALLOCATOR_USES_MEMORY_BANK)

	// Handler used during callback functions...
	static	Asura_Streaming_ZoneHandler*	s_pxCallbackHandler;
	static	Asura_Streaming_Zone*			s_pxCurrentZoneBeforeCallback;
	static	const Asura_Vector_3*			s_pxCurrentPosition;
	static	bool							s_bCallbackBlocking;


	// Private functions...
	Asura_Streaming_ZoneHandler  (void);
	Asura_Streaming_ZoneHandler  (const Asura_Streaming_ZoneHandler& xOther);

			Asura_Streaming_ZoneHandler&	operator=						 (const Asura_Streaming_ZoneHandler& xOther);

	// Zone/mission accessor functions...
			u_int							GetFreeZoneIndex				 (const Asura_Streaming_Zone::DataState eDataState) const;
			Asura_Hash_ID					FindZoneHashUsingFilename		 (const char* szFilename) const;
			void							SetCurrentZoneDataState			 (Asura_Streaming_ZoneDataState& xDataState, const bool bAllowDeletion);

	// Destruction functions...
			void							DestroyData						 (Asura_Streaming_Zone& xZone);
	static	void							DestroyDataZoneCallback			 (Asura_Hash_ID uHash, Asura_Streaming_Zone* pxZone)	{ s_pxCallbackHandler->DestroyData(*pxZone); }

	static	void							DestroySavedEntitiesZoneCallback (Asura_Hash_ID uHash, Asura_Streaming_Zone* pxZone)	{ pxZone->DestroySavedEntities(); }

	// Internal update functions...
			void							Update							 (Asura_Streaming_Zone& xZoneToUpdate, const Asura_Streaming_Zone* pxCurrentZone, const bool bBlocking);
	static	void							UpdateZoneCallback				 (Asura_Hash_ID uHash, Asura_Streaming_Zone* pxZone)	{ s_pxCallbackHandler->Update(*pxZone, s_pxCurrentZoneBeforeCallback, s_bCallbackBlocking); }

	static	void							UpdateEntitiesZoneCallback		 (Asura_Hash_ID uHash, Asura_Streaming_Zone* pxZone)	{ pxZone->UpdateEntities(); }
	static	void							PreRenderUpdateZoneCallback		 (Asura_Hash_ID uHash, Asura_Streaming_Zone* pxZone)	{ pxZone->PreRenderUpdate(); }

	// Internal module functions...
	static  void							PreModuleUpdateUpdateZoneCallback(Asura_Hash_ID uHash, Asura_Streaming_Zone* pxZone)	{ pxZone->PreModuleUpdateUpdate(); }

	// Internal render functions...
	static	void							RenderEntitiesZoneCallback		 (Asura_Hash_ID uHash, Asura_Streaming_Zone* pxZone)	{ pxZone->RenderEntities(); }
	static	void							RenderEnvironmentZoneCallback	 (Asura_Hash_ID uHash, Asura_Streaming_Zone* pxZone)	{ pxZone->RenderEnvironment(); }


	// Internal client update functions...
	static void ResetPeriodicClientUpdateListZoneCallback	(Asura_Hash_ID uHash, Asura_Streaming_Zone* pxZone)	{ pxZone->ResetPeriodicClientUpdateList(); }
	static void FinishPeriodicClientUpdatesZoneCallback		(Asura_Hash_ID uHash, Asura_Streaming_Zone* pxZone)	{ pxZone->FinishPeriodicClientUpdates(); }
	static void DoSomePeriodicClientUpdatesZoneCallback		(Asura_Hash_ID uHash, Asura_Streaming_Zone* pxZone)	{ pxZone->DoSomePeriodicClientUpdates(); }

	static void ResetConstantClientUpdateListZoneCallback	(Asura_Hash_ID uHash, Asura_Streaming_Zone* pxZone)	{ pxZone->ResetConstantClientUpdateList(); }
	static void DoConstantClientUpdatesZoneCallback			(Asura_Hash_ID uHash, Asura_Streaming_Zone* pxZone)	{ pxZone->DoConstantClientUpdates(); }

};   // End of class 'Asura_Streaming_ZoneHandler'.


#endif   // ifndef __ASURA_STREAMING_ZONEHANDLER_H__

#endif	// ASURA_USE_STREAMING

/// End of file. ///
