#include "Sound.h"

#ifdef WIN32
#define NOMINMAX // pour novodex
#include <windows.h>
#else
#include "fmod/wincompat.h"
#endif
#include "fmod/fmod.h"
#include <assert.h>
#include <math.h>
#include "cstdio"

using namespace SoundSystem;

Sound::Sound(void)
{
	channel = INVALID_CHANNEL;
	min = 0;
	max = 100;
	volume = 255;
	position[0] = 0.0f;
	position[1] = 0.0f;
	position[2] = 0.0f;
	sound3D = true;
	name = "notNamed";
}

Sound::~Sound(void)
{
	if (isPlaying())
	{
		stop();
	}
}

void Sound::pause(bool pause)
{
	if (pause)
	{
		FSOUND_SetPaused(channel,TRUE);
	}
	else
	{
		FSOUND_SetPaused(channel,FALSE);
	}
}

bool Sound::isPaused()
{
	return (FSOUND_GetPaused(channel) == TRUE);

}

void Sound::stop()
{
	FSOUND_StopSound(channel);
	channel = INVALID_CHANNEL;
}

void Sound::setMinMax(float min,float max)
{
	assert(min >= 0.0f);
	assert(max > 0.0f);
	assert(min <= max);
	this->min = min;
	this->max = max;
}

void Sound::setPosition(float x,float y,float z)
{
	position[0] = x;
	position[1] = y;
	position[2] = z;
}

void Sound::setLoop(bool loop)
{
	// les son hardware necessitent d'etre mis en pause pour pouvoir etre changé de mode.
	bool pauseMode = isPaused();
	if (!pauseMode)
	{
		pause(true);
	}
	if (loop)
	{
		FSOUND_SetLoopMode(channel,FSOUND_LOOP_NORMAL);
	}
	else
	{
		FSOUND_SetLoopMode(channel,FSOUND_LOOP_OFF);
	}
	// on restaure le mode de pause...
	pause(pauseMode);
}

void Sound::setVolume(int volume)
{
	this->volume = volume;
}

int Sound::getVolume()
{
	return volume;
}

void Sound::update(float x,float y, float z)
{
	// rien a faire si le son n'est pas en train d'etre joué.
	if (!isPlaying()) return;
	int finalLevel;
	if (sound3D)
	{
		// on definit la position dans l'espace du son
		FSOUND_3D_SetAttributes(channel,position,NULL);
		// calcul de la distance son/recepteur
		float vecteur[3] = {x - position[0],y - position[1], z - position[2]};
		float distance = sqrt(vecteur[0] * vecteur[0] + vecteur[1] * vecteur[1] + vecteur[2] * vecteur[2]);
		if (distance < min)
		{
			finalLevel = volume;
		}
		else if (distance > max)
		{
			finalLevel = 0;
		}
		else
		{
			float newMax = max - min;
			distance -= min;
			finalLevel = (int)(volume * (1-(distance/newMax)));
		}
	}
	else
	{
		// on pose le son au même endroit que le listener
		float listenerPos[3] = {x,y,z};
		FSOUND_3D_SetAttributes(channel,listenerPos,NULL);
		finalLevel = volume;
	}
	FSOUND_SetVolume(channel,finalLevel);
}

bool Sound::isPlaying()
{
	return FSOUND_IsPlaying(channel)== TRUE;
}

float Sound::getPosX()
{
	return position[0];
}

float Sound::getPosY()
{
	return position[1];
}

float Sound::getPosZ()
{
	return position[2];
}

void Sound::setChannel(int channel)
{
	// Surtout ne pas prendre en compte FSOUND_ALL car sinon chaque changement effectué sur le son le serait
	// sur tout les sons !!!
	if (channel == FSOUND_ALL)
	{
		this->channel = INVALID_CHANNEL;
	}
	else
	{
		this->channel = channel;
	}
}

void Sound::set3DSound(bool is3D)
{
	sound3D = is3D;
}

bool Sound::is3DSound()
{
	return sound3D;
}

bool Sound::isLooping()
{
	int loopMode = FSOUND_GetLoopMode(channel);
	// on prend aussi en compte le loop_bidi même si en pratique elle ne seront a priori pas utilisée.
	return loopMode == FSOUND_LOOP_NORMAL || loopMode == FSOUND_LOOP_BIDI;
}

float Sound::getMin()
{
	return min;
}

float Sound::getMax()
{
	return max;
}

void Sound::setName(const string& name)
{
	this->name = name;
}

string Sound::getName()
{
	return name;
}

