#include "AdeptHeaders.hpp"

#include "AudioRenderer.hpp"
#include "AudioFXComponent.hpp"
#include "EarComponent.hpp"
#include "Tool.hpp"

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Component::ClassData*
	AudioRenderer::CreateFactoryRequest(
		const char* component_type,
		Component::FactoryRequestParameters *parameters,
		Entity::ClassData *class_data
	)
{
	Check_Pointer(component_type);
	Check_Object(parameters);

	MemoryStream *component_stream = parameters->m_stream;
	Check_Object(component_stream);
	Channel::FactoryRequestParameters *channel_parameters =
		Cast_Pointer(Channel::FactoryRequestParameters*,parameters);

	//
	//---------------------------------------------
	// Check for any video specific component types
	//---------------------------------------------
	//
	if (!_stricmp(component_type, "EarComponent"))
	{
		*component_stream << static_cast<int>(EarComponentClassID);
		return EarComponent::CreateFactoryRequest(channel_parameters);
	}

	if (!_stricmp(component_type, "AudioFXComponent"))
	{
		*component_stream << static_cast<int>(AudioFXComponentClassID);
		return AudioFXComponent::CreateFactoryRequest(channel_parameters,class_data);
	}

	//
	//--------------------------------------------
	// Have the base renderer encode the component
	//--------------------------------------------
	//
	return
		BaseClass::CreateFactoryRequest(
			component_type,
			parameters,
			class_data
		);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	AudioRenderer::CreateRendererData(
		ResourceID			*stream_resource,
		Entity::ClassData	*class_data,
		NotationFile		*renderer_file
	)
{
	Check_Object(stream_resource);
	Check_Object(class_data);
	Check_Object(renderer_file);

	Check_Object(Resource::ParentFileDependencies);

	Resource audio_res(renderer_file->GetFileName());
	if (!audio_res.DoesResourceExist() || !audio_res.IsResourceUpToDate())
	{
		//
		//----------------------------------------------------------------
		// Now start building the stream by first putting in the number of 
		// components
		//----------------------------------------------------------------
		//
		FileDependencies audio_deps(*renderer_file->GetFileDependencies());
		FileDependencies *parent = Resource::ParentFileDependencies;
		Resource::ParentFileDependencies = &audio_deps;
		NotationFile::PageIterator *pages = renderer_file->MakePageIterator();
		Check_Object(pages);
		int page_count = pages->GetSize();
		Channel::FactoryRequestParameters parameters;

		DynamicMemoryStream component_stream;
		component_stream << page_count;
		parameters.m_stream = &component_stream;

		parameters.m_index = 0;
		parameters.m_commandEncoder = CommandEncoder;
		parameters.m_components = new DynamicArrayOf<ComponentDescriptor>(page_count);
		Check_Object(parameters.m_components);

		//
		//-------------------------------------------------------------------
		// Get the list of component names, and make sure we skip the locator
		// page
		//-------------------------------------------------------------------
		//
		while ((parameters.m_page = pages->ReadAndNext()) != NULL)
		{
			Check_Object(parameters.m_page);

			//
			//------------------------------
			// Get the type of the component
			//------------------------------
			//
			const char* component_type;
			parameters.m_page->GetEntry("Type", &component_type, true);

			//
			//------------------------------------------------------------
			// Store where the stream currently is, and set a dummy length
			//------------------------------------------------------------
			//
			int record_start = component_stream.GetIndex();
			component_stream << 0;

			//
			//---------------------------
			// Call the component creator
			//---------------------------
			//
			Component::ClassData *derivation =
				CreateFactoryRequest(
					component_type,
					&parameters,
					class_data
				);
			Check_Object(derivation);
			int end = component_stream.GetIndex();
			component_stream.SetPointer(record_start);
			component_stream << (end - record_start);
			component_stream.SetPointer(end);
			Check_Object(derivation);

			ComponentDescriptor *descriptor = &(*parameters.m_components)[parameters.m_index++];
			Check_Object(descriptor);
			descriptor->m_name = parameters.m_page->GetName();
			descriptor->m_classData = derivation;
		}
		Verify(parameters.m_index == page_count);

		//
		//-------------------------
		// Release allocated memory
		//-------------------------
		//
		Check_Object(parameters.m_components);
		delete parameters.m_components;
		Check_Object(pages);
		delete pages;

		//
		//----------------------------------------
		// Store the audio stream in the resources
		//----------------------------------------
		//
		Check_Object(Resource::ParentFileDependencies);
		audio_res.Save(&component_stream, &audio_deps);
		if (!audio_res.IsRegistered())
			Resource::ParentFileDependencies->AddDependencies(&audio_deps);
		Resource::ParentFileDependencies = parent;
	}
	else if (!audio_res.IsRegistered())
		audio_res.AddFileDependenciesTo(Resource::ParentFileDependencies);
	*stream_resource = audio_res.GetResourceID();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int AudioRenderer::FindChannelType(const char *type_name)
{
	Check_Pointer(type_name);

	if (!stricmp(type_name, "General"))
		return GeneralType;

	return -1;
}
