/***************************************************************************
 *   Copyright (C) 2005 by Michal Turek - Woq                              *
 *   WOQ (zavinac) seznam.cz                                               *
 *                                                                         *
 *   Program demonstruje prehravani hudby a hlavne zabudovane efekty       *
 *   v SDL_mixeru. Cesta k hudbe se predava jako parametr programu.        *
 *   Ovladani: [+/-] - hlasitost                                           *
 *             [mezernik] - prohodi levy a pravy kanal                     *
 *             [sipka doleva/doprava] - vystup z leveho/praveho kanalu     *
 *             [sipka nahoru/dolu] - vzdalenost od zdroje zvuku            *
 *             [1,2,3,4,6,7,8,9] - pozice zdroje zvuku                     *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <stdio.h>
#include <SDL.h>
#include <SDL_mixer.h>// -lSDL_mixer


/*
 * Symbolicke konstanty
 */

#define SDL_SUBSYSTEMS SDL_INIT_VIDEO|SDL_INIT_TIMER

#define WIN_WIDTH 320
#define WIN_HEIGHT 240
#define WIN_BPP 0
#define WIN_TITLE "Hudba a efekty"


/*
 * Funkcni prototypy
 */

bool Init();						// Inicializace
void Destroy();						// Deinicializace
void Draw();						// Vykresleni
bool ProcessEvent();					// Osetruje udalosti
int  main(int argc, char *argv[]);			// Vstup do programu
bool ToggleFullscreen();				// Zmena okno/fullscreen


/*
 * Globalni promenne
 */

Uint8 g_win_flags = SDL_HWSURFACE|SDL_DOUBLEBUF;
SDL_Surface *g_screen;			// Surface okna

Mix_Music *g_music = NULL;		// Hudba
int g_volume = MIX_MAX_VOLUME;		// Hlasitost
int g_volume_left = 128;		// Hlasitost leveho kanalu
int g_sound_distance = 128;		// Vzdalenost od zdroje zvuku
bool g_reverse_stereo = false;		// Prohodi levy a pravy kanal


/*
 * Inicializacni funkce
 */

bool Init(char *mus_filename)
{
	// Inicializace SDL
	if(SDL_Init(SDL_SUBSYSTEMS) == -1)
	{
		fprintf(stderr, "Unable to initialize SDL: %s\n",
				SDL_GetError());
		return false;
	}

	// Nastaveni ikony
	SDL_Surface *icon = SDL_LoadBMP("./icon.bmp");
	if(icon != NULL)
	{
		SDL_WM_SetIcon(icon, NULL);
		SDL_FreeSurface(icon);
	}

	// Vytvori okno s definovanymi vlastnostmi
	g_screen = SDL_SetVideoMode(WIN_WIDTH, WIN_HEIGHT, WIN_BPP, g_win_flags);
	if(g_screen == NULL)
	{
		fprintf(stderr, "Unable to set %dx%d video: %s\n",
				WIN_WIDTH, WIN_HEIGHT, SDL_GetError());
		return false;
	}

	// Titulek okna
	SDL_WM_SetCaption(WIN_TITLE, NULL);

	// Audio
	if(Mix_OpenAudio(MIX_DEFAULT_FREQUENCY,
			MIX_DEFAULT_FORMAT, 2, 1024) == -1)
	{
		printf("Unable to open audio: %s\n", Mix_GetError());
		return false;
	}

	if((g_music = Mix_LoadMUS(mus_filename)) == NULL)
	{
		printf("Unable to load music: %s\n", Mix_GetError());
		return false;
	}

	Mix_VolumeMusic(g_volume);
	Mix_PlayMusic(g_music, -1);

	return true;
}


/*
 * Deinicializacni funkce
 */

void Destroy()
{
	// Vterinove odezneni
	if(Mix_PlayingMusic())
	{
		Mix_FadeOutMusic(1000);
		SDL_Delay(1000);
	}

	if(g_music)
	{
		Mix_FreeMusic(g_music);
		g_music = NULL;
	}

	Mix_CloseAudio();

	SDL_Quit();
}


/*
 * Vykresleni sceny
 */

void Draw()
{
	// Nic se nekresli
}


/*
 * Osetreni udalosti
 */

bool ProcessEvent()
{
	SDL_Event event;

	while(SDL_WaitEvent(&event))
	{
		switch(event.type)
		{
		case SDL_KEYDOWN:
			switch(event.key.keysym.sym)
			{
			// Prohodi levy a pravy kanal
			case SDLK_SPACE:
				g_reverse_stereo = !g_reverse_stereo;
				Mix_SetReverseStereo(MIX_CHANNEL_POST,
						g_reverse_stereo ? 1 : 0);
				break;

			// Zvysi hlasitost
			case SDLK_KP_PLUS:
				if(g_volume < MIX_MAX_VOLUME-11)
				{
					g_volume += 10;
					Mix_VolumeMusic(g_volume);
				}
				break;

			// Snizi hlasitost
			case SDLK_KP_MINUS:
				if(g_volume > 10)
				{
					g_volume -= 10;
					Mix_VolumeMusic(g_volume);
				}
				break;

			// Zvysi hlasitost leveho kanalu
			case SDLK_LEFT:
				if(g_volume_left < 245)
				{
					g_volume_left += 10;
					Mix_SetPanning(MIX_CHANNEL_POST,
							g_volume_left,
							255 - g_volume_left);
				}
				break;

			// Zvysi hlasitost praveho kanalu
			case SDLK_RIGHT:
				if(g_volume_left > 10)
				{
					g_volume_left -= 10;
					Mix_SetPanning(MIX_CHANNEL_POST,
							g_volume_left,
							255 - g_volume_left);
				}
				break;

			// Snizi vzdalenost od zdroje zvuku
			case SDLK_UP:
				if(g_sound_distance > 10)
				{
					g_sound_distance -= 10;
					Mix_SetDistance(MIX_CHANNEL_POST,
							g_sound_distance);
				}
				break;

			// Zvysi vzdalenost od zdroje zvuku
			case SDLK_DOWN:
				if(g_sound_distance < 245)
				{
					g_sound_distance += 10;
					Mix_SetDistance(MIX_CHANNEL_POST,
							g_sound_distance);
				}
				break;

			// Zvuk zepredu
			case SDLK_KP8:
				Mix_SetPosition(MIX_CHANNEL_POST,
						0, g_sound_distance);
				break;

			// Zvuk zepredu zprava
			case SDLK_KP9:
				Mix_SetPosition(MIX_CHANNEL_POST,
						45, g_sound_distance);
				break;

			// Zvuk zprava
			case SDLK_KP6:
				Mix_SetPosition(MIX_CHANNEL_POST,
						90, g_sound_distance);
				break;

			// Zvuk zezadu zprava
			case SDLK_KP3:
				Mix_SetPosition(MIX_CHANNEL_POST,
						135, g_sound_distance);
				break;

			// Zvuk zezadu
			case SDLK_KP2:
				Mix_SetPosition(MIX_CHANNEL_POST,
						180, g_sound_distance);
				break;

			// Zvuk zezadu zleva
			case SDLK_KP1:
				Mix_SetPosition(MIX_CHANNEL_POST,
						235, g_sound_distance);
				break;

			// Zvuk zleva
			case SDLK_KP4:
				Mix_SetPosition(MIX_CHANNEL_POST,
						270, g_sound_distance);
				break;

			// Zvuk zepredu zleva
			case SDLK_KP7:
				Mix_SetPosition(MIX_CHANNEL_POST,
						315, g_sound_distance);
				break;

			case SDLK_ESCAPE:
				return false;
				break;

			case SDLK_F1:
				if(!ToggleFullscreen())
					return false;
				break;

			default:
				break;
			}
			break;

		// Zmena velikosti okna
		case SDL_VIDEORESIZE:
			g_screen = SDL_SetVideoMode(event.resize.w,
					event.resize.h, WIN_BPP, g_win_flags);

			if(g_screen == NULL)
			{
				fprintf(stderr, "Unable to resize window: %s\n",
						SDL_GetError());
				return false;
			}
			break;

		// Pozadavek na ukonceni
		case SDL_QUIT:
			return false;
			break;

		default:
			break;
		}

		Draw();
	}

	return true;
}


/*
 * Vstup do programu
 */

int main(int argc, char *argv[])
{
	if(argc < 2)
	{
		fprintf(stderr, "Usage: %s music_file\n", argv[0]);
		return 1;
	}

	printf(WIN_TITLE);
	printf("\nPress ESC key to quit.\n");

	// Inicializace
	if(!Init(argv[1]))
	{
		Destroy();
		return 1;
	}

	// Hlavni smycka programu
	bool done = false;
	while(!done)
	{
		done = !ProcessEvent();
		Draw();
	}

	// Deinicializace a konec
	Destroy();
	return 0;
}


////////////////////////////////////////////////////////////////
//                     "Standardni funkce"                    //
////////////////////////////////////////////////////////////////

/*
 * Zmena modu okno/fullscreen (melo by fungovat vsude, nejen pod X11)
 */

bool ToggleFullscreen()
{
	// Negace priznakoveho bitu ve flagach
	if(g_win_flags & SDL_FULLSCREEN)// Z fullscreenu do okna
		g_win_flags &= ~SDL_FULLSCREEN;
	else// Z okna do fullscreenu
		g_win_flags |= SDL_FULLSCREEN;

	// Pokus o prepnuti
	if(SDL_WM_ToggleFullScreen(g_screen) == 0)
	{
		fprintf(stderr, "Unable to toggle fullscreen,"
				"trying to recreate window\n");

		SDL_FreeSurface(g_screen);
		g_screen = SDL_SetVideoMode(WIN_WIDTH, WIN_HEIGHT,
				WIN_BPP, g_win_flags);

		if(g_screen == NULL)
		{
			fprintf(stderr, "Unable to recreate window: %s\n",
					SDL_GetError());
			return false;// Ukonci program
		}

		Draw();// Prekresli scenu
	}

	return true;// OK
}