
#include "MW4Headers.hpp"

#include "ABLAudio.hpp"
#include <Adept\AudioChannel.hpp>
#include <Adept\AudioCommand.hpp>
#include <Adept\AudioRenderer.hpp>
#include "mwguimanager.hpp"
#include "hudcomm.hpp"

using namespace ABL;
using namespace Stuff;

AudioManager* AudioManager::m_Instance = 0;
int AudioManager::m_RefCount = 0;



AudioManager::AudioManager()
	: m_AudioCommands(0)
	, m_MusicCommands(0)
	, m_OldTimeout(0)
	, m_NewVolume(1)
	, m_TransitionBegin(0)
	, m_TransitionEnd(0)
{
}

AudioManager::~AudioManager()
{
	m_WhoIsTalking.clear ();
}

void AudioManager::SetVOPlayed(int hash)
{
	m_PlayedVoiceOvers.insert(hash);
}

void AudioManager::IncrementRefCount()
{
	if (m_Instance == 0)
	{
		m_Instance = new AudioManager;
	}

	++m_RefCount;
}

void AudioManager::DecrementRefCount()
{
	Verify(m_RefCount > 0);
	Verify(m_Instance != 0);

	--m_RefCount;

	if (m_RefCount == 0)
	{
		delete m_Instance;
		m_Instance = 0;
	}
}

void AudioManager::Load(MemoryStream *stream)
{
	Verify(1 == 0);
	// BUGBUG: TODO: NOT YET IMPLEMENTED
}

void AudioManager::Save(MemoryStream *stream)
{
	Verify(1 == 0);
	// BUGBUG: TODO: NOT YET IMPLEMENTED
}

void AudioManager::AddCommand(AudioCommand* command,int talker_id)
{
	m_AudioCommands.Add(command);
	m_WhoIsTalking[command] = talker_id;
}

void AudioManager::DeleteAllCommands()
{
	ChainIteratorOf<AudioCommand *> i(&m_AudioCommands);
	AudioCommand *command;
	while((command = i.ReadAndNext()) != NULL)
	{
		command->Stop();
	}
	m_WhoIsTalking.clear ();
}

void AudioManager::Update()
{
	if (m_AudioCommands.GetSize () != 0)
	{
		MWGUIManager *gui;
		gui = MWGUIManager::GetInstance ();
		if (gui)
		{
			HUDComm *comm;
			comm = Cast_Object (HUDComm *,gui->Component (MWGUIManager::HUD_COMM));
			Verify (comm);
			std::map<AudioCommand *,int>::iterator iter;
			iter = m_WhoIsTalking.find (m_AudioCommands.GetNth(0));
			int id;
			if (iter == m_WhoIsTalking.end ())
				id = -1;
			else
				id = iter->second;

			comm->PlayVideo (id,m_AudioCommands.GetNth(0));
		}
	}

	if ((m_MusicCommands.GetSize() == 0) ||
		(m_TransitionEnd == 0))
	{
		return;
	}

	if ((m_MusicCommands.GetSize() > 1) &&
		(gos_GetElapsedTime() > m_TransitionBegin + m_OldTimeout))
	{
		{
			ChainIteratorOf<AudioCommand*> i(&m_MusicCommands);
			AudioCommand* command = i.ReadAndNext();
			command->Stop();
		}

		{
			ChainIteratorOf<AudioCommand*> i(&m_MusicCommands);
			AudioCommand* command = i.ReadAndNext();

			command->Play();
		}
	}

	ChainIteratorOf<AudioCommand*> i(&m_MusicCommands);
	AudioCommand* command = i.ReadAndNext();

	if (command->GetPlayMode() == gosAudio_Stop)
	{
		command->Play();
	}

	if ((AudioRenderer::Instance != 0) &&
		(AudioRenderer::Instance->m_channelTypes.GetLength() > AudioRenderer::MusicType))
	{
		AudioRenderer::Instance->m_channelTypes[AudioRenderer::MusicType].SetVolume(GetFadeVolume());
	}

	if (gos_GetElapsedTime() > m_TransitionEnd)
	{
		m_TransitionBegin = 0;
		m_TransitionEnd = 0;
	}
}

void AudioManager::AddMusicCommand(AudioCommand* command, Scalar old_timeout, Scalar new_timein, Scalar new_volume)
{
	m_MusicCommands.Add(command);
	while (m_MusicCommands.GetSize() > 2)
	{
		ChainIteratorOf<AudioCommand*> i(&m_MusicCommands);
		i.ReadAndNext();
		i.Remove();
	}

	if (m_MusicCommands.GetSize() == 1)
	{
		old_timeout = 0;
		command->Play();
	}

	m_OldVolume = m_NewVolume;
	m_OldTimeout = old_timeout;
	m_NewVolume = new_volume;

	m_TransitionBegin = (Stuff::Scalar)gos_GetElapsedTime();
	m_TransitionEnd = m_TransitionBegin + m_OldTimeout + new_timein;
}

Scalar AudioManager::GetFadeVolume() const
{
	const Scalar elapsed_time((Scalar)gos_GetElapsedTime());

	if (elapsed_time > m_TransitionEnd)
	{
		return (m_NewVolume);
	}

	if (elapsed_time < m_TransitionBegin)
	{
		return (m_OldVolume);
	}

	if (elapsed_time < m_TransitionBegin + m_OldTimeout)
	{
		Scalar normalized = ((Scalar)gos_GetElapsedTime() - m_TransitionBegin) / (m_OldTimeout);

		return (m_OldVolume * (1 - normalized));
	}

	Scalar middle = m_TransitionBegin + m_OldTimeout;

	Scalar normalized = (elapsed_time - middle) / (m_TransitionEnd - middle);
	return (m_NewVolume * normalized);
}

void AudioManager::MapTalker(int talker, Adept::ObjectID object_id)
{
	talker_mapping::iterator found = m_TalkerMappings.find(talker);

	if (found != m_TalkerMappings.end())
	{
		(*found).second = object_id;
		return;
	}

	talker_pair p(talker,object_id);
	m_TalkerMappings.insert(p);
}

Adept::ObjectID AudioManager::TalkerObjectID(int talker)
{
	talker_mapping::iterator found = m_TalkerMappings.find(talker);

	if (found == m_TalkerMappings.end())
	{
		return (-2);
	}

	return ((*found).second);
}

bool AudioManager::IsVoiceOverPlaying()
{
	return (m_AudioCommands.GetSize() != 0);
}

bool AudioManager::IsMusicPlaying()
{
	return (m_MusicCommands.GetSize() != 0);
}
