#ifndef SOUND_H
#define SOUND_H

#include <string>
using namespace std;

namespace SoundSystem
{
#define INVALID_CHANNEL -1

	//forward declaration
	class SoundManager;

	/**
	 * classe definissant un son dynamique joué par un SoundManager.
	 *
	 * Un son dynamique est un son dont les differents parametres peuvent etre modifié par l'utilisateur durant
	 * la lecture de ce son.
	 * 
	 * les parametres du son sont : 
	 * - son volume sonore
	 * - sa position dans l'espace (utilisé uniquement pour les sons 3D)
	 * - gestion en 3D du son
	 * - mise en pause/redemarrage du son
	 * - son rayon minimum (distance avant laquelle le volume sonore des sons 3D n'est pas attenué)
	 * - son rayon maximum (distance apres laquelle le son n'est plus audible)
	 */
	class Sound
	{
		/**
		 * seule la classe SoundManager peut crée un Sound et le detruire. de même certaine methode sont
		 * mis en private afin d'assurer que seul le SoundManager puisse y acceder.
		 */
		friend class SoundManager;
	private:
	protected:
		/**
		 * le channel du son.
		 */
		int channel;
		/**
		 * la distance minimum a partir de laquelle le son arrete d'augmenter
		 */
		float min;
		/**
		 * la distance maximum à partire de laquelle le son est a 0.
		 */
		float max;
		/**
		 * le volume absolue du son (a son niveau le plus fort, ne dependant pas du rayon du son.)
		 */
		int volume;

		/**
		 * la position dans l'espace du son.
		 */
		float position[3];

		/**
		 * permet de savoir si le son est un son 3D ou pas.
		 */
		bool sound3D;

		/**
		 * le nom du soundDescriptor sur lequel est joué ce son.
		 */
		string name;

		/**
		 * constructeur par defaut. Mis en private pour que seul la friend classe SoundManager puisse crée des instances
		 */
		Sound(void);

		/**
		 * destructeur par defaut. Mis en private pour que seul la friend class SoundManager puisse detruire des
		 * instances
		 */
		~Sound(void);

		/**
		 * methode permettant de definir si le son boucle ou pas. A utiliser uniquement avec les SAMPLE. pour
		 * les STREAM, il faut appeler SoundDescriptor::free() puis rappeler load pour pouvoir changer le mode
		 * de boucle. Cette methode est mise en private pour que seul SoundManager puisse y acceder.
		 */
		void setLoop(bool loop);

		/**
		 * methode mettant a jour le son. comme pour les methode setLoop(), setChannel(), constructeur et destructeur,
		 * cette methode est mise en private pour n'autoriser que SoundManager a y acceder.
		 *
		 * @param x : position en x de listener
		 * @param y : position en y de listener
		 * @param z : position en z de listener
		 */ 
		void update(float x,float y, float z);

		/**
		 * methode permettant de definire le channel utilisé par le son. Mis en private pour que seul SoundManager
		 * puisse y acceder.
		 *
		 * @param channel : le channel a utilise pour le son.
		 */
		void setChannel(int channel);

		/**
		 * methode definissant le nom du SoundDescriptor sur lequel est joué le son. Mise en private pour que seul 
		 * le SoundManager puisse y acceder.
		 *
		 * @param name : le nom du descripteur sur lequel est joué le son.
		 */
		void setName(const string& name);

	public:
		/**
		 * definit les rayon minimum et maximum du son.
		 *
		 * - le rayon maximum du son est la valeur a partire de laquelle  le son commence a se reduire. par exemple un
		 * son avec un rayon minimum de 5 avec le listener a une disance du son inferieur a 5, le son ne sera pas 
		 * attenué. par contre si le listener ou le son bouge et que leur distance devient superieure a 5, le son
		 * sera attenué en fonction de la distance. Le rayon minimum sert donc a crée des sons qui sont au maximum de
		 * leur volume dans une certaine zone.
		 * - Le rayon maximum est la limite a partire de laquelle le volume du son est a 0. c'est le rayon effectif du
		 * son.
		 *
		 * @param min : le rayon minimum du son.
		 * @param max : le rayon maximum du son.
		 */
		void setMinMax(float min,float max);

		/**
		 * Methode retournant le rayon minimum du son.
		 *
		 * Pour plus d'informations sur le rayon minimum voir la methode setMinMax()
		 *
		 * @return float : le rayon minimum du son.
		 */
		float getMin();

		/**
		 * Methode retournant le rayon maximum du son.
		 *
		 * Pour plus d'informations sur le rayon maximum voir la methode setMinMax()
		 *
		 * @return float : le rayon maximum du son.
		 */
		float getMax();

		/**
		 * methode definissant la position spatial du son.
		 *
		 * @param x : position X du son
		 * @param y : position Y du son
		 * @param z : position Z du son
		 */
		void setPosition(float x,float y,float z);

		/**
		 * retourne la position X du son dans l'epace.
		 *
		 * @return float : la position X du son dans l'espace.
		 */
		float getPosX();

		/**
		 * retourne la position Y du son dans l'epace.
		 *
		 * @return float : la position Y du son dans l'espace.
		 */
		float getPosY();

		/**
		 * retourne la position Z du son dans l'epace.
		 *
		 * @return float : la position Z du son dans l'espace.
		 */
		float getPosZ();

		/**
		 * methode definissant le volume (relatif) du son.
		 *
		 * Ce volume est le volume maximum du son. il paut etre attenué en cas de son 3D.
		 *
		 * @param volume : le volume du son.
		 */
		void setVolume(int volume);

		/**
		 * methode retournant le volume relatif du son, c'est a dire a son maximum.
		 *
		 * @return int : le volume relatif du son.
		 */
		int getVolume();

		/**
		 * methode permettant de considerer le son comme etant un son 3D ou pas.
		 *
		 * @param is3D : mode de gestion du son : true = son 3D, false = son 2D.
		 */
		void set3DSound(bool is3D);

		/**
		 * methode permattant de savoir si un son est un son 3D ou pas.
		 *
		 * @return bool : true => son 3D, false => son 2D
		 */
		bool is3DSound();

		/**
		 * Methode permettant de savoir si le son est en train d'etre joué ou pas.
		 *
		 * Un son qui n'est pas en train d'etre joué peut etre libéré par l'appel a la methode SoundManager::freeSound()
		 * car il ne peut pas etre relancé directement par la classe Sound.
		 *
		 * @return bool : true si le son est en train d'etre joué, false sinon.
		 */
		bool isPlaying();

		/**
		 * stop le son. Apres avoir été stoppé, le son ne peut plus etre redemarré, il faut liberer la memoire qu'il
		 * utilise avec la methode SoundManager::freeSound(), puis refaire appel à la methode 
		 * SoundManager::playDynamicSound() pour recuperer une instance de Sound valide.
		 */
		void stop();

		/**
		 * met en pause/quite la pause du son
		 *
		 * @param pause : true => met le son en pause, false => redemarre le son
		 */
		void pause(bool pause);

		/**
		 * permet de savoir si le son est en pause ou pas.
		 *
		 * @return bool : true si le son est en pause, false sinon.
		 */
		bool isPaused();

		/**
		 * methode permettant de savoir si le son est une boucle ou pas.
		 *
		 * @return bool : true => le son est une boucle, false => le son n'est pas une boucle.
		 */ 
		bool isLooping();

		/**
		 * methode retournant le nom du descripteur sur lequel est joué le son.
		 *
		 * @return string : le nom du descripteur dans le SoundManager sur lequel a été lancé ce son.
		 */
		string getName();

	};
}//namespace SoundSystem

#endif
