//===========================================================================//
// File:	audio.hh                                                        	  //
// Project: MUNGA           Brick: Audio manager									  //
// Contents: 																					  //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 01/30/95  ECH  Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc.                //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#include <munga.hpp>
#pragma hdrstop

#if !defined(AUDLVL_HPP)
#	include <audlvl.hpp>
#endif

#if !defined(OBJSTRM_HPP)
	#include <objstrm.hpp>
#endif

#if !defined(NAMELIST_HPP)
	#include <namelist.hpp>
#endif

#if !defined(APP_HPP)
	#include <app.hpp>
#endif

#if !defined(AUDREND_HPP)
	#include <audrend.hpp>
#endif

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioLevelOfDetail ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//
//#############################################################################
//#############################################################################
//
AudioLevelOfDetail::AudioLevelOfDetail(PlugStream *stream):
	Plug(stream)
{
	#if 0
	amplitudeRadiationProfile = 0.0f;
	filterRadiationProfile = 0.0f;
	#endif

	//
	// Read fields
	//
	MemoryStream_Read(stream, &voiceCount);
	MemoryStream_Read(stream, &audioRenderType);
	
	//
	// Read suspend seconds and calculate suspendDelay
	//
	Scalar 
		suspend_delay_seconds;
		
	MemoryStream_Read(stream, &suspend_delay_seconds);
	Check(application);
	Check(application->GetAudioRenderer());
	suspendDelay = suspend_delay_seconds * 
		application->GetAudioRenderer()->GetCalibrationRate() + 0.5f;
}

//
//#############################################################################
//#############################################################################
//
void
	AudioLevelOfDetail::BuildFromPage(
		PlugStream *stream,
		NameList *name_list,
		ClassID class_ID,
		ObjectID object_ID
	)
{
	Plug::BuildFromPage(stream, name_list, class_ID, object_ID);

	//
	// Store fields
	//
	MEM_STRM_WRITE_ENTRY(*stream, name_list, AudioVoiceCount, voice_count);
	MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, render_type);
	
	//
	// Store suspend delay
	//
	CString suspend_delay_string("suspend_delay");
	Scalar suspend_delay_seconds = 0.33f; // HACK - should come from somewhere else

	if (name_list->FindData(suspend_delay_string) != NULL)
	{
		Check_Pointer(name_list->FindData(suspend_delay_string));
		Convert_From_Ascii(
			(const char *)name_list->FindData(suspend_delay_string), 
			&suspend_delay_seconds
		);
	}
	MemoryStream_Write(stream, &suspend_delay_seconds);
}

//
//#############################################################################
//#############################################################################
//
AudioLevelOfDetail::~AudioLevelOfDetail()
{
}

//
//#############################################################################
//#############################################################################
//
Logical
	AudioLevelOfDetail::TestInstance() const
{
	Plug::TestInstance();
	return True;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioResource ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//
//#############################################################################
//#############################################################################
//
AudioResource::AudioResource(PlugStream *stream):
	Node(stream),
	audioLevelOfDetailSocket(NULL, True)
{
	//
	// Read the table
	//
	CollectionSize i, number_of_entries;

	MemoryStream_Read(stream, &number_of_entries);
	for (i = 0; i < number_of_entries; i++)
	{
		Scalar distance;
		AudioLevelOfDetail *audio_level_of_detail;

		MemoryStream_Read(stream, &distance);
		PlugStream_ReadObjectIDAndFindPlug(stream, &audio_level_of_detail);
		Check(audio_level_of_detail);
		audioLevelOfDetailSocket.AddValue(audio_level_of_detail, distance);
	}

	//
	// Verify that there is at least one entry and the first one is at 0.0f
	//
	#if DEBUG_LEVEL>0
	{
		TableIteratorOf<AudioLevelOfDetail*, Scalar> iterator(&audioLevelOfDetailSocket);
		Check(&iterator);
		Verify(iterator.GetSize() > 0);
		Verify(iterator.GetCurrent() != NULL);
		Verify(iterator.GetValue() == 0.0f);
	}
	#endif

	//
	// Select the first entry
	//
	TableIteratorOf<AudioLevelOfDetail*, Scalar> iterator(&audioLevelOfDetailSocket);

	audioLevelOfDetail = iterator.GetCurrent();
	Check(audioLevelOfDetail);
}

//
//#############################################################################
//#############################################################################
//
void
	AudioResource::BuildFromPage(
		PlugStream *stream,
		NameList *name_list,
		ClassID class_ID,
		ObjectID object_ID
	)
{
	Node::BuildFromPage(stream, name_list, class_ID, object_ID);

	//
	// Count number of entries
	//
	int number_of_entries = 0;
	NameList::Entry *entry;

	Check(name_list);
	entry = name_list->GetFirstEntry();
	while (entry != NULL)
	{
		Check(entry);
		if (entry->IsName("audio_level_of_detail"))
			number_of_entries++;
		entry = entry->GetNextEntry();
	}

	//
	// Store entries
	//
	MemoryStream_Write(stream, &number_of_entries);

	Check(name_list);
	entry = name_list->GetFirstEntry();
	while (entry != NULL)
	{
		Check(entry);
		if (entry->IsName("audio_level_of_detail"))
		{
			CString object_string;
			Scalar distance;
			ObjectID object_ID;

			Check_Pointer(entry->GetChar());
			object_string = entry->GetChar();

			Check_Pointer(object_string.GetNthToken(0));
			Convert_From_Ascii(object_string.GetNthToken(0), &distance);
			MemoryStream_Write(stream, &distance);

			Check(stream);
			Check_Pointer(object_string.GetNthToken(1));
			object_ID = stream->FindObjectID(object_string.GetNthToken(1));
			Verify(object_ID != NullObjectID);
			MemoryStream_Write(stream, &object_ID);
		}
		entry = entry->GetNextEntry();
	}
}

//
//#############################################################################
//#############################################################################
//
AudioResource::~AudioResource()
{
}

//
//#############################################################################
//#############################################################################
//
Logical
	AudioResource::TestInstance() const
{
	Node::TestInstance();
	Check(&audioLevelOfDetailSocket);
	return True;
}

//
//#############################################################################
//#############################################################################
//
void
	AudioResource::SetDistance(Scalar distance)
{
	Check(this);
	Verify(distance >= 0.0f);

	//
	// Goto the last entry
	//
	TableIteratorOf<AudioLevelOfDetail*, Scalar>
		iterator(&audioLevelOfDetailSocket);

	Check(&iterator);
	iterator.Last();

	//
	// While the distance is less than the distance of the entry
	//
	while (distance < iterator.GetValue())
	{
		iterator.Previous();
	}
	audioLevelOfDetail = iterator.GetCurrent();
	Check(audioLevelOfDetail);

	//
	// Verify that the distance is greater than this entry, and less than
	// the next
	//
	#if DEBUG_LEVEL>0
		Verify(distance >= iterator.GetValue());
		iterator.Next();
		if (iterator.GetCurrent() != NULL)
		{
			Verify(distance < iterator.GetValue());
		}
	#endif

	//
	// Dump the LOD of the resource 
	//
	#if 0
		CollectionSize i = 0;
		iterator.First();
		while (iterator.GetCurrent() != NULL)
		{
			Check(iterator.GetCurrent());
			if (audioLevelOfDetail == iterator.GetCurrent() /* && i > 0 */ )
			{
				Tell(
					"AudioLOD:" << i <<
					" d:" << distance <<
					" t:" << iterator.GetValue() <<
					"\n"
				);
				break;
			}
			iterator.Next();
			i++;
		}
	#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioResourceIndex ~~~~~~~~~~~~~~~~~~~~~~~~~~

//
//#############################################################################
//#############################################################################
//
AudioResourceIndex::AudioResourceIndex(PlugStream *stream):
	Node(stream),
	audioResourceSocket(NULL, True)
{
	CollectionSize i, number_of_entries;

	MemoryStream_Read(stream, &number_of_entries);
	for (i = 0; i < number_of_entries; i++)
	{
		AudioResource *audio_resource;

		PlugStream_ReadObjectIDAndFindPlug(stream, &audio_resource);
		Check(audio_resource);
		AddAudioResource(audio_resource, i);
	}
}

//
//#############################################################################
//#############################################################################
//
void
	AudioResourceIndex::BuildFromPage(
		PlugStream *stream,
		NameList *name_list,
		ClassID class_ID,
		ObjectID object_ID
	)
{
	Node::BuildFromPage(stream, name_list, class_ID, object_ID);

	//
	// Count number of entries
	//
	int number_of_entries = 0;
	NameList::Entry *entry;

	Check(name_list);
	entry = name_list->GetFirstEntry();
	while (entry != NULL)
	{
		Check(entry);
		if (entry->IsName("audio_resource"))
			number_of_entries++;
		entry = entry->GetNextEntry();
	}

	//
	// Store entries
	//
	MemoryStream_Write(stream, &number_of_entries);

	Check(name_list);
	entry = name_list->GetFirstEntry();
	while (entry != NULL)
	{
		Check(entry);
		if (entry->IsName("audio_resource"))
		{
			CString object_name;
			ObjectID object_ID;

			Check_Pointer(entry->GetChar());
			object_name = entry->GetChar();

			Check(stream);
			object_ID = stream->FindObjectID(object_name);
			Verify(object_ID != NullObjectID);
			MemoryStream_Write(stream, &object_ID);
		}
		entry = entry->GetNextEntry();
	}
}

//
//#############################################################################
//#############################################################################
//
AudioResourceIndex::~AudioResourceIndex()
{
}

//
//#############################################################################
//#############################################################################
//
Logical
	AudioResourceIndex::TestInstance() const
{
	Node::TestInstance();
	Check(&audioResourceSocket);
	return True;
}

//
//#############################################################################
//#############################################################################
//
void
	AudioResourceIndex::AddAudioResource(
      AudioResource *audio_resource,
      Enumeration index
   )
{
	Check(this);
	audioResourceSocket.AddValue(audio_resource, index);

   #if DEBUG_LEVEL>0
		TableIteratorOf<AudioResource*, Enumeration> iterator(&audioResourceSocket);
		Check(&iterator);
      for (int i = 0; i < iterator.GetSize(); i++)
      {
      	Verify(iterator.GetNth(i) == audioResourceSocket.Find(i));
		}
	#endif
}

//
//#############################################################################
//#############################################################################
//
AudioResource*
	AudioResourceIndex::GetAudioResource(Enumeration index)
{
	Check(this);

	TableIteratorOf<AudioResource*, Enumeration> iterator(&audioResourceSocket);
	Check(&iterator);
	Verify(iterator.GetNth(index) == audioResourceSocket.Find(index));

	return iterator.GetNth(index);
}

//
//#############################################################################
//#############################################################################
//
CollectionSize
	AudioResourceIndex::GetSize()
{
	Check(this);

	TableIteratorOf<AudioResource*, Enumeration> iterator(&audioResourceSocket);
	Check(&iterator);

	return iterator.GetSize();
}


