//	DwindlingSounder.h - The Sounder for my Dwindling Worlds game.
//  ----------------------------------------------------------------------------
//	This file is part of 'NiallsAVLib', base code for any kind of audiovisual
//	apps.
//	Copyright (C) 2012  Niall Moody
//	
//	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 3 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, see <http://www.gnu.org/licenses/>.
//	----------------------------------------------------------------------------

#ifndef DWINDLINGSOUNDER_H_
#define DWINDLINGSOUNDER_H_

#include "sound/StreamingSound.h"
#include "InterestingNoise.h"
#include "sound/Sounder.h"
#include "StuckBuffer.h"
#include "MiscHelper.h"
#include "TwoFloats.h"
#include "Thread.h"

#include <string>
#include <map>

///	A Sounder which plays StreamingSounds.
class DwindlingSounder : public Sounder,
						   public Thread
{
  public:
	///	Constructor.
	DwindlingSounder();
	///	Destructor.
	~DwindlingSounder();
	
	///	Called for every audio block.
	void getAudio(float *input, float *output, int numSamples);

	///	Called for each sound file resource by LoadingScreen.
	void loadSoundFileResource(SoundFileLoaderPtr soundFileLoader);

	///	Used to stream audio off the disk.
	bool run();

	///	Starts a StreamingSound playing at the desired position in the scene.
	/*!
		\param sound The name of the sound to play.
		\return The index of the sound which has been activated, so you can
		call deactivateSound() on it later.

		The sound will play until it reaches its end. Its level will be
		determined by the distance between it and the player.
	 */
	int activateSound(const std::wstring& sound);
	///	Stops the named sound playing w/a fade out.
	void deactivateSound(int index);
	///	Stops all sounds currently playing (w/a fade out).
	void killAllSounds();
	///	Triggers a StreamingSound to play as a one-shot.
	/*!
		\param The name of the sound to play.
		\param pan How the sound is panned (0->1; left->right).

		This will tell a StreamingSound to play, and stop when it reaches the
		end of its file.
	 */
	void triggerSound(const std::wstring& sound, float pan = 0.5f);
	///	Starts a sound playing in a loop.
	void playMusic(const std::wstring& sound);
	///	Stops the music playing.
	void stopMusic();

	///	Sets the amount the noise encroaches on the other sounds.
	void setNoiseLevel(float val);
	///	Stops the noise.
	void killNoise();

	///	Stops the stuck buffer effect.
	void killStuckBuffer();

	///	Called whenever the sounder hits a bar start.
	class Callback
	{
	  public:
		///	Destructor.
		virtual ~Callback() {};

		///	Called whenever the sounder hits a bar start.
		virtual void barStart() = 0;
	};
	///	Sets the bar start callback.
	void setCallback(Callback *c);
  private:
	///	Struct representing a pre-loaded buffer.
	struct PreLoadedBuffer
	{
		///	Pointer to the buffer data.
		float *buffer;
		///	The size of the buffer data.
		int size;
	};

	///	The number of available StreamingSounds.
	enum
	{
		NumSounds = 128
	};

	///	Map of sound file names and their associated SoundFileLoaders.
	/*!
		Used for longer files.
	 */
	std::map<std::wstring, SoundFileLoaderPtr> soundFiles;
	///	Map of sound file names and their pre-loaded buffers.
	/*!
		Used for short files, which can reasonably be read entirely into
		memory.
	 */
	std::map<std::wstring, PreLoadedBuffer> preLoadedBuffers;

	///	The available StreamingSounds.
	StreamingSound sounds[NumSounds];

	///	The interference noise.
	InterestingNoise noise;
	///	The stuck buffer effect.
	StuckBuffer stuckBuffer;

	///	Index of the music track.
	int musicIndex;

	///	Whether the background noise is currently on.
	bool noiseOn;
	///	Whether the stuck buffer effect is currently on.
	bool stuckBufferOn;

	///	Used to kill the thread.
	bool timeToStop;

	///	The bar start callback.
	Callback *barStartCallback;
	///	True if we're generating bar start callbacks now.
	bool generateCallbacks;
	///	Used to generate bar start callbacks.
	float barPos;
};

#endif
