#include "AdeptHeaders.hpp"

#include "VideoHeaders.hpp"
#include <ElementRenderer\StateChange.hpp>

using namespace ElementRenderer;

//
// Class Data Support
//
Component::ClassData*
	VideoComponent::DefaultData = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	VideoComponent::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			VideoComponentClassID,
			"Adept::VideoComponent",
			BaseClass::DefaultData,
			0, NULL
		);
	Register_Object(DefaultData);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	VideoComponent::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
VideoComponent::VideoComponent(
	ClassData *class_data,
	MemoryStream *stream,
	VideoComponentWeb *owning_web,
	Element* child
):
	Component(
		class_data,
		stream,
		owning_web
	)
{
	Check_Pointer(this);
	Check_Pointer(child);
	componentElement = child;

	//
	//-------------------------------------------------
	// Hook up to our translation input if there is one
	//-------------------------------------------------
	//
	LinearMatrix4D matrix;
	*stream >> matrix;
	child->SetLocalToParent(matrix);

	//
	//-----------------------
	// Read any state changes
	//-----------------------
	//
	unsigned delta;
	*stream >> delta;
	if (delta)
	{
		unsigned state;
		*stream >> state;
		componentElement->SetElementState(
			(componentElement->GetElementState()&~delta) | (delta&state)
		);
		if (delta & Element::OBBFlag)
			*stream >> componentElement->m_localOBB;
	}

	//
	//-------------------------------------------------------------------
	// Read a state change from stream, but if it has no changes, kill it
	//-------------------------------------------------------------------
	//
	StateChange *states =
		new StateChange(stream, ElementRenderer::ReadERFVersion(stream));
	Register_Object(states);
	if (states->IsRealStateChange())
		child->AdoptStateChange(states);
	else
	{
		Unregister_Object(states);
		delete states;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
VideoComponent::~VideoComponent()
{
	Check_Object(this);
	Unregister_Object(componentElement);
	delete componentElement;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	VideoComponent::SkipStreamData(MemoryStream *stream)
{
	Check_Object(this);
	Check_Object(stream);

	//
	//-------------------------------------------
	// Skip the matrix
	//-------------------------------------------
	//
	BaseClass::SkipStreamData(stream);
	LinearMatrix4D matrix;
	*stream >> matrix;

	//
	//-----------------------
	// Skip the state changes
	//-----------------------
	//
	unsigned delta;
	*stream >> delta;
	if (delta)
	{
		unsigned state;
		*stream >> state;
		if (delta & Element::OBBFlag)
			*stream >> componentElement->m_localOBB;
	}

	STOP(("Not implemented"));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
unsigned
	VideoComponent::GetStreamSize(MemoryStream *stream)
{
	STOP(("Not implemented..."));
	return
		BaseClass::GetStreamSize(stream)
		 + sizeof(LinearMatrix4D)
		 + 2*sizeof(unsigned)
		 + sizeof(OBB);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	VideoComponent::Execute()
{
	Check_Object(this);
	Check_Object(componentElement);
	componentElement->Sync();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	VideoComponent::TestInstance()
{
	Verify(IsDerivedFrom(DefaultData));
}

//
// Class Data Support
//
Component::ClassData*
	GroupComponent::DefaultData = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	GroupComponent::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			GroupComponentClassID,
			"Adept::GroupComponent",
			BaseClass::DefaultData,
			0, NULL
		);
	Register_Object(DefaultData);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	GroupComponent::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
GroupComponent::GroupComponent(
	ClassData *class_data,
	MemoryStream *stream,
	VideoComponentWeb *owning_web,
	GroupElement* holder
):
	VideoComponent(
		class_data,
		stream,
		owning_web,
		(holder) ? holder : AllocateGroup(stream)
	)
{
	//
	//---------------------------------------------------------------------
	// Read in child ID's until we find a NULL.  For each child, hook it up
	// to this parent
	//---------------------------------------------------------------------
	//
	ComponentID component_id;
	component_id.scriptResourceID = owning_web->GetScriptResourceID();
	*stream >> component_id.componentNumber;
	while (component_id.componentNumber != -1)
	{
		Component *component = owning_web->FindComponent(component_id);
		Check_Object(component);
		VideoComponent *child =
			Cast_Object(VideoComponent*, component);
		AttachChild(child);
		*stream >> component_id.componentNumber;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
GroupElement*
	GroupComponent::AllocateGroup(MemoryStream *stream)
{
	Check_Object(stream);

	//
	//---------------------------------------------------------------------
	// Deal with the billboard type.  We have to skip ahead to see what the
	// data will be, so remember where we are
	//---------------------------------------------------------------------
	//
	GroupElement *node = new GroupElement;
	Register_Object(node);
	return node;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	GroupComponent::SkipStreamData(MemoryStream *stream)
{
	Check_Object(this);
	Check_Object(stream);

	//
	//----------------------------------------
	// Read in child ID's until we find a NULL
	//----------------------------------------
	//
	BaseClass::SkipStreamData(stream);
	ComponentID component_id;
	*stream >> component_id.componentNumber;
	while (component_id.componentNumber != -1)
		*stream >> component_id.componentNumber;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
GroupComponent*
	GroupComponent::Make(
		MemoryStream *stream,
		VideoComponentWeb *owning_web
	)

{
	GroupComponent *lod =
		new GroupComponent(DefaultData, stream, owning_web);
	return lod;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	GroupComponent::AttachChild(VideoComponent* child)
{
	Check_Object(this);
	Check_Object(child);

	Element *element = GetElement();
	Check_Object(element);
	Element *part = child->GetElement();
	Check_Object(part);
	element->AttachChild(part);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	GroupComponent::TestInstance()
{
	Verify(IsDerivedFrom(DefaultData));
}
