//////////////////////////////////////////////////////////////////////////////
//
// Asura_PS2_Object_System.h
//
// Copyright (c) 2003 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////

// B E G I N   F I L E   W R A P P E R ///////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef ___ASURA_PS2_OBJECT_SYSTEM_H___
#define ___ASURA_PS2_OBJECT_SYSTEM_H___ 1

// I N C L U D E S ///////////////////////////////////////////////////////////

#include "Core/Asura_Hash.h"
#include "Core/Asura_HashTree.h"
#include "Rendering/Asura_PlatformRenderObject.h"

// D E F I N E S /////////////////////////////////////////////////////////////

#define ASURA_PS2_MAX_LODS_PER_OBJECT (4)

// F O R W A R D   D E C L A R A T I O N S ///////////////////////////////////

class Asura_Chunk_ResourceFile_PS2_StrippedObject;
class Asura_PS2_Object_System;
class Asura_Stream;

// C L A S S E S /////////////////////////////////////////////////////////////

class Asura_PS2_ObjectEntry
{
public:

	// C L A S S   M E T H O D S /////////////////////////////////////////
	Asura_PS2_ObjectEntry()
		: m_uHashID(ASURA_HASH_ID_UNSET)
		, m_uNumLODs(0)
#ifdef _DEBUG
		, m_szName(NULL)
		, m_bHasBeenScaled(false)
#endif
	{
		for (int i = 0; i < ASURA_PS2_MAX_LODS_PER_OBJECT; i++)
		{
			m_apxLODs[i] = NULL;
			m_afLODThresholdsSqd[i] = 0.0f;
		}
	}

	~Asura_PS2_ObjectEntry()
	{
#ifdef _DEBUG
		if (m_szName) delete[] m_szName;
#endif
		
		while (m_uNumLODs--)
		{
			delete m_apxLODs[m_uNumLODs];
		}
	}

	// C L A S S   D A T A ///////////////////////////////////////////////
	Asura_Hash_ID             m_uHashID;
	u_int                     m_uNumLODs;
	Asura_PS2_StrippedObject* m_apxLODs[ASURA_PS2_MAX_LODS_PER_OBJECT];
	float                     m_afLODThresholdsSqd[ASURA_PS2_MAX_LODS_PER_OBJECT];
#if _DEBUG
	char*                     m_szName;
	bool					  m_bHasBeenScaled;
#endif
};

class Asura_PS2_Object_Handler
{
	// F R I E N D S /////////////////////////////////////////////////////
	friend Asura_PS2_Object_System;

public:

	// C L A S S   M E T H O D S /////////////////////////////////////////
	Asura_PS2_Object_Handler() : m_fAppliedThresholdMultiplier(0.0f) {}

	void Reset( void );

	// Should be called at level load.
	void SetNumViewports( u_int uNumViewports );

	int GetMaterialIdx( Asura_Hash_ID uHashID );
	const Asura_PS2_StrippedObject* GetPS2ObjectToRender( Asura_Hash_ID uHashID, float fDistFromCamSqd );

private:

	// C L A S S   M E T H O D S /////////////////////////////////////////

	// Only for use by stripped Asura_PS2_Object_System, hence the friend
	// declaration above.
	Asura_PS2_StrippedObject* CreatePS2Object( const char* szName, const float fLODThreshold);
	Asura_PS2_ObjectEntry* FindEntryForHashID( Asura_Hash_ID uHashID, bool bAddIfNotFound );
	int CountObjects();

	// C L A S S   D A T A //////////////////////////////////////////////
	Asura_TemplateHashTree<Asura_PS2_ObjectEntry> m_xObjectStorage;
	float m_fAppliedThresholdMultiplier;
};

class Asura_PS2_Object_System
{
	// F R I E N D S /////////////////////////////////////////////////////
	friend Asura_Chunk_ResourceFile_PS2_StrippedObject;

public:

	// C L A S S   M E T H O D S /////////////////////////////////////////
    static void Initialise( void );
    static void Reset( void );
    static void Shutdown( void );

    // Should be called at level load.
    static void SetNumViewports( u_int uNumViewports );

	static int GetMaterialIdx( Asura_Hash_ID uHashID )	{ return GetCurrentHandler().GetMaterialIdx(uHashID); }
	static const Asura_PS2_StrippedObject* GetPS2ObjectToRender( Asura_Hash_ID uHashID, float fDistFromCamSqd ) { return GetCurrentHandler().GetPS2ObjectToRender(uHashID, fDistFromCamSqd); }

#if defined(ASURA_USE_MULTIPLE_HANDLERS) || defined(ASURA_USE_STREAMING)
	// Handler functions...
	static	void						ReparentHandler		(Asura_PS2_Object_Handler& xSourceHandler, const Asura_Hash_ID uNewParentHash);
	static	void						ReparentHandler		(const Asura_Hash_ID uSourceHash, const Asura_Hash_ID uNewParentHash);	

	static	Asura_PS2_Object_Handler*	CreateHandler		(const Asura_Hash_ID uHash, const Asura_Hash_ID uParentHandlerHash);
	static	bool						DestroyHandler		(const Asura_Hash_ID uHash);
	static	void						WriteHandlerReport	(u_int uHandler, Asura_Stream& xLog);

	static	void						CreateAndSetHandler	(const Asura_Hash_ID uHash, const Asura_Hash_ID uParentHandlerHash)	{ s_pxCurrentHandler = CreateHandler(uHash, uParentHandlerHash); }
	static	void						SetCurrentHandler	(Asura_PS2_Object_Handler* pxHandler)						{ s_pxCurrentHandler = pxHandler; }
	static	void						SetCurrentHandler	(const Asura_Hash_ID uHash)											{ s_pxCurrentHandler = s_xHandlerTree.GetDataByHash(uHash); }
	static	Asura_PS2_Object_Handler&	GetCurrentHandler	(void)																{ return(*s_pxCurrentHandler); }
	static	Asura_PS2_Object_Handler*	GetHandler			(const Asura_Hash_ID uHash)											{ return(s_xHandlerTree.GetDataByHash(uHash)); }
#else
	// Handler functions...
	static	Asura_PS2_Object_Handler&	GetCurrentHandler	(void)																{ return(s_xHandler); }
#endif

private:

	// C L A S S   M E T H O D S /////////////////////////////////////////

    // Only for use by stripped object chunk, hence the friend
    // declaration above.
	static Asura_PS2_StrippedObject* CreatePS2Object( const char* szName, const float fLODThreshold) { return GetCurrentHandler().CreatePS2Object(szName,fLODThreshold); }
	static int CountObjects();

	// C L A S S   D A T A //////////////////////////////////////////////

#if defined(ASURA_USE_MULTIPLE_HANDLERS) || defined(ASURA_USE_STREAMING)
	// Private variables...
	static	Asura_PS2_Object_Handler*						s_pxCurrentHandler;		// Currently active handler.
	static	Asura_TemplateHashTree<Asura_PS2_Object_Handler>	s_xHandlerTree;			// Tree of all of the handlers available.
#else
	// Private variables...
	static	Asura_PS2_Object_Handler							s_xHandler;				// Single static-instance of a zone.
#endif
};

// E N D   F I L E   W R A P P E R ///////////////////////////////////////////

#endif // #ifndef ___ASURA_PS2_OBJECT_SYSTEM_H___
