#include "empire.h"

FMOD_SOUND *musicfile_main = 0;
FMOD_SOUND *musicfile = 0;
vector<FMOD_SOUND *> soundeffects;
FMOD_SYSTEM *fmodmain = 0;
FMOD_CHANNELGROUP *sound_effects = 0;
FMOD_CHANNEL *music_channel = 0;

bool music_deliberately_stopped = false;

#define ERRCHECK(x) if(x!=FMOD_OK){cerr<<"Error setting up sound: "<<x<<"\n";return false;}

void shutdown_sound()
{
	if (global.sound)
	{
		empdebug("Unloading sound...");
		set_sfx_volume(0);
		set_music_volume(0);
		FMOD_Sound_Release(musicfile_main);
		//FMOD_System_Release(fmodmain);  //FREEZES EVERYTHING ON ALL UBUNTU KERNELS I'VE TRIED
		empdebug("Done");
	}
}

bool init_sound()
{
	FMOD_CAPS capability;
	FMOD_SPEAKERMODE speakermode;
	FMOD_RESULT result;
	unsigned int version;
	char name[256];
	
	if (FMOD_System_Create(&fmodmain) != FMOD_OK)
	{
		return false;
	}
	
	result = FMOD_System_GetVersion(fmodmain, &version);
	ERRCHECK(result);
	
	if (version < FMOD_VERSION)
	{
		fprintf(stderr, "Error!  You are using an old version of FMOD %08x.  This program requires %08x or higher\n", version, FMOD_VERSION);
		return false;
	}
	
	result = FMOD_System_GetDriverCaps(fmodmain, 0, &capability, 0, 0, &speakermode);
	ERRCHECK(result);

	result = FMOD_System_SetSpeakerMode(fmodmain, speakermode);  //set the user selected speaker mode
	ERRCHECK(result);

	if (capability & FMOD_CAPS_HARDWARE_EMULATED)  //no hardware acceleration, so we'll get crap latency
	{
		cerr << "No hardware acceleration: latency will be an issue\n";
		result = FMOD_System_SetDSPBufferSize(fmodmain, 1024, 10);    /* At 48khz, the latency between issuing an fmod command and hearing it will now be about 213ms. */
		ERRCHECK(result);
	}
	
	result = FMOD_System_GetDriverInfo(fmodmain, 0, name, 256, 0);
	ERRCHECK(result);
	
	if (strstr(name, "SigmaTel"))
	{  // Sigmatel sound devices crackle for some reason if the format is PCM 16bit.  PCM floating point output seems to solve it.
		result = FMOD_System_SetSoftwareFormat(fmodmain, 48000, FMOD_SOUND_FORMAT_PCMFLOAT, 0, 0, FMOD_DSP_RESAMPLER_LINEAR);
		ERRCHECK(result);
	}
	
	result = FMOD_System_Init(fmodmain, 32, FMOD_INIT_NORMAL, 0); 
	if (result != FMOD_OK)
	{
		if (result == FMOD_ERR_OUTPUT_CREATEBUFFER)
		{  // The speaker mode selected isn't supported by this soundcard, switch it back to stereo...
			result = FMOD_System_SetSpeakerMode(fmodmain, FMOD_SPEAKERMODE_STEREO);
			ERRCHECK(result);
			
			result = FMOD_System_Init(fmodmain, 32, FMOD_INIT_NORMAL, 0);
			ERRCHECK(result);
		}
		else return false;
	}
	
	FMOD_System_CreateChannelGroup(fmodmain, NULL, &sound_effects);
	set_sfx_volume(global.volume);
	set_music_volume(global.music_volume);
	
	// Load the main fsb file containing all our music
	// I would prefer to have the straight ogg files, but stockmusic.net's license says that their music can't be played/accessed outside of the game 
	if (FMOD_System_CreateSound(fmodmain, "data/music.fsb", FMOD_NONBLOCKING | FMOD_LOOP_NORMAL | FMOD_CREATESTREAM, 0, &musicfile_main) != FMOD_OK)
	{
		empdebug("Error opening music.fsb");
		return false;
	}
	
	return true;
}

void load_sounds()
{
	const int SOUNDNUM = 22;
	FMOD_SOUND *t;
	int i = 0;
	string tstr;
	const string path = "data/sfx/";
	const string files[SOUNDNUM] = {"01_antiair.wav", "02_autogun.wav", "03_bombs.wav",
									"04_chopper.wav", "05_click.wav", "06_engine.wav",
									"07_explosion.wav", "08_jet.wav", "09_march.wav",
									"10_mdtankfire.wav", "11_missile.wav", "12_seaboat.wav",
									"13_tank.wav", "14_tankfire.wav", "15_tiledown.wav",
									"16_torpedo.wav", "17_unitdown.wav", "18_explode2.wav",
									"19_win.wav", "20_defeat.wav", "21_teleport.wav",
									"22_shothit1.wav"};
	empdebug("  Loading sound effects...");
	while (i < SOUNDNUM)
	{
		soundeffects.push_back(t);
		tstr = path + files[i];
		FMOD_System_CreateSound(fmodmain, tstr.c_str(), FMOD_CREATESAMPLE, 0, &soundeffects[i]);
		i++;
	}
	empdebug("    ...done");
}

void play_sound(int soundtype)
{
	if (soundtype == -1) return;
	
  if (global.sound)
  {
		FMOD_CHANNEL *ch;
		FMOD_System_PlaySound(fmodmain, FMOD_CHANNEL_FREE, soundeffects[soundtype], false, &ch);
		FMOD_Channel_SetChannelGroup(ch, sound_effects);
  }
}

void stop_music()
{
	if (global.sound)
	{
		FMOD_Channel_Stop(music_channel);
		music_deliberately_stopped = true;
	}
}

void play_song(enum music_choice choice)
{
	static enum music_choice currentsong = VICTORY_THEME;
	music_deliberately_stopped = false;
	if ((musicfile_main != 0) && (global.sound) && (currentsong != choice))
	{
		currentsong = choice;
		FMOD_Channel_Stop(music_channel);
		
		FMOD_RESULT result = FMOD_Sound_GetSubSound(musicfile_main, choice, &musicfile);
		if (result != FMOD_OK)
		{
			stringstream s;
			s << "Error opening subsound of music.fsb: " << result;
			empdebug(s.str());
		}
		FMOD_System_PlaySound(fmodmain, FMOD_CHANNEL_FREE, musicfile, false, &music_channel);
		FMOD_Channel_SetVolume(music_channel, float(global.music_volume) / 100.0);
	}
}

void set_sfx_volume(int percent)
{
	if ((percent >= 0) && (percent <= 100))
	{
	  global.volume = percent;
	}
	else global.volume = 0;
	FMOD_ChannelGroup_SetVolume(sound_effects, float(global.volume) / 100.0);
}

void set_music_volume(int percent)
{
	if ((percent >= 0) && (percent <= 100))
	{
		global.music_volume = percent;
	}
	else global.music_volume = 0;
	FMOD_Channel_SetVolume(music_channel, float(global.music_volume) / 100.0);
}

void ensure_music_is_playing()
{
	FMOD_BOOL musicplaying = false;
	FMOD_Channel_IsPlaying(music_channel, &musicplaying);
	if (!musicplaying && !music_deliberately_stopped)
	{
		FMOD_System_PlaySound(fmodmain, FMOD_CHANNEL_FREE, musicfile, false, &music_channel);
		FMOD_Channel_SetVolume(music_channel, float(global.music_volume) / 100.0);
	}
}
