#pragma once

/**
 * \file Protocol.h
 * \brief File describing protocol
 */

#include "blitz/common/DataBuffer.h"

namespace blitz {
namespace protocol {

class PacketHandler;

/**
 * \enum PacketType
 * \brief Map the packets name to their ID
 */
enum class PacketType : std::uint8_t {
	// client --> server

	PlayerLogin = 0, /**< Corresponds to PlayerLoginPacket */

	// client <-- server

	ConnexionInfo, /**< Corresponds to ConnexionInfoPacket */
	PlayerJoin,	   /**< Corresponds to PlayerJoinPacket */
	PlayerLeave,   /**< Corresponds to PlayerLeavePacket */
	PlayerList,	   /**< Corresponds to PlayerListPacket */
	ServerTps,	   /**< Corresponds to ServerTpsPacket */

	// client <--> server

	KeepAlive,				   /**< Corresponds to KeepAlivePacket */
	Disconnect,				   /**< Corresponds to DisconnectPacket */
	Chat,					   /**< Corresponds to ChatPacket */
	PlayerPositionAndRotation, /**< Corresponds to PlayerPositionAndRotationPacket */
	PlayerShoot,			   /**< Corresponds to PlayerShootPacket */

	PACKET_COUNT
};

/**
 * \class Packet
 * \brief Represents a network packet <br/>
 * %Packet data structure :
 *| Field Name 			|  Field Type	|  Notes 						|
 *|---------------------|---------------|-------------------------------|
 *| Length 				| Long 			| Length of whole Packet		|
 *| Uncompressed Length | VarInt 		| Length of Packet ID + Data	|
 *| Packet ID 			| Byte   		| Represents the #PacketType 	|
 *| Data 				| Byte Array 	| Depends on the packet ID 		|
 */
class Packet {
  public:
	Packet() {}
	virtual ~Packet() {}

	/**
	 * \brief Serialize the Packet into a DataBuffer to be sent over the network
	 * \param packetID Set to false if you don't want to write the Packet ID for some reason
	 * \returns A DataBuffer filled with the serialized Packet
	 */
	virtual DataBuffer Serialize(bool packetID = true) const = 0;

	/**
	 * \brief Deserialize the DataBuffer into a Packet to be read by the client/server
	 * \param data The DataBuffer containing the data from the network
	 */
	virtual void Deserialize(DataBuffer& data) = 0;

	/**
	 * \brief Dispatches the Packet
	 * \param handler The class to dispatch the Packet to
	 */
	virtual void Dispatch(PacketHandler* handler) const = 0;

	/**
	 * \brief Writes the Packet ID into a buffer
	 * \param data The DataBuffer to write to
	 * \param packetID If set to false, this function does nothing
	 */
	void WritePacketID(DataBuffer& data, bool packetID) const;

	/**
	 * \returns The type of the Packet
	 */
	virtual PacketType GetType() const = 0;

	/**
	 * \returns The Packet ID corresponding to the PacketType of this Packet
	 */
	std::uint8_t GetID() const {
		return static_cast<std::uint8_t>(GetType());
	}
};

}  // namespace protocol
}  // namespace blitz