#pragma once

#include "entity.h"
#include "network.h"

class Mission;

//##########################################################################
//#############################    Icom    #################################
//##########################################################################
class Icom : public Plug
{
	friend class IcomManager;

public:
// constructor is protected: only the IcomManager should call it.

	virtual ~Icom();

	Logical TestInstance() const;

	//--------------------------------------------------
	// These methods are used to set the channel, PTT,
	// and PA status globally across all the cockpits.
	//
	// They invoke the protected 'set value' methods
	// defined below.
	//--------------------------------------------------
	void SetChannel(int new_channel);
	void SetPTTStatus(Logical new_ptt);
	void SetPACaptive(Logical new_pa);
	//--------------------------------------------------
	// These methods allow access to the values
	//--------------------------------------------------
	int GetChannel();
	Logical GetPTTStatus();
	Logical GetPACaptive();

	enum
	{
		undefinedChannel = -1
	};

protected:
	Icom(HostID host_id, int unit_number = 0);
	//--------------------------------------------------
	// These methods are used to locally set the value
	// for the channel, PTT, and PA status.
	//
	// The difference between these methods and the
	// public methods defined above is that these
	// methods are called by both the public routines
	// above and the event receiver to actually
	// set the values involved.  Making them virtual
	// allows derived classes to be notified of changes
	// (but also requires that all derived classes
	// explicitly call the overridden methods!)
	//--------------------------------------------------
	virtual void SetChannelValue(int new_channel);
	virtual void SetPTTStatusValue(Logical new_ptt);
	virtual void SetPACaptiveValue(Logical new_pa);

	HostID hostID;
	int unitNumber;
	int channel, channelBeforePA;
	Logical PTTStatus;
	Logical PACaptive;		// held by operator
};

//##########################################################################
//#####################   IcomManager::Message   ###########################
//##########################################################################

class IcomManager__Message : public Receiver::Message
{
public:
	HostID hostID;
	int unitNumber;

	union
	{
		int channelNumber;
		Logical PTTStatus;
		Logical PAStatus;
	}
	data;

	IcomManager__Message() : Receiver::Message(Receiver::AnyMessageID, sizeof(*this))	{}

	// Message ID's must be passed in as parameters
	// to avoid circular reference (ID's not defined yet)
	void BuildChannelMessage(Receiver::MessageID message_id, HostID host_id, int unit_number, int new_channel)
	{
		messageLength = sizeof(IcomManager__Message);
		messageID = message_id;
		hostID = host_id;
		unitNumber = unit_number;
		data.channelNumber = new_channel;
	}

	void BuildPTTMessage(Receiver::MessageID message_id, HostID host_id, int unit_number, Logical new_status)
	{
		messageLength = sizeof(IcomManager__Message);
		messageID = message_id;
		hostID = host_id;
		unitNumber = unit_number;
		data.PTTStatus = new_status;
	}

	void BuildPAMessage(Receiver::MessageID message_id, HostID host_id, int unit_number, Logical new_status)
	{
		messageLength = sizeof(IcomManager__Message);
		messageID = message_id;
		hostID = host_id;
		unitNumber = unit_number;
		data.PAStatus = new_status;
	}
};

//##########################################################################
//#########################    IcomManager    ##############################
//##########################################################################
class IcomManager : public NetworkClient
{
	friend class Icom;
public:
	static Derivation *GetClassDerivations();
	static SharedData DefaultData;

public:
	enum
	{
		ChannelMessageID = NetworkClient::NextMessageID,
		PTTMessageID,
		PAMessageID,
		NextMessageID
	};

	void ReceiveNetworkPacket(NetworkPacket *packet, Receiver::Message *packet_message);

	typedef IcomManager__Message IMMessage;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
public:
	IcomManager(SharedData &shared_data = DefaultData);
	virtual ~IcomManager();

	Logical TestInstance() const;

	virtual Icom *MakeIcom(HostID host_id, int unit_number=0);
	int AllocateUnitNumber();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LoadMission, Shutdown methods
//
public:
	virtual void LoadMission(Mission *mission);
	virtual void Shutdown();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Periodic update method
//
public:
	virtual void Execute();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Public address (force all intercoms to listen to common channel)
//
	virtual void SetPAState(int channel);	// use Icom::undefinedChannel to release
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Icom object support routines
//
protected:
	Icom *FindIcom(HostID host_id, int unit_number);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// protected data
//
protected:
	int nextUnitNumber;
	ChainOf<Icom*> instanceList;		// list of all Icom objects
};
