#include "dllinterface.h"

#include "Sound.h"
#include "fmod_errors.h"

extern void wlog(char *str,...);

bool CheckFMODError(const FMOD_RESULT result)
{
	if (result != FMOD_OK)
	{
		wlog("FMOD error! (%d) %s", result, FMOD_ErrorString(result));
		return true;
	}
	return false;
}

SoundDevice::SoundDevice(void)
{
	// Create the main system object.
	CheckFMODError(FMOD::System_Create(&m_pSystem));	
}

SoundDevice::~SoundDevice(void)
{
	m_Sounds.Clear();

	if (m_pSystem)
		m_pSystem->release(); //also frees all ressources
	m_pSystem = NULL;
}

void SoundDevice::Init(unsigned voices, unsigned flags)
{
	//m_pSystem->setDriver(0);

	//m_pSystem->setSpeakerMode(FMOD_SPEAKERMODE_STEREO); 

	//m_pSystem->setHardwareChannels(0, 0, 0, 0);

	// Initialize FMOD.
	CheckFMODError(m_pSystem->init(voices, flags, 0));
}

SoundRessource* SoundDevice::CreateRessource(const XString& filename, const bool stream, const FMOD_MODE  mode)
{
	SoundRessource* res;

	//check if same ressource already has been created
	FOREACH(el, m_Sounds, SoundRessource)
	{
		res = el->GetInfo();
		if(res->GetMode () == mode && res->IsStream() == stream && res->GetFilename() == filename)
		{
			return res;
		}
	}
	res = new SoundRessource(this, filename, stream, mode);
	m_Sounds.AddHead(res, (unsigned)res);
	return res;
}

//called from destructor of SoundRessource
void SoundDevice::ReleaseRessource(SoundRessource* const ressource)
{
	ListElement<SoundRessource> *el = m_Sounds.GetElement((unsigned)ressource);
	if(el)
	{
		el->Unlink(); //info already deleted
		delete el;
	}
}

SoundRessource::SoundRessource(SoundDevice* const device, const XString& filename, const bool stream, const FMOD_MODE  mode)
{
	m_pDevice = device;
	m_strFilename = filename;
	m_bStream = stream;
	m_Mode = mode;
	m_pSound = NULL;

	if (m_bStream)
		CheckFMODError(m_pDevice->GetSystem()->createStream(m_strFilename.getbuffer(), m_Mode, 0, &m_pSound));
	else
		CheckFMODError(m_pDevice->GetSystem()->createSound(m_strFilename.getbuffer(), m_Mode, 0, &m_pSound));
}

SoundRessource::~SoundRessource(void)
{
	if (m_pSound)
		m_pSound->release();
	
	m_pDevice->ReleaseRessource(this);
}

unsigned SoundRessource::GetLength(void) const
{
	if (m_pSound)
	{
		unsigned length; 
		if (!CheckFMODError(m_pSound->getLength(&length, FMOD_TIMEUNIT_MS)))
			return length;
	}

	return NULL;
}

FMOD::Channel* SoundRessource::Play(const bool paused) const
{
	if (m_pSound)
	{
		FMOD::Channel *channel;
		if (!CheckFMODError(m_pDevice->GetSystem()->playSound(FMOD_CHANNEL_FREE, m_pSound, paused, &channel)))
			return channel;
	}
	return NULL;

}