#include "MW4Headers.hpp"

#include "EffectGenerator.hpp"

#include <Adept\Effect.hpp>
#include <Adept\Map.hpp>
#include <Adept\Mission.hpp>

//#############################################################################
//###############################    EffectGenerator    #######################
//#############################################################################

EffectGenerator::ClassData*
	EffectGenerator::DefaultData = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	EffectGenerator::InitializeClass()
{
	Verify(!DefaultData);


	DefaultData =
		new ClassData(
			EffectGeneratorClassID,
			"MechWarrior4::EffectGenerator",
			Entity::DefaultData,
			0, NULL,
			(Entity::Factory)Make,
			(Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
			ExecutionStateEngine::DefaultData,
			(Entity::GameModel::Factory)GameModel::ConstructGameModel,
			NULL,
			(Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
			(Entity::GameModel::ModelWrite)GameModel::WriteToText,
			(Entity::GameModel::ModelSave)GameModel::SaveGameModel
		);
	Register_Object(DefaultData);


}

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
EffectGenerator*
	EffectGenerator::Make(
		CreateMessage *message,
		ReplicatorID *base_id
	)
{
	Check_Object(message);
	gos_PushCurrentHeap(Heap);
	EffectGenerator *new_entity =
		new EffectGenerator(DefaultData, message, base_id, NULL);
	gos_PopCurrentHeap();
	Check_Object(new_entity);
	return new_entity;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	EffectGenerator::ClearAllEffects()
{
	Check_Object(this);
	
	ChainIteratorOf<Adept::Effect *> citr(&effectChain);
	citr.First();

	Adept::Effect *eft;
	while((eft=citr.ReadAndNext())!=NULL)
	{
	eft->SentenceToDeathRow();
	}
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
EffectGenerator::~EffectGenerator()
{
	DESTRUCTOR("EffectGenerator");
	Check_Object(this);
	ClearAllEffects();

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
EffectGenerator::EffectGenerator(
	ClassData *class_data,
	CreateMessage *message,
	ReplicatorID *base_id,
	ElementRenderer::Element *element
):
	Entity(class_data, message, base_id, element),
		effectChain(NULL)
{
	Check_Pointer(this);
	Check_Object(message);
	effectResourceID = message->effectResourceID;
	m_nightOnly=message->m_nightOnly;
	m_randomizeTime=message->m_randomizeTime;
	nextDelay=timeDelay=message->timeDelay;
	replay=true;
	shouldCreateEffect = false;
	lastParameterization = gos_GetElapsedTime();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	EffectGenerator::PreCollisionExecute(Stuff::Time till)
{
	Check_Object(this);
	Check_Object(executionState);
	PRECOLLISION_LOGIC("EffectGenerator");


	if(!(m_nightOnly && !Mission::GetInstance()->m_isNightMission))
	{
			
		if((GetTimeParameter(till) > nextDelay) || (shouldCreateEffect))
		{
			shouldCreateEffect = true;
			lastParameterization = gos_GetElapsedTime();
			UsePostCollision();
		}
	}

	Entity::PreCollisionExecute(till);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	EffectGenerator::PostCollisionExecute(Stuff::Time till)
{
	Check_Object(this);
	POSTCOLLISION_LOGIC("EffectGenerator");


	if(shouldCreateEffect)
	{
		shouldCreateEffect = false;
		CreateEffect();
		if(m_randomizeTime)
			if(timeDelay>1.0)
				nextDelay=(Stuff::Random::GetFraction()*(timeDelay-1.0f))+1.0f;
			else
				nextDelay=Stuff::Random::GetFraction();
	}
	Entity::PostCollisionExecute(till);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	EffectGenerator::PlayEffect()
{
	Check_Object(this);
	ClearAllEffects();
	replay = true;
	shouldCreateEffect = true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	EffectGenerator::KillEffect()
{
	Check_Object(this);
	ClearAllEffects();
	replay=false;
	shouldCreateEffect = false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	EffectGenerator::CreateEffect()
{
	Check_Object(this);
	if(!replay) return;

	if(effectResourceID == ResourceID::Null)
		return;

	Resource resource(effectResourceID);
	Verify(resource.DoesResourceExist());
	
	ClassID class_ID;
	class_ID = Entity::GetClassIDFromDataListID(effectResourceID);
	Verify(class_ID != NullClassID);

	Effect::CreateMessage effect_create_message(
		sizeof(Effect::CreateMessage),
		DefaultEventPriority,
		Entity::CreateMessage::DefaultFlags,
		class_ID,
		Effect::DefaultFlags,
		effectResourceID,
		GetLocalToWorld(),
		0.0f,
		Entity::ExecutionStateEngine::AlwaysExecuteState,
		NameTable::NullObjectID,
		Entity::DefaultAlignment
	);
	MemoryStream stream(&effect_create_message, effect_create_message.messageLength);

	ReplicatorID effect_rep_id = Connection::Hermit->GetNextReplicatorID();
	Effect *effect;
	effect = Cast_Object(Effect *,Entity::CreateEntity(&stream, &effect_rep_id, false));
	Check_Object(effect);
	Check_Object(Map::GetInstance());
	if(effect->IsLooped()) replay=false;
	Map::GetInstance()->AddChild(effect);
	effectChain.Add(effect);
	effect->SyncMatrices(true);
}

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