#pragma once

#include "Mix/Parallel/IManager.h"

#ifdef _DEBUG
	#include "Mix/Timer.h"
	#include "Mix/CriticalSection.h"
#endif //_DEBUG

namespace Mix{ namespace Parallel{

	class Manager : public Mix::Parallel::IManager
	{
		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Parallel::Manager
		////////////////////////////////////////////////////////////////////////////////////////////////////

	private:
		enum WAKEUP_TYPE
		{
			SEMA_EXE_FUNC			= 0,
			EVENT_TERM				= 1,
			EVENT_MAP_WORK			= 2,
			WAKEUP_TYPE_MAX			= 3,

			SYNC_WORK_START			= WAKEUP_TYPE_MAX,
		};

		struct WORK
		{
			Mix::Parallel::FunctionPtr pFunc;
			void* pData;
#ifdef _DEBUG
			UInt32 debID;
#endif //_DEBUG

			WORK( Mix::Parallel::FunctionPtr _pFunc, void* _pData, UInt32 _debID )
			{
				pFunc = _pFunc;
				pData = _pData;
#ifdef _DEBUG
				debID = _debID;
#endif //_DEBUG
			}
		};

		typedef Mix::STL::Vector<Mix::Memory::SECTION_GENERAL, HANDLE> HandleList;
		typedef Mix::STL::Vector<Mix::Memory::SECTION_GENERAL, Mix::Parallel::WORK> WorkList;
		typedef Mix::STL::Map<Mix::Memory::SECTION_GENERAL, HANDLE, Manager::WorkList> WorkTree;

		struct THREAD_SHARE
		{
			// Common
			UInt32 threadCount;

			// Wakeup ( ExecuteFunction MapWork )
			HANDLE* compHandles;

			// ExecuteFunction
			Mix::Parallel::FunctionPtr pFunc;
			void* pData;
			Long32 callFuncCount;
#ifdef _DEBUG
			UInt32 debID;
#endif //_DEBUG
		};

		struct THREAD_DATA
		{
			// Common
			Manager::THREAD_SHARE* pShare;
			UInt32 threadIndex;

			// Wakeup
			Manager::HandleList wakeupHandles;

			// MapWork
			HANDLE validMapWorkHandle;
			HANDLE waitMapWorkHandle;
			Mix::STL::Vector<Mix::Memory::SECTION_GENERAL, Manager::WORK> works;

#ifdef _DEBUG
			Mix::Timer debTimer;

			Mix::STL::Vector<Mix::Memory::SECTION_GENERAL, Mix::StringW> debResidentFunctionNames;

			Mix::Parallel::DEBUG_THREAD_INFO debThreadInfos[2];
			Mix::Parallel::DEBUG_THREAD_INFO* pDebThreadInfoNext;

			Mix::STL::Vector<Mix::Memory::SECTION_GENERAL, Mix::Parallel::DEBUG_FUNC_INFO> debThreadFuncInfos[2];
			Mix::STL::Vector<Mix::Memory::SECTION_GENERAL, Mix::Parallel::DEBUG_FUNC_INFO>* pDebThreadFuncInfosNext;
#endif //_DEBUG
		};

		typedef Mix::STL::Vector<Mix::Memory::SECTION_GENERAL, Manager::THREAD_DATA> ThreadDataList;

	private:
		HANDLE m_ExeFuncHandle;
		HANDLE m_TermHandle;
		Manager::HandleList m_MapWorkHandles;
		Manager::HandleList m_CompHandles;
		Manager::HandleList m_WaitHandles;

		Manager::HandleList m_ThreadHandles;

		THREAD_SHARE m_ThreadShare;
		Manager::ThreadDataList m_ThreadDatum;

		Manager::WorkTree m_WorkTree;

#ifdef _DEBUG
		UInt32 m_DebCur;
		UInt32 m_DebNext;
#endif //_DEBUG

	public:
		static Manager* CreateInstance( void );

	private:
		Manager( void );
		virtual ~Manager( void );

		void RefreshWorks( void );

		static unsigned __stdcall ThreadMain( void* pArg );

	public:
		Boolean Initialize( void );
		void Dispose( void );

#ifdef _DEBUG
		void Debug_Update( void );
#endif //_DEBUG

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Parallel::IManager
		////////////////////////////////////////////////////////////////////////////////////////////////////

	public:
		virtual UInt32 GetThreadCount( void ) const;

		virtual HANDLE MapWorks( UInt32 numWork, Mix::Parallel::WORK* works );
		virtual Boolean UnmapWorks( HANDLE handle );

		virtual Boolean ExecuteFunction( UInt32 threadNum, FunctionPtr pFunc, void* pData, UInt32 debugID );

		virtual const Mix::Parallel::DEBUG_THREAD_INFO& Debug_GetThreadInfo( UInt32 threadIndex ) const;

	private:
		static const Mix::Parallel::DEBUG_THREAD_INFO DEBUG_INIT_THREAD_INFO;
	};

}}
