#include "soundset.h"
#include "engine.h"
#include "audioengine/soundfactory.h"

#include "string/stringhash.h"

namespace rage
{
	bool audSoundSet::Init(const char *name)
	{
		return Init(atStringHash(name));
	}

	bool audSoundSet::Init(const u32 nameHash)
	{
		m_NameHash = nameHash;
		const SoundSet *setData = g_AudioEngine.GetSoundManager().GetFactory().GetMetadataManager().GetObject<SoundSet>(nameHash);
		return Init(setData);
	}

	bool audSoundSet::Init(const SoundSet *metadata)
	{
		if(metadata)
		{
			m_Data = metadata;
#if __USEDEBUGAUDIO
			// validate sorting
			for(u32 i = 1; i < m_Data->numSounds; i++)
			{
				audAssertf(m_Data->Sounds[i-1].Name < m_Data->Sounds[i].Name, "SoundSet %s not correctly sorted (index %u is out of order)", g_AudioEngine.GetSoundManager().GetFactory().GetMetadataManager().GetObjectNameFromNameTableOffset(metadata->NameTableOffset), i);
			}				
#endif
			return true;
		}
		return false;
	}

	s32 audSoundSet::FindIndex(const u32 nameHash) const
	{
		if(m_Data && m_Data->numSounds)
		{			
			// binary search this list
			s32 start = 0;
			s32 middle;
			s32 end = static_cast<s32>(m_Data->numSounds) - 1;

			while(start <= end)
			{
				middle = (start + end) >> 1;
				if(nameHash > m_Data->Sounds[middle].Name)
				{
					start = middle + 1;
				}
				else if(nameHash < m_Data->Sounds[middle].Name)
				{
					end = middle - 1;
				}
				else
				{
					return middle;
				}
			}
		}
		return -1;
	}

	audMetadataRef audSoundSet::Find(const u32 nameHash) const
	{
#if __USEDEBUGAUDIO
		// Reinitialise to pick up RAVE edits that override our metadata.
		if(m_Data && g_AudioEngine.GetSoundManager().GetFactory().GetMetadataManager().IsRAVEConnected())
		{
			const char *thisName = g_AudioEngine.GetSoundManager().GetFactory().GetMetadataManager().GetNameFromNTO_Debug(m_Data->NameTableOffset);
			const_cast<audSoundSet*>(this)->Init(thisName);
		}
#endif
		if(m_Data && m_Data->numSounds)
		{			
			// binary search this list
			s32 start = 0;
			s32 middle;
			s32 end = static_cast<s32>(m_Data->numSounds) - 1;

			while(start <= end)
			{
				middle = (start + end) >> 1;
				if(nameHash > m_Data->Sounds[middle].Name)
				{
					start = middle + 1;
				}
				else if(nameHash < m_Data->Sounds[middle].Name)
				{
					end = middle - 1;
				}
				else
				{
					return m_Data->Sounds[middle].Sound;
				}
			}
		}
		return audMetadataRef();
	}

	audMetadataRef audSoundSet::Find(const char *name) const
	{
		return Find(atStringHash(name));
	}

	void audSoundSetFieldRef::ResolveMetadataRef()
	{
		if(IsSoundSetValid())
		{
			audSoundSet soundSet;

			if(soundSet.Init(GetSoundSetHash()))
			{			
				m_MetadataRef = soundSet.Find(GetFieldHash());
			}
		}
		else
		{
			m_MetadataRef = SOUNDFACTORY.GetMetadataManager().GetObjectMetadataRefFromHash(GetFieldHash());
		}
	}

} // namespace rage
