#include "AdeptHeaders.hpp"

#include "ComponentHeaders.hpp"

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

	//
	//-------------------------------------------------------------------------
	// Allocate enough room for what we need to write out, then call our parent
	//-------------------------------------------------------------------------
	//
	MemoryStream *component_stream = parameters->m_stream;
	Check_Object(component_stream);
	component_stream->AllocateBytes(sizeof(LFOChannel));
	bool result =
		ChannelOf<Scalar>::CreateFactoryRequest(parameters) != NULL;

	//
	//------------------------------------------------------------------------
	// Find all the input lines in the page and determine the component ids of
	// each of them
	//------------------------------------------------------------------------
	//
	Page *page = parameters->m_page;
	Check_Object(page);
	const char* waveform;
	page->GetEntry("WaveForm", &waveform, true);
	if (!_stricmp(waveform, "SinusoidalWaveForm"))
	{
		*component_stream << static_cast<unsigned>(SinusoidalWaveForm);
	}
	else if (!_stricmp(waveform, "SquareWaveForm"))
	{
		*component_stream << static_cast<unsigned>(SquareWaveForm);
	}
	else if (!_stricmp(waveform, "DescendingTriangularWaveForm"))
	{
		*component_stream << static_cast<unsigned>(DescendingTriangularWaveForm);
	}
	else if (!_stricmp(waveform, "AscendingTriangularWaveForm"))
	{
		*component_stream << static_cast<unsigned>(AscendingTriangularWaveForm);
	}
	else
	{
		STOP((
			"%s: {[%s]WaveForm=%s}: Unsupported wave form type!",
			page->GetNotationFile()->GetFileName(),
			page->GetName(),
			waveform
		));
		result = false;
	}

	Scalar minimum;
	page->GetEntry("MinimumValue", &minimum, true);
	*component_stream << minimum;

	Scalar range;
	page->GetEntry("MaximumValue", &range, true);
	if (range < minimum)
	{
		STOP((
			"%s: {[%s]MaximumValue=%f}: MaximumValue must not be less than Minimum Value!",
			page->GetNotationFile()->GetFileName(),
			page->GetName(),
			range
		));
		result = false;
	}
	else
	{
		range -= minimum;
		*component_stream << range;
	}

	Scalar period;
	page->GetEntry("Period", &period, true);
	if (period <= 0.0f)
	{
		STOP((
			"%s: {[%s]Period=%f}: Period must be greater than 0!",
			page->GetNotationFile()->GetFileName(),
			page->GetName(),
			range
		));
		result = false;
	}
	else
	{
		*component_stream << period;
	}

	Scalar phase=0.0f;
	page->GetEntry("Phase", &phase);
	*component_stream << phase;

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

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

	//
	//-------------------------------------------------------------------------
	// Allocate enough room for what we need to write out, then call our parent
	//-------------------------------------------------------------------------
	//
	MemoryStream *component_stream = parameters->m_stream;
	Check_Object(component_stream);
	component_stream->AllocateBytes(sizeof(Quantizer));
	bool result = ChannelOf<int>::CreateFactoryRequest(parameters) != NULL;

	//
	//-------------------------------
	// Find the input channel to read
	//-------------------------------
	//
	Page *page = parameters->m_page;
	Check_Object(page);
	DynamicArrayOf<ComponentDescriptor> *list = parameters->m_components;
	Check_Pointer(list);
	const char* input_name;
	page->GetEntry("Input", &input_name, true);

	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
		));
		result = false;
	}
	else
	{
		Component::ClassData* class_data = (*list)[input_id].m_classData;
		Check_Object(class_data);
		if (!class_data->IsDerivedFrom(ChannelOf<Scalar>::DefaultData))
		{
			STOP((
				"%s: {[%s]Input=%s}: Not a Scalar channel!",
				page->GetNotationFile()->GetFileName(),
				page->GetName(),
				input_name
			));
			result = false;
		}
		else
		{
			*component_stream << input_id;
		}
	}

	//
	//-----------------------------------------------------------------------
	// For now, the use will only put in the min, max and band count.  Later,
	// each data point will be able to be individually specified
	//-----------------------------------------------------------------------
	//
	int bands;
	page->GetEntry("Bands", &bands, true);
	if (bands <= 0)
	{
		STOP((
			"%s: {[%s]Bands=%d}: Bands must be greater than 0!",
			page->GetNotationFile()->GetFileName(),
			page->GetName(),
			bands
		));
		result = false;
	}
	else
	{
		++bands;
		*component_stream << bands;
	}

	//
	//----------------
	// Read the limits
	//----------------
	//
	Scalar minimum, maximum;
	page->GetEntry("Minimum", &minimum, true);
	page->GetEntry("Maximum", &maximum, true);
	if (minimum >= maximum)
	{
		STOP((
			"%s: {[%s]Maximum=%f}: Maximum must be greater than Minimum!",
			page->GetNotationFile()->GetFileName(),
			page->GetName(),
			maximum
		));
		result = false;
	}
	Scalar step = (maximum - minimum) / static_cast<Scalar>(bands - 1);
	for (int i=0; i<bands; ++i)
	{
		*component_stream << minimum;
		minimum += step;
	}

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