#pragma once

#include "entity.h"
#include "boxsolid.h"
#include "table.h"

//##########################################################################
//#####################    Explosion::ModelResource    #####################
//##########################################################################

struct Explosion__ModelResource
{
	ObjectID resourceTableObjectID;
	Scalar explosionDuration;
};

//##########################################################################
//###########################    Explosion    ##############################
//##########################################################################

class Explosion__MakeMessage;

class Damage;
class Mover;

class Explosion : public Entity
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data support
//
public:
	static Derivation *GetClassDerivations();

	static SharedData DefaultData;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Model Support
//
public:
	typedef Explosion__ModelResource
		ModelResource;

	typedef void
		(Explosion::*Performance)(Scalar time_slice);

	void
		SetPerformance(Performance performance)
		{
			Check(this);
			activePerformance = (Simulation::Performance)performance;
		}

	void
		ExplosionSimulation(Scalar time_slice);

	static ResourceDescription::ResourceID
		Explosion::CreateModelResource(
			ResourceFile *resource_file,
			const char *model_name,
			NotationFile *model_file,
			const ResourceDirectories *directories
		);


	typedef ChainIteratorOf<Entity*>  EntityIterator;

	void
		SplashDamage(
			EntityID inflicting,
			Damage &damage,
			Scalar collisionRadius,
			Vector3D offset = Vector3D::Identity,
			Entity *exludedEntities = NULL
		);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
public:
	typedef Explosion__MakeMessage
		MakeMessage;

	static Explosion*
		Make(MakeMessage *creation_message);

	Explosion(
		MakeMessage *creation_message,
		SharedData &virtual_data = DefaultData
	);
	~Explosion();

	Logical
		TestInstance() const;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
public:
	Enumeration
		GetInterestPriority(Entity *linked_entity);

	// The entity this explosion hit.  Read by the BT death-wreck render script
	// (effect 104: swap the victim's visual to its <mech>dbr burning hulk).
	Entity *GetEntityHit()	{ return entityHit; }

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Protected Data
//
protected:
	Scalar
		explosionDuration;
	Entity
		*entityHit;
	Entity
		*creatingEntity;
	Point3D
		localHitPosition;
};

//##########################################################################
//#####################    Explosion::MakeMessage    #######################
//##########################################################################

class Explosion__MakeMessage:
	public Entity::MakeMessage
{
public:
	EntityID
		entityHitID;
	EntityID
		creatingEntityID;

	Explosion__MakeMessage(
		Receiver::MessageID message_ID,
		size_t length,
		Entity::ClassID class_ID,
		const EntityID &owner_ID,
		ResourceDescription::ResourceID resource_ID,
		LWord instance_flags,
		const Origin &origin,
		const EntityID &entity_hit_ID,
		const EntityID &creating_entity_ID
	):
		Entity::MakeMessage(
			message_ID,
			length,
			class_ID,
			owner_ID,
			resource_ID,
			instance_flags,
			origin
		),
		entityHitID(entity_hit_ID),
		creatingEntityID(creating_entity_ID)
		{}
};

//##########################################################################
//######################    ExplosionResourceTable    ######################
//##########################################################################

class ExplosionResourceTable:
	public Plug
{
public:
	typedef PlugOf<ResourceDescription::ResourceID>
		ResourceIDPlug;

	ExplosionResourceTable(PlugStream *stream);
	~ExplosionResourceTable();

	static void
		BuildFromPage(
			ObjectStream *stream,
			NameList *name_list,
			ClassID class_ID,
			ObjectID object_ID
		);

	Logical
		TestInstance() const;

	ResourceDescription::ResourceID
		FindResourceID(Enumeration material_type);
	ResourceDescription::ResourceID
		FindResourceID(Entity *entity_hit);

private:
	TableOf<ResourceIDPlug*, Enumeration>
		resourceIDSocket;
};
