#pragma once

#include "node.h"
#include "hostid.h"
#include "schain.h"
#include "network.h"

class Entity;

//##########################################################################
//#######    Support types for entity identity and host manager    #########
//##########################################################################

enum HostType
{
	GameMachineHostType,
	CameraShipHostType,
	MissionReviewHostType,
	ConsoleHostType
};

//##########################################################################
//############################    Host    ##################################
//##########################################################################

class Host:
	public Node
{
	friend class HostManager;

	friend class Host__AllEntityIterator;
	friend class Host__DynamicMasterEntityIterator;
	friend class Host__DynamicReplicantEntityIterator;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Public types
//
public:
	typedef Host__AllEntityIterator
		AllEntityIterator;

	//
	// NoNetworkConnectionStatus -
	//		Initial state, host just created with no net link
	// OpeningConnectionStatus -
	//		Waiting for completion of an active open to this host
	// ListeningConnectionStatus -
	//		Waiting for this host to connect to us
	// OnLineConnectionStatus -
	//		Host is on-line and ready
	//
	enum ConnectionStatus
	{
		NoNetworkConnectionStatus,
		OpeningConnectionStatus,
		ListeningConnectionStatus,
		OnLineConnectionStatus
	};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, and testing
//
public:
	Host(
		HostID host_ID,
		HostType host_type,
		const SOCKADDR_IN *network_address
	);
	~Host();

	Logical
		TestInstance() const;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Accessors
//
public:
	HostType
		GetHostType();
	HostID
		GetHostID();

	inline SOCKADDR_IN *GetNetworkAddress()	{ return &networkAddress; }
	inline void SetNetworkAddress(const SOCKADDR_IN *network_address) { networkAddress = *network_address; }

	ConnectionStatus
		GetConnectStatus();
	void
		SetConnectStatus(ConnectionStatus new_status);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Host Manager support
//
private:
	void
		AddEntity(Entity *entity);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private data
//
private:
	HostID				hostID;
	HostType			hostType;
	SOCKADDR_IN			networkAddress;
	ConnectionStatus	currentConnectStatus;

	//
	// The all entity socket contains all entities that are on this host.
	//
	SChainOf<Entity*>
		allEntitySocket;

	//
	// The dynamic master entity socket contains all entities that are
	// masters and dynamic
	//
	SChainOf<Entity*>
		dynamicMasterEntitySocket;

	//
	// The dynamic replicant entity socket contains all entities that are
	// replicants and dynamic
	//
	SChainOf<Entity*>
		dynamicReplicantEntitySocket;
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Host inlines  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

inline HostType
	Host::GetHostType()
{
	Check(this);
	return hostType;
}

inline HostID
	Host::GetHostID()
{
	Check(this);
	return hostID;
}

inline Host::ConnectionStatus
	Host::GetConnectStatus()
{
	Check(this);
	return currentConnectStatus;
}

inline void
	Host::SetConnectStatus(ConnectionStatus new_status)
{
	Check(this);
	currentConnectStatus = new_status;
}

//~~~~~~~~~~~~~~~~~~~~~~~~ Host__AllEntityIterator ~~~~~~~~~~~~~~~~~~~~~~~~~

class Host__AllEntityIterator:
	public SChainIteratorOf<Entity*>
{
public:
	Host__AllEntityIterator(Host *host);
	~Host__AllEntityIterator();
};

//~~~~~~~~~~~~~~~~~~~~ Host__DynamicMasterEntityIterator ~~~~~~~~~~~~~~~~~~~

class Host__DynamicMasterEntityIterator:
	public SChainIteratorOf<Entity*>
{
public:
	Host__DynamicMasterEntityIterator(Host *host);
	~Host__DynamicMasterEntityIterator();
};

//~~~~~~~~~~~~~~~~~~~ Host__DynamicReplicantEntityIterator ~~~~~~~~~~~~~~~~~

class Host__DynamicReplicantEntityIterator:
	public SChainIteratorOf<Entity*>
{
public:
	Host__DynamicReplicantEntityIterator(Host *host);
	~Host__DynamicReplicantEntityIterator();
};
