/* vim: ts=4 sw=4 sts=4 :
 * =============================================================================
 *  SDL sample  for  D
 * =============================================================================
 */

import std.stdio;
import std.string;
import std.conv;

import sdl.c.sdl;
import sdl.c.sdl_mixer;


/**
 * MAIN.
 *
 * Params:
 *  args = 起動引数
 */
int main(char[][] args)
{
	string file;
	int    sampling;
	if (args.length > 1)
	{
		file     = cast(string) args[1];
		sampling = MIX_DEFAULT_FREQUENCY;
	}
	else
	{
		file     = "sample/resource/park.mp3";
		sampling = 16000;
	}

	if (args.length > 2)
	{
		sampling = std.conv.toInt(cast(string) args[2]);
	}

	SDLMixer sdlmix = new SDLMixer();
	sdlmix.playMedia(file, sampling);
	eventLoop();

	return 0;
}


/**
 * イベントループ.
 */
void eventLoop()
{
	int quit = 0;
	SDL_Event event;

	/* unicode 変換を有効にする. */
	SDL_EnableUNICODE(1);

	while (!quit)
	{
		while (SDL_PollEvent(&event))
		{
			switch (event.type)
			{
				/* SDL_QUIT イベント (ウィンドウが閉じられた) */
				case SDL_QUIT:
					quit = 1;
					break;

				default:
					break;
			}
		}
	}
}


/**
 * SDLMixer.
 * あくまでサンプル, 構成変でスミマセン.
 */
class SDLMixer
{
	/**
	 * 静的コンストラクタ.
	 *
	 * SDL_Init を実行し, SDL を初期化しています.
	 * SDL_Init 実行後, まだ初期化していないサブシステムを
	 * 初期化する場合は, SDL_InitSubSytem を使用する必要があります.
	 */
	static this()
	{
		int ret = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
		if (ret < 0)
		{	// SDL初期化失敗
			string errmsg = getErrorMessage();
			throw new SDLException("can't init sdl. " ~ errmsg);
		}
	}


	/**
	 * 静的デストラクタ.
	 * static this() が正常に完了している場合にのみ,
	 * プログラム終了時に呼び出されます.
	 * 本デストラクタにて, SDL終了処理を実行しています.
	 */
	static ~this()
	{
		SDL_Quit();
	}


	/**
	 * コンストラクタ.
	 * ビデオ表示初期化等を実施します.
	 */
	public
	this()
	{
		this.music = null;
		SDL_Surface* screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
		if (screen is null)
		{	// Video Mode 設定失敗
			string errmsg = getErrorMessage();
			throw new SDLException("can't set video mode. " ~ errmsg);
		}
	}


	/**
	 * デストラクタ.
	 * Music 開放など実施します.
	 */
	public
	~this()
	{
		if (this.music !is null)
		{
			Mix_HaltMusic();				// 演奏停止
			Mix_FreeMusic(this.music);		// 曲開放
			Mix_CloseAudio();				// Audio Close
		}
	}


	/**
	 * メディア再生.
	 *
	 * Params:
	 *  file     = ファイル
	 *  sampling = サンプリング
	 */
	public void playMedia(string file, int sampling = MIX_DEFAULT_FREQUENCY)
	{
		int ret = Mix_OpenAudio(sampling, MIX_DEFAULT_FORMAT, 2, 1024);
		if (ret < 0)
		{	// オーディオオープン失敗
			string errmsg = getErrorMessage();
			throw new SDLException("can't init audio. " ~ errmsg);
		}

		// ロード
		music = Mix_LoadMUS(cast(char*) std.string.toStringz(file));
		if (music is null)
		{	// ロード失敗
			string errmsg = getErrorMessage();
			throw new SDLException("can't load audio. " ~ errmsg);
		}

		// 連続再生(第2引数:再生回数. -1 の場合, 永久繰り返し)
		Mix_PlayMusic(music, -1);
	}


	/**
	 * 現在発生している SDL エラーメッセージを取得します.
	 *
	 * Returns:
	 *  エラーメッセージ
	 */
	public static
	string getErrorMessage()
	{
		const char* errmsg = SDL_GetError();
		return std.string.toString(errmsg);
	}

	private
	{
		Mix_Music* music;
	}

}


/**
 * SDL Exception.
 * エラー発生時に throw する.
 */
class SDLException : Exception
{
	/**
	 * 指定されたエラーメッセージを持つ, SDLException を構築します.
	 *
	 * Params:
	 *   msg  = エラーメッセージ
	 *   next = Exception
	 */
    this(string msg, Throwable next = null)
    {
        super(msg, next);
    }
}

