#if !defined	SPUUTIL_THREADGRP_H_
#define			SPUUTIL_THREADGRP_H__

#include <types.h>

#include <sys/spu_thread.h>


namespace spuutil
{
	class ThreadGrp
	{
	public:

		ThreadGrp( uint32_t spuCount );

		uint32_t	Release();

		bool		SetProgram( uint32_t spuNum, const char* name );
		bool		SetParam0( uint32_t spuNum, uint32_t param );
		bool		SetParam1( uint32_t spuNum, uint32_t param );
		bool		EnableInterrupts( uint32_t spuNum, bool enable );

		void		SetGroupPriority( uint32_t priority );


		bool		Deploy();
		bool		Start();
		bool 		Reset( uint32_t spuCount );

		bool		IsThreadDeployed( uint32_t index ) const;
		bool		IsFullyDeployed() const;

		spu_thread_t	GetThread( uint32_t index ) const;



	private:

		ThreadGrp();
		ThreadGrp( const ThreadGrp& );				//not defined
		ThreadGrp& operator= ( const ThreadGrp& );	//not defined
		
		~ThreadGrp();



		uint32_t			m_refCount;
		spu_thread_attr_t*	m_attrBlock;
		spu_thread_t*		m_threadBlock;
		uint32_t			m_spuCount;
		uint32_t			m_maxSPUCount;		//used for allocation tracking
		uint32_t			m_grpPriority;
		uint32_t			m_deployedThreads;	//Bits specifing currently deployed threads
		uint32_t			m_deployedMask;		//Bit mask of maximum deployed threads(only valid after ThreadGrp::Deploy)
		uint8_t*			m_privateStore;
	};




	///////////////////ThreadGrp inline implemetaion

	
	inline bool ThreadGrp::SetParam0( uint32_t spuNum, uint32_t param )
	{
		bool result = false;

		if(  (spuNum < m_spuCount) & (m_deployedThreads == 0) )
		{
			spu_thread_attr_t& attrs = m_attrBlock[spuNum];

			attrs.arg1 = param;

			result = true;
		}

		return result;
	}

	inline bool ThreadGrp::SetParam1( uint32_t spuNum, uint32_t param )
	{
		bool result = false;

		if(  (spuNum < m_spuCount) & (m_deployedThreads == 0)  )
		{
			spu_thread_attr_t& attrs = m_attrBlock[spuNum];

			attrs.arg2 = param;

			result = true;
		}

		return result;

	}

	inline bool ThreadGrp::EnableInterrupts( uint32_t spuNum, bool enable )
	{
		bool result = false;

		if(  (spuNum < m_spuCount) & (m_deployedThreads == 0)  )
		{
			spu_thread_attr_t& attrs = m_attrBlock[spuNum];

			attrs.async_intr_enable = (enable != false) ? 1 : 0;

			result = true;
		}

		return result;

	}

	inline void ThreadGrp::SetGroupPriority( uint32_t priority )
	{
		m_grpPriority = priority;
	}

	inline bool ThreadGrp::IsThreadDeployed( uint32_t index ) const
	{
		bool result = false;

		if(  index < m_spuCount  )
		{
			result = (((1 << index) & m_deployedThreads) != 0);
		}

		return result;
	}

	inline bool ThreadGrp::IsFullyDeployed() const
	{
		return (m_deployedThreads == m_deployedMask);
	}

	inline spu_thread_t ThreadGrp::GetThread( uint32_t index ) const
	{
		spu_thread_t result = 0xffffffff;

		if(  IsThreadDeployed( index )  )
		{
			result = m_threadBlock[index];
		}

		return result;
	}

}

#endif
