/*
	ZNetPeer.hpp
	Author: Patrick Baggett	<ptbaggett@762studios.com>
	Created: 6/5/2013

	Purpose:

	ZNet peer class, representing a remote host

	License:
	
	Copyright 2013, 762 Studios
*/

#pragma once

#ifndef _ZNETPEER_HPP
#define _ZNETPEER_HPP

#include <SST/SST_Net.h>
#include <ZNet/ZNetConsts.hpp>
#include <ZNet/ZNetPacketChannel.hpp>

class ZNetPeer;
class ZNetServer;

class ZNetPeer
{
	public:
		ZNetPeer();
		~ZNetPeer() { Deinitialize(); }

		/*
			ZNetPeer::SetUserData()
			
			Sets the user data for this peer. This value is not
			modified or inspected by ZNet. It defaults to NULL.
			
			@param ud - The user data
		*/
		void SetUserData(void* ud) { userdata = ud; }
		
		/*
			ZNetPeer:GetUserData()
			
			Gets the user data for this peer.
			
			@return (void*) - The user data
		*/
		void* GetUserData() { return userdata; }
		
		/*
			ZNetPeer::GetNetAddress()

			Gets the network address that this remote host uses.

			@return (const SST_NetAddress*) - The remote host's network address
		*/
		const SST_NetAddress* GetNetAddress() const { return &addr; }


		/*
			ZNetPeer::GetState()

			Gets the remote host's state. TODO: Is this necessary for public API?

			@return (ZNetConnectionState) - The connection state
		*/
		ZNetConnectionState GetState() const { return state; }

		/*
			ZNetPeer::GetSocket()

			Gets the socket that was is used to send/receive from the remote host.
		*/
		SST_Socket GetSocket() const { return socketCopy; }

		/*
			ZNetPeer::GetPing()

			Gets the approximate ping. Note that the ping value is only updated
			when a packet is received, so during a disconnect event, this would not
			be accurate. Use GetLastReceived() to find the time since the last packet.

			@return (int32_t) - The last known ping value. If < 0, then the ping is unknown.
		*/
		int32_t GetPing() { return ping; }

		/*
			Gets the timestamp at which the last valid packet was received. Applications
			can use this as a sort of "health" meter for the link and decide how to change
			things such as client predictions during times of high latency. A value of 0
			indicates that no valid packet has yet been received. To compare timestamps,
			use SST_OS_GetMilliTime(). Note that only *valid* packets are considered; so
			hosts sending incompatible data are not considered.

			@return (uint64_t) - The timestamp of the last valid packet.
		*/
		uint64_t GetLastReceived() { return lastValidIncoming; }

	private:

		/* Initialize the peer */
		bool Initialize(ZNetHost* _host, const SST_NetAddress* newAddr, SST_Socket s, uint32_t nrChannels);

		void Deinitialize();

		void SetState(ZNetConnectionState s) { state = s; }
		void SetLastReceived(uint64_t ts) { lastValidIncoming = ts; }
		void SetPing(int32_t _ping) { ping = _ping; }


		uint32_t GetNumberChannels() const { return nrChannels; }

		ZNetPacketChannel* GetPacketChannel(uint32_t chId);


		//Process all received packets' sequence number to come up with a
		//new sequence number to tell the remote server that we've received.
		void ProcessLocalAcks();

		void SendAcksForAllChannels();

		friend class ZNetHost;
		friend class ZNetClient;
		friend class ZNetServer;

		SST_NetAddress addr;			//Remote address
		uint64_t lastValidIncoming;		//Last time a valid packet was received
		uint64_t lastOutgoingAck;		//Last time an outgoing ACK was sent, or 0 for never.
		SST_Socket socketCopy;			//Copy of the socket that was used connect to this peer
		ZNetPacketChannel* channels;	//The packet channels
		void* userdata;					//User data
		uint32_t nrChannels;			//Size of channels[] array
		int32_t ping;					//Estimated ping
		ZNetConnectionState state;		//Connection state
		
		
};

#endif


