#include "AdeptHeaders.hpp"

#include "VideoHeaders.hpp"
#include <gosFX\EffectLibrary.hpp>
#include <ElementRenderer\gosFXElement.hpp>

#include "Entity.hpp"
#include "Attribute.hpp"

//############################################################################
//###############################  gosFXComponent  ################################
//############################################################################

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

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

}

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
gosFXComponent::gosFXComponent(
	ClassData *class_data,
	MemoryStream *stream,
	VideoComponentWeb *owning_web
):
	VideoComponent(class_data, stream, owning_web, ReadFX(stream))
{
	Check_Object(this);
	ElementRenderer::gosFXElement *effect = GetElement();
	Check_Object(effect);
	gosFX::Effect *gos_effect = effect->GetEffect();
	Check_Object(gos_effect);

	//
	//------------------------------------------------------
	// Read the attribute id and find it in the web's entity
	//------------------------------------------------------
	//
	int attribute_id;
	*stream >> attribute_id;
	owningEntity = owning_web->GetEntity();
	Check_Object(owningEntity);
	if (attribute_id != -1)
	{
		statusPointer = owningEntity->GetAttributeEntry(attribute_id);
		Check_Object(statusPointer);
		Verify(statusPointer->attributeType == BoolClassID);
	}
	else
	{
		statusPointer = NULL;
		Verify(gos_effect->IsLooped());
		Verify(gos_effect->IsExecuted());
	}

	//
	//--------------------------------------------
	// Start the effect if its execute flag is set
	//--------------------------------------------
	//
	if (gos_effect->IsExecuted())
	{
		gosFX::Effect::ExecuteInfo
			info(
				gos_GetElapsedTime(),
				&effect->GetLocalToWorld(),
				NULL
			);
		gos_effect->Start(&info);
		if(statusPointer)
		{
			bool result = true;
			statusPointer->SetValue(owningEntity, &result);
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::gosFXElement* gosFXComponent::ReadFX(MemoryStream *stream)
{
	Check_Object(stream);

	//
	//---------------------
	// Get the gosFX number
	//---------------------
	//
	int gfx_id;
	unsigned flags;
	*stream >> gfx_id >> flags;
	Check_Object(gosFX::EffectLibrary::Instance);
	gosFX::Effect *gos_effect =
		gosFX::EffectLibrary::Instance->MakeEffect(gfx_id, flags);
	Register_Object(gos_effect);

	gos_PushCurrentHeap(ElementRenderer::gosFXElement::s_Heap);
	ElementRenderer::gosFXElement *effect = new ElementRenderer::gosFXElement(gos_effect);
	gos_PopCurrentHeap();

	Register_Object(effect);
	return effect;
}

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

	int gfx_id;
	unsigned flags;
	int attribute_id;
	*stream >> gfx_id >> flags >> attribute_id;

	BaseClass::SkipStreamData(stream);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
gosFXComponent*
	gosFXComponent::Create(
		MemoryStream *stream,
		VideoComponentWeb *owning_web
	)
{
	Check_Object(stream);
	Check_Object(owning_web);
	Component *component = DoesComponentExist(stream, owning_web);
	gosFXComponent *object;
	if (component)
	{
		object = static_cast<gosFXComponent*>(component);
		Check_Object(object);
		object->SkipStreamData(stream);
	}
	else
	{
		object = new gosFXComponent(DefaultData, stream, owning_web);
		Register_Object(object);
	}
	return object;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	gosFXComponent::Execute()
{
	Check_Object(this);
	ElementRenderer::gosFXElement *effect = GetElement();
	Check_Object(effect);
	gosFX::Effect *gos_effect = effect->GetEffect();
	Check_Object(gos_effect);
	Verify(
		gos_effect->GetSimulationMode() != gosFX::Effect::DynamicWorldSpaceSimulationMode
		 || !effect->IsMatrixDirty()
	);

	//
	//------------------
	// Execute the gosFX
	//------------------
	//
	bool result = false;
	if (gos_effect->IsExecuted())
	{
		gosFX::Effect::ExecuteInfo
			info(
				gos_GetElapsedTime(),
				&effect->GetLocalToWorld(),
				&effect->m_localOBB
			);
		{
			Start_Timer(gosFX::Animation_Time);
			result = gos_effect->Execute(&info);
			Stop_Timer(gosFX::Animation_Time);
		}

		//
		//---------------------------
		// Update the bounding sphere
		//---------------------------
		//
		if (result && effect->m_localOBB.sphereRadius > 0.0f)
			effect->NeedNewBounds();
		else
			effect->SetNeverCullMode();
		effect->Sync();
	}
	else
		effect->SetAlwaysCullMode();

	//
	//------------------------------
	// Set the status is appropriate
	//------------------------------
	//
	if (statusPointer)
	{
		Check_Object(statusPointer);
		Check_Object(owningEntity);
#if 0
		if(gos_effect->IsLooped())
			result = true;
#endif
		statusPointer->SetValue(owningEntity, &result);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	gosFXComponent::ChannelChanged(Channel *channel)
{
	Check_Object(this);
	Check_Object(channel);
	ElementRenderer::gosFXElement *effect = GetElement();
	Check_Object(effect);
	gosFX::Effect *gos_effect = effect->GetEffect();
	Check_Object(gos_effect);

	gosFX::Effect::ExecuteInfo
		info(
			gos_GetElapsedTime(),
			&effect->GetLocalToWorld(),
			NULL
		);
	switch (channel->GetCommand())
	{
	case VideoRenderer::StartEffectCommandID:
//		Verify(!gos_effect->InWorldSpace() || !effect->IsMatrixDirty());
		gos_effect->Start(&info);
		break;

	case VideoRenderer::StopEffectCommandID:
		gos_effect->Stop();
		break;

	case VideoRenderer::KillEffectCommandID:
		gos_effect->Kill();
		break;

	default:
		BaseClass::ChannelChanged(channel);
		break;
	}
}

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