//Copyright © 2014 SDXFramework
//[License]GNU Affero General Public License, version 3
//[Contact]http://sourceforge.jp/projects/dxframework/
#pragma once
#include <Multimedia/Window.h>
#include <Multimedia/Input.h>
#include <Multimedia/Font.h>

namespace SDX
{
	/** ライブラリの初期化やシステム的な処理を行う関数群.*/
	/** \include System.h*/
	class System
	{
		friend class Window;

	private:
		MONO_STATE(System)

		/** シングルトンなインスタンスを取得.*/
		static bool& IsEnd()
		{
			static bool isEnd;
			return isEnd;
		}
	public:

		/** ライブラリの初期化.*/
		/** 初期化に失敗した場合、ソフトを強制的に終了する。\n*/
		/**	一部の設定関数は初期化前に呼び出す必要がある。*/
		static void Initialise(const char* ウィンドウ名, int 幅, int 高さ , bool フルスクリーンフラグ = false)
		{
			if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO) < 0)
			{
				exit(1);
				return;
			}

#ifndef TABLET
			SDL_JoystickEventState(SDL_ENABLE);

			if (SDL_NumJoysticks() > 0)
			{
				Input::pad.Open();
			}
#endif
			SubWindow::mainWindow.Create(ウィンドウ名,幅,高さ,フルスクリーンフラグ);

			Screen::SetRenderer(Renderer::mainRenderer);
			Window::SetWindow(SubWindow::mainWindow);

			//タブレットと画面サイズを合わせる
#ifdef TABLET
			int dpiX;
			int dpiY;
			SDL_GetWindowSize(SubWindow::mainWindow.handle, &dpiX, &dpiY);
			SubWindow::mainWindow.aspect = (double)dpiX / dpiY;
			SDL_RenderSetLogicalSize(Screen::GetHandle(), 幅, 高さ);
#endif

			//デフォルトフォントの設定
			setlocale(LC_CTYPE, "jpn");//文字コードを日本語に

			TTF_Init();
			Drawing::SetDefaultFont(SystemFont::Gothic, 16 , 2 );
			SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVERYTHING);


			//音声関連の初期化
			Mix_Init(MIX_INIT_MP3 | MIX_INIT_OGG);
			Mix_OpenAudio(44100, AUDIO_S16, 2, 1024);
			Mix_AllocateChannels(16);

			Mix_HookMusicFinished(Music::Finished);

			IsEnd() = false;


		}

		/** ライブラリの終了処理.*/
		/** この関数を使用した後は速やかにプログラムを終了させなければならない。*/
		static bool End()
		{
			TTF_Quit();
			Mix_CloseAudio();
			Mix_Quit();
			SDL_Quit();
			Window::activeWindow->Destroy();
			IsEnd() = true;
			return true;
		}

		/** 各種更新処理をまとめて行う.*/
		static bool Update(bool 描画更新フラグ = true)
		{
			if (描画更新フラグ)
			{
				Screen::Flip();
				Screen::Clear();
			}
			Input::Update();
			bool result = System::ProcessMessage();

			Music::Update();

			return result;
		}

		/** OSのメッセージ処理を行う.*/
		/** 目安として1/60秒に一回程度、この関数を呼び出す必要があり。*/
		/**	falseを返した場合、速やかにプログラムを終了させなければならない。*/
		/** @todo タブレット版専用の処理色々*/
		static bool ProcessMessage()
		{
			SDL_Event event;

			while (SDL_PollEvent(&event))
			{
				if (event.type == SDL_WINDOWEVENT)
				{
					switch (event.window.event)
					{
					case SDL_WINDOWEVENT_CLOSE:
#ifndef TABLET
						//ここでIDに応じてDestroy等する
						SubWindow::CheckWindowID(event.window.windowID);
						if (SubWindow::mainWindow.handle == nullptr)
						{
							IsEnd() = true;
							for (auto it : SubWindow::windowS)
							{
								it->Destroy();
							}
						}
#endif
						break;
					case SDL_WINDOWEVENT_MINIMIZED:
#ifdef TABLET
						//スリープに入る
						if (Music::Check())
						{
							//Music::active->Stop();
						}
#endif
						break;
					case SDL_WINDOWEVENT_RESTORED:
#ifdef TABLET
						//スリープ解除
						if (Music::Check())
						{
							//Music::active->Restart();
						}
#endif
						break;
					}

				}
				else if (event.type == SDL_QUIT)
				{
					IsEnd() = true;
				}
				else
				{
					Input::GetState(event);
				}
			}

			return !IsEnd();
		}

		/** 指定ミリ秒処理を停止する.*/
		static void Wait(int 停止ミリ秒)
		{
			SDL_Delay(停止ミリ秒);
		}

		/** なんらかのキーが入力されるまで処理を停止する.*/
		static void WaitKey()
		{
			while (!Keyboard::HoldAnyKey() && System::ProcessMessage()){}
		}
	};
}
