/* vim: ts=4 sw=4 sts=4 fenc=utf-8 :
 * =============================================================================
 *  SDL sample  for  C
 * =============================================================================
 */

#include <stdio.h>
#include <string.h>

#include <SDL.h>
#include <SDL_mixer.h>


/* エラーメッセージ出力. */
#define ERROR(x)     printError(x, __FILE__, __LINE__)
#define SDL_ERROR(x) printSDLError(x, __FILE__, __LINE__)

#define FILE_NAME_SIZE (1024)

/* プロトタイプ宣言 */
int  init(void);
void quit(void);
SDL_Surface* setVideoMode(void);
void mainLoop(Mix_Music* music);

/* プロトタイプ宣言 [メディア再生]. */
Mix_Music* playMedia(const char* file, int sampling);

/* プロトタイプ宣言 [エラー表示用]. */
void printError(const char* msg, const char* file, int line);
void printSDLError(const char* msg, const char* file, int line);


/**
 * MAIN.
 *
 * @param argc   起動引数の数
 * @param argv[] 起動引数
 *        [1] メディアファイル(省略時は, sample/resource/park.mp3 を使用する)
 *        [2] サンプリングレート
 * ※日本語ファイル名は対応していません...
 */
int main(int argc, char* argv[])
{
	int ret;
	SDL_Surface* screen;
	Mix_Music*   music;
	char        fname[FILE_NAME_SIZE];
	int         sampling;

	/* メディアファイルを設定 */
	if (argc > 1) {
		strncpy(fname, argv[1], FILE_NAME_SIZE);
		sampling = MIX_DEFAULT_FREQUENCY;
	} else {
		/* デフォルトのメディアファイル設定 */
		strncpy(fname, "sample/resource/park.mp3", FILE_NAME_SIZE);
		sampling = 16000;
	}

	if (argc > 2) {
		sampling = atoi(argv[2]);
	}

	/* SDL初期化. */
	ret = init();
	if (ret < 0) { return -1; }

	/* SDL終了処理を終了時に自動実行するよう登録. */
	atexit(quit);

	/* ビデオモード設定. */
	screen = setVideoMode();
	if (screen == NULL) { return -1; }

	/* メディア再生 */
	music = playMedia((const char*)fname, sampling);
	if (music == NULL) { return -1; }

	/* メインループ */
	mainLoop(music);

	return 0;
}


/**
 * SDL初期化.
 */
int init(void)
{
	/* 初期化 */
	int ret = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
	if (ret < 0)
	{	/* 初期化エラー */
		SDL_ERROR("can't init sdl.");
		return -1;
	}

	/*
	 * SDL_Init 後にまだ初期化していないサブシステムを
	 * 初期化する場合は, 下記関数を使用する.
	 * int SDL_InitSubSystem(Uint32 flags);
	 */

	return 0;
}


/**
 * SDL終了処理.
 */
void quit(void)
{
	SDL_Quit();
}


/**
 * ビデオ表示初期化.
 * @return SDL_Screen
 */
SDL_Surface* setVideoMode(void)
{
	SDL_Surface* screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
	if (screen == NULL)
	{	/* ビデオモード設定エラー */
		SDL_ERROR("can't set video mode.");
		return NULL;
	}
	return screen;
}


/**
 * メディア再生.
 *
 * @param file   ファイル
 * @param sampling サンプリングレート
 */
Mix_Music* playMedia(const char* file, int sampling)
{
	int ret;
	Mix_Music* music;

	/* 初期化 */
	ret = Mix_OpenAudio(sampling, MIX_DEFAULT_FORMAT ,2 ,1024);
	if (ret < 0)
	{
		SDL_ERROR("can't init audio");
		return NULL;
	}

	/* ロード */
	music = Mix_LoadMUS(file);
	if (!music) {
		SDL_ERROR("can't load audio");
		return NULL;
	}

	/* 連続再生(第2引数が再生回数. -1 の場合, 連続再生となる) */
	Mix_PlayMusic(music, -1);

	return music;
}


/**
 * イベントループ.
 * @param music メディア停止用
 */
void mainLoop(Mix_Music* music)
{
	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;
					Mix_HaltMusic();		/*< 演奏停止 */
					Mix_FreeMusic(music);	/*< 曲開放   */
					Mix_CloseAudio();		/*< Audio Close */
					break;

				default:
					break;
			}
		}
	}
}


/* =============================================================================
 *  以下, エラーメッセージ表示や, ユーティリティなど.
 *  本質ではないので・・・あんま見なくて良いかと.
 * =============================================================================
 */
/**
 * エラーメッセージ表示.
 *
 * @param msg  メッセージ
 * @param file ファイル名
 * @param line 行番号
 */
void printError(const char* msg, const char* file, int line)
{
	fprintf(stderr, "%s:%d %s\n", file, line, msg);
}


/**
 * SDLエラーメッセージを含む, エラーメッセージ表示.
 *
 * @param msg  メッセージ
 * @param file ファイル名
 * @param line 行番号
 */
void printSDLError(const char* msg, const char* file, int line)
{
	char* sdlerr = SDL_GetError();
	fprintf(stderr, "%s:%d %s [%s]\n", file, line, msg, sdlerr);
}

