#pragma once

#include "Mix/IEngine.h"

#include "Mix/Plugin/Common.h"
#include "Mix/Private/IO/NarrowManager.h"
#include "Mix/Private/IO/BroadManager.h"
#include "Mix/Private/Sound/Manager.h"
#include "Mix/Private/HID/Manager.h"
#include "Mix/Private/Graphics/DX9/Manager.h"
#include "Mix/Private/Graphics/DX11/Manager.h"
#include "Mix/Private/Dynamics/Manager.h"
#include "Mix/Private/Scene/Common/Manager.h"
#include "Mix/Private/Parallel/Manager.h"

namespace Mix{

	class UserFile;

	class Engine : public Mix::IEngine
	{
		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Engine
		////////////////////////////////////////////////////////////////////////////////////////////////////

	public:
		static Boolean CreateInstance( const Mix::ENGINE_CONFIG& config, Mix::UserFile* pSysReport );
		static void ReleaseInstance( void );
		static Engine* GetInstance( void );

	private:
		static Mix::Engine* g_pThis;

		// フレームレート

		LARGE_INTEGER m_Freq;
		Float64 m_InvFreqF64;
		LARGE_INTEGER m_PeriodCount;
		LARGE_INTEGER m_BeforeUpdateCount;
		LARGE_INTEGER m_ErrorSleepCount;
		Float64 m_SleepTimeCount;
		Int32 m_InsomniaFrameMax;
		Int32 m_InsomniaFrameCount;
		LARGE_INTEGER m_BeforeCount;
		Int32 m_FrameCount;
		Int32 m_BaseFPS;
		Float32 m_BaseET;
		Float32 m_FPS;
		Float32 m_ET;
		Float64 m_STPS;
		Int32 m_IFCPS;

		// ウィンドウ

		HWND m_hWnd;
		WNDPROC m_ExternalWndProc;
		LONG_PTR m_WndStyle;
		LONG_PTR m_WndExStyle;
		Mix::MessageProcPtr m_pMsgProcFunc;
		void* m_pMsgProcData;
		Mix::String m_Caption;
		Mix::Point m_TargetSize;
		Boolean m_bSizeable;
		Boolean m_bCloseEnabled;
		Boolean m_bWindowed;
		Boolean m_bActive;

		// 各種インターフェース

		Mix::IO::Manager*				m_pIOMgr;	
		Mix::HID::Manager*				m_pHIDMgr;
		Mix::Graphics::Common::Manager*	m_pGraphicsMgr;
		Mix::Sound::Manager*			m_pSoundMgr;
		Mix::Dynamics::Manager*			m_pDynamicsMgr;
		Mix::Parallel::Manager*			m_pParallelMgr;
		Mix::Scene::Common::Manager*	m_pSceneMgr;

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

		Boolean Initialize( const Mix::ENGINE_CONFIG& cfg, Mix::UserFile* pSysReport );

		Boolean MakeWindow( const Mix::Point& targetSize, const wchar_t* pCaption, HICON hIcon, HICON hSmallIcon, Boolean bAcceptDrop );
		Boolean LoadWindow( HWND hWnd, const Mix::Point& targetSize );
		void DisposeWindow( void );
		Boolean UpdateWindow( void );
		LRESULT MessageProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
		static LRESULT CALLBACK MessageProcEntry( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );

		void LoadPlugins( const wchar_t* pDirPath );

		void Dispose( void );
		void Dispose_Init( void );

	public:
		Boolean IsSizeableWindow( void ) const;
		void SetWindowStyle( Boolean bWindowed );

		Mix::IO::IManager* GetIOManagerPtr( void ) const;
		Mix::HID::IManager* GetHIDManagerPtr( void ) const;
		Mix::Graphics::IManager* GetGraphicsManagerPtr( void ) const;
		Mix::Sound::IManager* GetSoundManagerPtr( void ) const;
		Mix::Dynamics::IManager* GetDynamicsManagerPtr( void ) const;
		Mix::Parallel::IManager* GetParallelManagerPtr() const;
		Mix::Scene::IManager* GetSceneManagerPtr( void ) const;

		Mix::IO::Manager* GetInternalIOManagerPtr( void ) const;
		Mix::HID::Manager* GetInternalHIDManagerPtr( void ) const;
		Mix::Graphics::Common::Manager* GetInternalGraphicsManagerPtr( void ) const;
		Mix::Sound::Manager* GetInternalSoundManagerPtr( void ) const;
		Mix::Dynamics::Manager* GetInternalDynamicsManagerPtr( void ) const;
		Mix::Parallel::Manager* GetInternalParallelManagerPtr() const;
		Mix::Scene::Common::Manager* GetInternalSceneManagerPtr( void ) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::IEngine
		////////////////////////////////////////////////////////////////////////////////////////////////////

	public:
		virtual Int32 GetBaseFPS( void ) const;
		virtual Float32 GetBaseDT( void ) const;

		virtual void ResetFPS( void );
		virtual Float32 GetFPS( void ) const;

		virtual Float32 GetDT( void ) const;

		virtual Float32 GetSleepTimePerSec( void ) const;

		virtual Int32 GetInsomniaFrameCountPerSec( void ) const;
		virtual Int32 GetInsomniaFrameMax( void ) const;

		virtual HWND GetWindowHandle( void ) const;
		virtual Mix::Point GetClientSize( void ) const;

		virtual Boolean IsActive( void ) const;

		virtual const wchar_t* GetCaption( void ) const;
		virtual void SetCaption( const wchar_t* pCaption );

		virtual Boolean IsCloseEnabled( void ) const;
		virtual void SetCloseEnabled( Boolean bEnable );

		virtual void SetMessageProc( Mix::MessageProcPtr pMsgProc, void* pData );

		virtual Boolean Update( void );

		virtual void Shutdown( void );

	private:
		static const wchar_t* DEF_CAPTION;
		static UInt32 WINDOW_STYLE;
		static UInt32 FULLSCREEN_STYLE;
		static const wchar_t* PLUGIN_TYPE_TEXT_TABLE[Mix::Plugin::TYPE_MAX];

		typedef const Mix::Plugin::INFORMATION& ( __stdcall* PPluginGetInformation )( void );

	};

}
