#pragma once

#include "entity.h"
#include "icom.h"
#include "scnrole.h"

class Mission;
class DropZone__ReplyMessage;

//##########################################################################
//#####################    Player::MakeMessage    ##########################
//##########################################################################
class Player__MakeMessage:
	public Entity::MakeMessage
{
public:

	int
		playerBitmapIndex;

	Player__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,
		int   player_bitmap_index
	):
		Entity::MakeMessage(
			message_ID,
			length,
			class_ID,
			owner_ID,
			resource_ID,
			instance_flags,
			origin
		),
		playerBitmapIndex(player_bitmap_index)
	{ }

	Player__MakeMessage(
		Receiver::MessageID message_ID,
		size_t length,
		const EntityID &entity_ID,
		Entity::ClassID class_ID,
		const EntityID &owner_ID,
		ResourceDescription::ResourceID resource_ID,
		LWord instance_flags,
		const Origin &origin,
		int	player_bitmap_index
	):
		Entity::MakeMessage(
			message_ID,
			length,
			entity_ID,
			class_ID,
			owner_ID,
			resource_ID,
			instance_flags,
			origin
		),
		playerBitmapIndex(player_bitmap_index)
	{ }

};

//##########################################################################
//###################      Player::UpdateRecord         ####################
//##########################################################################

struct Player__UpdateRecord :
	public Entity::UpdateRecord
{
	Scalar
		currentScore;
	Point3D
		dropZoneLocation;
};

//##########################################################################
//#################    ScoreZone::ReplyMessage    ##########################
//##########################################################################

class Player__ScoreMessage :
	public Entity::Message
{
public:
	Scalar
		scoreAward;

	Player__ScoreMessage(
		Receiver::MessageID message_ID,
		size_t length,
		Scalar score
	):
		Entity::Message(message_ID, length),
		scoreAward(score)
			{}
};

//##########################################################################
//#################    ScoreZone::ReplyMessage    ##########################
//##########################################################################

class Player__VehicleDeadMessage:
	public Entity::Message
{
public:
	int deathCount;
	EntityID dropZoneID;

	Player__VehicleDeadMessage(
		Receiver::MessageID message_ID,
		size_t length,
		const EntityID &dropzone_id=EntityID::Null
	):
		Entity::Message(message_ID, length),
		deathCount(-1),
		dropZoneID(dropzone_id)
			{}
};

//##########################################################################
//######################   Player::StatusMessage   #########################
//##########################################################################
class Player;

class Player__StatusMessage:
	public Node
{
public:
	Player__StatusMessage(
		Player *player_involved,
		int message_type,
		Scalar display_time
	);

	enum {
		NoMessage = -1,
		NextMessageType = 0
	};

	int
		messageType;
	Player
		*playerInvolved;
	Scalar
		displayTime;
};

//##########################################################################
//###########################    Player    ################################
//##########################################################################

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Attribute Support
//
	enum
	{
		CurrentScoreAttributeID = Entity::NextAttributeID,
		DropZoneLocationAttributeID,
		PlayerRankingAttributeID,
		StatusMessagePointerAttributeID,
		PlayerBitmapIndexAttributeID,
		PlayerHighlightedAttributeID,
		NextAttributeID
	};

private:

	static const IndexEntry
		AttributePointers[];

protected:

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

	virtual int
		CalcRanking();

public:

	Logical
		playerHighlighted;

	Scalar
		currentScore;
	int
		playerRanking;
	
	Point3D
		dropZoneLocation;

	Player__StatusMessage
		*statusMessagePointer;

	int
		playerBitmapIndex;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Gauge Support
//
public:
	typedef Player__StatusMessage
		StatusMessage;
	void
		AddStatusMessage(StatusMessage *status_message);
	void
		StatusMessageUpdate(Scalar time_slice);

protected:
	ChainOf<StatusMessage*>
		statusMessageQueue;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Message Support
//
public:
	enum
	{
		DropZoneReplyMessageID = Entity::NextMessageID,
		ScoreMessageID,
		VehicleDeadMessageID,
		MissionStartingMessageID,
		MissionEndingMessageID,
		NextMessageID
	};

	typedef Player__VehicleDeadMessage VehicleDeadMessage;

private:
	static const HandlerEntry MessageHandlerEntries[];

protected:
	//static MessageHandlerSet MessageHandlers;
	static MessageHandlerSet& GetMessageHandlers();

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Game start/stop support
//
public:
	typedef Message MissionStartingMessage;
	typedef Message MissionEndingMessage;

protected:
	void
		MissionStartingMessageHandler(Message *message);
	void
		MissionEndingMessageHandler(Message *message);

	Scalar
		fadeTimeRemaining;

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

	enum {
		DropZoneAcquiredState = Entity::StateCount,
		VehicleTranslocatedState,
		MissionStartingState,
		MissionEndingState,
		StateCount
	};

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

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

	virtual void
		PlayerSimulation(Scalar time_slice);

	virtual void
		CameraShipSimulation(Scalar time_slice);

	void
		GoToVehicle(Scalar time_slice);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Vehicle creation
//
protected:
	void
		DropZoneReplyMessageHandler(DropZone__ReplyMessage *message);
	void
		VehicleDeadMessageHandler(VehicleDeadMessage *message);

	void
		HuntForDropZone(Scalar time_slice);

	Mission*
		playerMission;

	Entity*
		playerVehicle;

	int
		deathCount;

public:
	Entity*
		GetPlayerVehicle()
			{Check(this); return playerVehicle;}

	void
		SetPlayerVehicle(Entity *player_vehicle)
			{
				Check(player_vehicle);
				Check(this);
				playerVehicle = player_vehicle;
			}

	Mission*
		GetMission()
			{
				Check(this);
				return playerMission;
			}

	int
		GetDeathCount()
			{Check(this); return deathCount;}
protected:

	virtual void
		CreatePlayerVehicle(Origin);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Renderer Support
//
public:
	Enumeration
		GetAudioRepresentation(Entity *linked_entity);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Intercom Support
//
public:
	Icom*
		GetIntercom()
			{
				Check(this);
				return intercomPointer;
			}

protected:
	Icom
		*intercomPointer;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//	Scoring Support
//
public:
	typedef Player__ScoreMessage ScoreMessage;

	const ScenarioRole*
		GetScenarioRole() const
	{Check(this); return scenarioRole; }

protected:
	void
		ScoreMessageHandler(ScoreMessage *message);

	ScenarioRole
  	*scenarioRole;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Flag Support
//
public:
	enum {
		NonScoringPlayerBit = Entity::NextBit,
		CameraShipPlayerBit,
		NextBit
	};

	enum {
		NonScoringPlayerFlag = 1 << NonScoringPlayerBit,
		CameraShipPlayerFlag = 1 << CameraShipPlayerBit,
		DefaultFlags =
			Entity::DefaultFlags
			 | NonScoringPlayerFlag
			 | PreRunFlag
	};

	void
		SetNonScoringPlayerFlag()
			{Check(this); simulationFlags |= NonScoringPlayerFlag;}
	void
		SetScoringPlayerFlag()
			{Check(this); simulationFlags &= ~NonScoringPlayerFlag;}

	Logical
		IsScoringPlayer()
			{Check(this); return (simulationFlags&NonScoringPlayerFlag) == 0;}

	Logical IsCameraShipPlayer()
	{
		Check(this);
		return (simulationFlags & CameraShipPlayerFlag) != 0;
	}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Update Support
//

	typedef Player__UpdateRecord UpdateRecord;

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
public:

	typedef Player__MakeMessage MakeMessage;

	static Player*
		Make(MakeMessage *creation_message);

	Player(
		MakeMessage *creation_message,
		SharedData &shared_data = DefaultData
	);
	~Player();

	Logical
  	TestInstance() const;

protected:

	void
		ManageApplicationStatus(Scalar time_slice);
};
