#include "AdeptHeaders.hpp"

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Component::ClassData*
	Component::CreateFactoryRequest(FactoryRequestParameters *parameters)
{
	Check_Object(parameters);

	//
	//---------------------------------------------------
	// Allocate enough room for what we need to write out
	//---------------------------------------------------
	//
	MemoryStream *component_stream = parameters->m_stream;
	Check_Object(component_stream);
	component_stream->AllocateBytes(sizeof(Component));

	//
	//---------------------
	// Set the component ID
	//---------------------
	//
	*component_stream << parameters->m_index;

	//
	//-----------------------------------------
	// Set the flags that component knows about
	//-----------------------------------------
	//
	bool result = true;
	int flags = 0;
	bool entry;
	Page *page = parameters->m_page;
	Check_Object(page);
	if (page->GetEntry("SimulationShouldExecute", &entry))
	{
		if (entry)
			flags |= SimulationShouldExecuteFlag;
	}
	if (page->GetEntry("RendererShouldExecute", &entry))
	{
		if (entry)
		{
			flags |= RendererShouldExecuteFlag;
			if (flags & SimulationShouldExecuteFlag)
				STOP((
					"%s: [%s] Cannot contain both Simulation and Renderer execution flags!",
					page->GetNotationFile()->GetFileName(),
					page->GetName()
				));
		}
	}
	if (page->GetEntry("Shared", &entry))
	{
		if (entry)
			flags |= SharedFlag;
	}
	if (page->GetEntry("DoesReceiveCommands", &entry))
	{
		if (entry)
			flags |= DoesReceiveCommandsFlag;
	}
	*component_stream << flags;

	Check_Object(DefaultData);
	return (result) ? DefaultData : NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	Component::ReadInputsFromPage(
		FactoryRequestParameters *parameters,
		ClassData *required_class
	)
{
	Check_Object(parameters);

	bool result = true;
	Page *page = parameters->m_page;
	Check_Object(page);
	MemoryStream *component_stream = parameters->m_stream;
	Check_Object(component_stream);

	//
	//-----------------------------------------------------------------
	// Find all the input lines in the page.  There must be at least 1!
	//-----------------------------------------------------------------
	//
	DynamicArrayOf<ComponentDescriptor> *list = parameters->m_components;
	Check_Pointer(list);
	ChainOf<Note*> *input_entries = page->MakeNoteChain("input");
	Register_Object(input_entries);
	Page::NoteIterator inputs(input_entries);
	int input_count = inputs.GetSize();
	if (!input_count)
	{
		STOP((
			"%s: [%s]input entries are missing!",
			page->GetNotationFile()->GetFileName(),
			page->GetName()
		));
	}

	//
	//-----------------------------------------------------------------
	// Write out the number of inputs, and then right out each input id
	//-----------------------------------------------------------------
	//
	*component_stream << input_count;
	Note *input;
	while ((input = inputs.ReadAndNext()) != NULL)
	{
		Check_Object(input);
		const char* input_name = NULL;
		input->GetEntry(&input_name);
		Check_Pointer(input_name);
		int input_id = ComponentDescriptor::FindName(list, parameters->m_index, input_name);
		if (input_id == -1)
		{
			STOP((
				"%s: {[%s]input=%s}: Unknown component name!",
				page->GetNotationFile()->GetFileName(),
				page->GetName(),
				input_name
			));
		}
		else
		{
			Component::ClassData* input_class = (*list)[input_id].m_classData;
			Check_Object(input_class);
			if (!input_class->IsDerivedFrom(required_class))
			{
				STOP((
					"%s: {[%s]input=%s}: Not the right type of component!",
					page->GetNotationFile()->GetFileName(),
					page->GetName(),
					input_name
				));
			}
			else
				*component_stream << input_id;
		}
	}
	Check_Object(input_entries);
	delete input_entries;
	return result;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	ComponentDescriptor::FindName(
		Stuff::DynamicArrayOf<ComponentDescriptor> *array,
		int size,
		const char* name
	)
{
	for (int i=0; i<size; ++i)
	{
		if (!_stricmp(name, (*array)[i].m_name))
			return i;
	}
	return -1;
}
