#pragma once

#include "vtvsub.h"
#include "..\munga\linmtrx.h"

class Motion;

//############################################################################
//Generic Gun Subsystem Resource

struct GenericGun__SubsystemResource :
	public VTVSubsystem::SubsystemResource
{
	ResourceDescription::ResourceID	ammoVideoResourceID;

	int
		rearSiteIndex;
};

//############################################################################
//###############		Class	Generic Gun     ##################################
//############################################################################

class GenericGun:
	public VTVSubsystem
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data Support
//
public:
	static Derivation *GetClassDerivations();
	static SharedData DefaultData;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Messaging Support
//
public:
	enum {
		ConfigureMappablesMessageID = VTVSubsystem::NextMessageID,
		ChooseButtonMessageID,
		NextMessageID
	};

	void
		ConfigureMappablesMessageHandler(
			ReceiverDataMessageOf<ControlsButton> *message
		);
	void
		ChooseButtonMessageHandler(
			ReceiverDataMessageOf<ControlsButton> *message
		);

protected:
	static const HandlerEntry
		MessageHandlerEntries[];
	static MessageHandlerSet
		MessageHandlers;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Attribute Support
//
public:
	enum {
		TriggerStateAttributeID	= VTVSubsystem::NextAttributeID,
		PercentDoneAttributeID,
		NextAttributeID
	};

private:
	static const IndexEntry AttributePointers[];

public:
	//static AttributeIndexSet	AttributeIndex
	static AttributeIndexSet& GetAttributeIndex();

//
// public attribute std::declarations go here
//
public:
	int
		triggerState;
	Scalar
		percentDone;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Model Support
//
public:

	enum {
		Firing = VTVSubsystem::StateCount,
		StateCount
	};

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

	void
		GenericGunSimulation(Scalar time_slice);

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

  virtual int
		Fire() {std::cout<<"GenericGun::Fire() Should not be here!"<<std::endl; return False;}

  void
		CalcAmmoOrigin(Origin *);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
public:
	typedef GenericGun__SubsystemResource SubsystemResource;

	static int
		CreateStreamedSubsystem(
			NotationFile					*model_file,
			const char						*model_name,
			const char						*subsystem_name,
			SubsystemResource				*subsystem_resource,
			NotationFile					*subsystem_file,
			ResourceFile					*resource_file,
			const ResourceDirectories	*directories
		);

protected:
	GenericGun(
		VTV			*owner,
		int			subsystem_ID,
		SubsystemResource *sub_res,
		SharedData	&shared_data=DefaultData
	);
	~GenericGun();

	Logical
		TestInstance() const;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Local data for the gun class
//

protected:
	int
		oldTriggerState;
	ResourceDescription::ResourceID
		ammoVideoResourceID;

	LinearMatrix
		siteFrontTransform,
		siteRearTransform;
};

//############################################################################
//Rivet Gun Subsystem Resource
struct RivetGun__SubsystemResource :
	public GenericGun::SubsystemResource
{
	Scalar
		loadTime;
	Scalar
		ammoCount;
	Vector3D
		muzzleVelocity;
};

//############################################################################
//################		Class	Rivet Gun     ##################################
//############################################################################

class	RivetGun :
	public GenericGun
{

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data Support
//

public:
	static Derivation *GetClassDerivations();
	static SharedData DefaultData;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Attribute Support
//
public:
	enum {
		TimeToLoadedAttributeID	=	GenericGun::NextAttributeID,
		AmmoCountAttributeID,
		NextAttributeID
	};

private:
	static const IndexEntry AttributePointers[];

public:
	//static AttributeIndexSet	AttributeIndex
	static AttributeIndexSet& GetAttributeIndex();

//
// public attribute std::declarations go here
//
public:
	Scalar
		timeToLoaded;
	Scalar
		ammoCount;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Model Support
//
public:
	enum {
		MisFire = GenericGun::StateCount,
		NoAmmo,
		Loaded,
		Loading,
		StateCount
	};

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

	void
		RivetGunSimulation(Scalar time_slice);

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

	VTV*
		GetEntity()
			{Check(this); return Cast_Object(VTV*, Subsystem::GetEntity());}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//   Damage Support
//
void
	DeathReset(int reset_command);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
public:
	typedef RivetGun__SubsystemResource SubsystemResource;

	RivetGun(
		VTV		*owner,
		int			subsystem_ID,
		SubsystemResource *sub_res,
		SharedData	&shared_data=DefaultData
	);
	~RivetGun();

	Logical
		TestInstance() const;

	static int
		CreateStreamedSubsystem(
			NotationFile					*model_file,
			const char						*model_name,
			const char						*subsystem_name,
			SubsystemResource				*subsystem_resource,
			NotationFile					*subsystem_file,
			ResourceFile					*resource_file,
			const ResourceDirectories	*directories
		);
protected:

	int
		Fire();

	Scalar
		loadTime;
	Vector3D
		muzzleVelocity;

	Scalar
		maxAmmoCount;

	void
		CalcAmmoMotion(Motion *);
};
//##########################################################################
//#####################    LaserGun::UpdateRecord         #####################
//##########################################################################

struct LaserGun__UpdateRecord :
	public GenericGun::UpdateRecord
{
	Vector3D
		laserScale;

	Logical
		frontLaserOn,
		rearLaserOn;

};
//############################################################################
// Laser Gun Subsystem Resource
struct LaserGun__SubsystemResource :
	public GenericGun::SubsystemResource
{
	Scalar
		fullChargeDuration;

	Scalar
		laserDuration;

	Scalar
		chargeLevel;

	Scalar
		chargePerSecond;

	Scalar
  	drainPerSecond;

	Scalar
		laserLength;

	ResourceDescription::ResourceID
		explosionResourceID;

	Damage
		damageData;

	Scalar
  	pulseDuration;
};

//############################################################################
//################		Class	Laser Gun     ##################################
//############################################################################

class	LaserGun :
	public GenericGun
{

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data Support
//

public:
	static Derivation *GetClassDerivations();
	static SharedData DefaultData;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Attribute Support
//
public:
	enum {
		FrontLaserOnAttributeID	=	GenericGun::NextAttributeID,
		RearLaserOnAttributeID,
		LaserScaleAttributeID,
		NextAttributeID
	};

private:
	static const IndexEntry AttributePointers[];

public:
	//static AttributeIndexSet	AttributeIndex
	static AttributeIndexSet& GetAttributeIndex();

//
// public attribute std::declarations go here
//
public:

	Logical
		frontLaserOn,
		rearLaserOn;

	Vector3D
		laserScale;



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Model Support
//
public:
	enum{
		Charging = GenericGun::StateCount,
		Misfire,
     PulseFiring,
		StateCount
	};
	typedef void (LaserGun::*Performance)(Scalar time_slice);

	void
		ChargingSimulation(Scalar time_slice);

	void
		FiringSimulation(Scalar time_slice);

	void
		PulseFiringSimulation(Scalar time_slice);

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

	VTV*
		GetEntity()
			{Check(this); return Cast_Object(VTV*, Subsystem::GetEntity());}


protected:
	typedef LaserGun__UpdateRecord  UpdateRecord;

	void
		WriteUpdateRecord(Simulation::UpdateRecord *message, int update_model);
	void
		ReadUpdateRecord(Simulation::UpdateRecord *message);


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Damage Support
//

	Damage
		damageData;
void
	DeathReset(int reset_command);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
public:
	typedef LaserGun__SubsystemResource SubsystemResource;

	LaserGun(
		VTV			*owner,
		int			subsystem_ID,
		SubsystemResource *sub_res,
		SharedData	&shared_data=DefaultData
	);
	~LaserGun();

	Logical
		TestInstance() const;

	static int
		CreateStreamedSubsystem(
			NotationFile					*model_file,
			const char						*model_name,
			const char						*subsystem_name,
			SubsystemResource				*subsystem_resource,
			NotationFile					*subsystem_file,
			ResourceFile					*resource_file,
			const ResourceDirectories	*directories
		);

protected:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Local  Support
//
	int
		Fire();

	Scalar
     fullChargeDuration,
		maxChargeLevel,
		chargeLevel;

	Scalar
  	maxLaserDuration,
		laserDuration,
		pulseDuration,
		maxPulseDuration;

	Scalar
		chargePerSecond,
		drainPerSecond;

	Scalar
		maxLaserLength;

	ResourceDescription::ResourceID
		explosionResourceID;

	void
		CalcPercentDone();

	Logical
		hitSomething;
};

//############################################################################
//################		Class	DemolitionPackDropper ##########################
//############################################################################

class	DemolitionPackDropper :
	public RivetGun
{

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data Support
//

public:
	static Derivation *GetClassDerivations();
	static SharedData DefaultData;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
public:
	
	DemolitionPackDropper(
		VTV			*owner,
		int			subsystem_ID,
		SubsystemResource *sub_res,
		SharedData	&shared_data=DefaultData
	);
	~DemolitionPackDropper();

	Logical
		TestInstance() const;

	static int
		CreateStreamedSubsystem(
			NotationFile					*model_file,
			const char						*model_name,
			const char						*subsystem_name,
			SubsystemResource				*subsystem_resource,
			NotationFile					*subsystem_file,
			ResourceFile					*resource_file,
			const ResourceDirectories	*directories
		);

	void
		DeathReset(int reset_command);

protected:
	int
		Fire();
};
