
///////////////////////////////////////////////////////////////////////////////
//
// File   : Asura_Streaming_Zone.h
// Author : Andy Tate
// Date   : 2-Feb-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_ZONE_H__
#define __ASURA_STREAMING_ZONE_H__

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

#include "Core/Asura_Hash.h"
#include "Core/Asura_Maths.h"
#include "Core/Asura_String.h"
#include "Streaming/Asura_Streaming_Connection.h"


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

class Asura_Chunk_Stream;
class Asura_Streaming_ZoneDataState;
class Asura_Streaming_ZoneEntities;
class Asura_Streaming_ZoneHandler;


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

////////////////////////////////////////////////////////////////////////////////
// Class        : Asura_Streaming_ZoneCache
// Author       : Andy Tate
// Date         : 15-Jun-2006
//
// Description  : Class used to cache positional data to allow zone queries to
//				  to be performed much quicker than re-checking all of the 
//				  modules in all of the zones.
////////////////////////////////////////////////////////////////////////////////

class Asura_Streaming_ZoneCache
{
public:
	// Public functions...
	Asura_Streaming_ZoneCache  (void) : m_uZoneHash(ASURA_HASH_ID_UNSET), m_iModuleIndex(-1)	{}
//	~Asura_Streaming_ZoneCache ();
	Asura_Streaming_ZoneCache  (const Asura_Streaming_ZoneCache& xOther)						{ m_uZoneHash = xOther.m_uZoneHash; m_iModuleIndex = xOther.m_iModuleIndex; }

	Asura_Streaming_ZoneCache&	operator=	(const Asura_Streaming_ZoneCache& xOther)			{ m_uZoneHash = xOther.m_uZoneHash; m_iModuleIndex = xOther.m_iModuleIndex; return(*this); }

	// Manipulation functions...
	void						Reset		(const Asura_Hash_ID uHash = ASURA_HASH_ID_UNSET)	{ m_uZoneHash = uHash; m_iModuleIndex = -1; }

	void						Update		(const Asura_Vector_3& xPosition);

	// Accessor functions...
	Asura_Hash_ID				GetZoneHash	(void) const	{ return(m_uZoneHash); }


protected:
	// Protected variables...


	// Protected functions...


private:
	// Private variables...
	Asura_Hash_ID	m_uZoneHash;
	int				m_iModuleIndex;


	// Private functions...

};   // End of class 'Asura_Streaming_ZoneCache'.



////////////////////////////////////////////////////////////////////////////////
// Class        : Asura_Streaming_Zone
// Author       : Andy Tate
// Date         : 2-Feb-2006
//
// Description  : An individual zone used by the streaming. Each zone holds it's
//				  own geometry, collision mesh and gameplay.
////////////////////////////////////////////////////////////////////////////////

class Asura_Streaming_Zone
{
public:
	// Public enumerated types...
	enum DataState
	{
		HIGH_DETAIL_DATA,
#if !defined(ASURA_TOOLS)
		LOW_DETAIL_DATA,
#endif	// !defined(ASURA_TOOLS)

		MAX_DATA_STATES,

		ENTITY_DATA	= HIGH_DETAIL_DATA,
	};

	// Public functions...
	Asura_Streaming_Zone  (void);
	~Asura_Streaming_Zone ();

	// Initialisation/destruction functions...
	void								Initialise					(Asura_Streaming_ZoneHandler& xHandler, const char* szFilename, const Asura_Hash_ID uHash, const bool bAllowEnvironment);

	Asura_Streaming_ZoneDataState*		CreateDataState				(const DataState eDataState);
	void								DestroyDataState			(const DataState eDataState, const bool bBlocking);

	void								DestroySavedEntities		(void);

	void								MarkLoadCompletion			(const DataState eDataState);

	// Connection functions...
	bool								HasConnection				(const Asura_Streaming_Zone& xToZone) const	{ return(FindConnectionIndex(xToZone) >= 0); }
	bool								HasConnection				(Asura_Hash_ID uZoneHash) const				{ return(FindConnectionIndex(uZoneHash) >= 0); }

	bool								AddConnection				(const char* szToZoneName,const char* szFilename);
	bool								DeleteConnection			(u_int uIndex);

	// Update functions...
	bool								UpdateState					(const DataState eDataState, const bool bBlocking);
	void								UpdateEntities				(const bool bSetSubsystemHandlers = true);

	// Module functions...		
	void								PreModuleUpdateUpdate		(void);

	// Render functions...
	void								PreRenderUpdate				(const bool bSetSubsystemHandlers = true);

	void								RenderEntities				(const bool bSetSubsystemHandlers = true);
	void								RenderEnvironment			(const bool bSetSubsystemHandlers = true);

	// Client update functions...
	void ResetPeriodicClientUpdateList();
	void FinishPeriodicClientUpdates(const bool bSetSubsystemHandlers = true);
	void DoSomePeriodicClientUpdates(const bool bSetSubsystemHandlers = true);

	void ResetConstantClientUpdateList();
	void DoConstantClientUpdates(const bool bSetSubsystemHandlers = true);

	// Query functions...
	bool								ContainsPosition			(const Asura_Vector_3& xPosition, const DataState eDataState = ENTITY_DATA, int* piHintModuleIndex = NULL, const bool bCheckScenery = false) const;

	// Accessor functions...
	bool								IsDataUnused				(void) const;
	bool								IsDataFull					(void) const;
	bool								IsDataEmpty					(void) const;

	bool								IsConnectedTo				(const Asura_Hash_ID uToHash) const;
	bool								IsConnectionAvailable		(const Asura_Hash_ID uToHash, const DataState eDataState, const Asura_Vector_3* pxPosition) const;

	bool								IsEnvironmentAllowed		(void) const								{ return(m_bAllowEnvironment); }

	Asura_Streaming_ZoneHandler&		GetHandler					(void) const								{ return(*m_pxHandler); }

	Asura_Streaming_ZoneDataState*		GetZoneDataState			(const DataState eDataState) const			{ return(m_apxDataState[eDataState]); }
	DataState							GetDataState				(const Asura_Streaming_ZoneDataState& xZoneDataState) const;

	const char*							GetFilename					(void) const								{ return(m_xFilename.GetString()); }
	Asura_Hash_ID						GetHashID					(void) const								{ return(m_uHashID); }

	const Asura_Vector_3&				GetPosition					(void) const								{ return(m_xPosition); }
	u_int								GetNumConnection			(void) const								{ return(m_uNumConnections); }
	const Asura_Streaming_Connection*	GetConnection				(const u_int uIndex) const					{ return(&m_pxConnections [uIndex]); }
	Asura_Streaming_Connection*			GetConnection				(const u_int uIndex)						{ return(&m_pxConnections [uIndex]); }

	static void							SetRenderLODs				(const bool bSet)							{ s_bRenderLODs = bSet; }
	static bool							GetRenderLODs				(void)										{ return(s_bRenderLODs); }

	void								SetPosition					(const Asura_Vector_3& xPosition)			{m_xPosition = xPosition;}

	Asura_Streaming_ZoneEntities*		GetEntities					(void)										{ return(m_pxEntities); }

	//Load & Save
	void								ReadFromChunkStream			(Asura_Chunk_Stream& xStream,int iChunkVersion);
#ifdef ASURA_TOOLS
	void								WriteToChunkStream			(Asura_Chunk_Stream& xStream) const;
#endif

	void SaveEntitiesToBuffer(class Asura_SaveBlock_Base& xSaveBlock);

	// Project specific functions...
	static Asura_Hash_ID				Project_CalculateHashForZoneName	(const Asura_String& xName);


	// Projects can clean up before destruction of the zone data by setting this callback.
	typedef void PreDestroyDataStateFunction(Asura_Hash_ID uZoneHash,
											 const DataState eDataState,
											 const bool bBlocking);

	static void SetPreDestroyDataStateFunction(PreDestroyDataStateFunction* pfnFunction)
	{
		s_pfnPreDestroyDataStateFunction = pfnFunction;
	}

protected:
	// Protected variables...


	// Protected functions...
	bool								Project_ApplyCameraOffset	(void);

private:
	// Private enumerated types...
	enum
	{
		UNINITIALISED_DATA_INDEX	= 0x7FFFFFFF,
	};

	// Private variables...
	Asura_Streaming_ZoneHandler*	m_pxHandler;						// The handler which contains this zone.

	bool							m_bAllowEnvironment;				// Flags to say whether there is environment/module data (or not).
	Asura_Hash_ID					m_uHashID;							// The hash ID for this zone.
	Asura_String					m_xFilename;						// The filename (minus extension) for this zone.

	Asura_Streaming_ZoneDataState*	m_apxDataState[MAX_DATA_STATES];	// The data-states for this zone.

	Asura_Vector_3					m_xPosition;						// The world-space position of this zone.

	u_int							m_uNumConnections;					// The number of other zones which are connected to this zone.
	Asura_Streaming_Connection*		m_pxConnections;					// Array of zones which are connected to this zone.

	Asura_Streaming_ZoneEntities*	m_pxEntities;						// The entities held by this zone.

	static bool						s_bRenderLODs;						// Debug flag to say whether to render LODs.

	static PreDestroyDataStateFunction* s_pfnPreDestroyDataStateFunction;	// Project callback


	// Private functions...

	Asura_Streaming_Zone  (const Asura_Streaming_Zone& xOther);

	Asura_Streaming_Zone&				operator=								(const Asura_Streaming_Zone& xOther);

	// Connection accessor functions...
	int									FindConnectionIndex						(const Asura_Streaming_Zone& xToZone) const {return FindConnectionIndex(xToZone.GetHashID());}
	int									FindConnectionIndex						(Asura_Hash_ID uZoneHash) const;

	// Project specific functions...
	// Called after the zone is fully loaded, to give projects a chance to initialise any entities etc.
	void								Project_PostLoadInitialise				(const DataState eDataState);
	void								Project_ModifyPathForNewlyCreatedZone	(const DataState eDataState, Asura_String& xPath);

};   // End of class 'Asura_Streaming_Zone'.


#endif   // ifndef __ASURA_STREAMING_ZONE_H__

#endif	// ASURA_USE_STREAMING

/// End of file. ///
