/*
PolyGun

Copyright (c) 2023 mrkubax10 <mrkubax10@onet.pl>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#ifndef POLYGUN_NETWORK_NETWORK_PACKET_HPP
#define POLYGUN_NETWORK_NETWORK_PACKET_HPP

#include <vector>
#include <cstdint>
#include <cstddef>
#include <string>

namespace polygun::network {
	class NetworkSerializable;

	enum NetworkPacketFlag {
		FLAG_NONE = 0b00000000,
		FLAG_RELIABLE = 0b10000000
	};

	// packets that are only sent to server are prefixed with PACKET_TO_SERVER_
	// same applies to client
	// packets with PACKET_ prefix apply to both
	enum NetworkPacketID {
		// join packets
		PACKET_HANDSHAKE = 0,
		// gameplay packets
		PACKET_ACTION,
		PACKET_MESSAGE,
		PACKET_TO_SERVER_CHUNK_REQUEST,
		// node definition packets
		PACKET_NODE_DEFINITION,
		// resource packets
		PACKET_RESOURCE,
		PACKET_RESOURCE_CHECKSUM,
		// quit packets
		PACKET_EXIT,
		// control packets (for internal use only)
		PACKET_ACK,
		PACKET_ACTIVITY
	};

	class NetworkPacket final {
	public:
		NetworkPacket(uint8_t flags, uint8_t id, uint32_t num = 0);
		NetworkPacket();
		~NetworkPacket() = default;

		void write(uint8_t val);
		void write(uint16_t val);
		void write(uint32_t val);
		void write(float val);
		void write(const std::vector<uint8_t>& val);
		void write(const std::string& val);
		void write(const NetworkSerializable* val);

		bool load(const uint8_t* data, size_t size);
		bool read(uint8_t& output); // unsigned 8-bit number
		bool read(uint16_t& output); // unsigned 16-bit number
		bool read(uint32_t& output); // unsigned 32-bit number
		bool read(float& output); // float
		bool read(std::vector<uint8_t>& output); // unsigned 8-bit number array
		bool read(std::string& output); // string
		bool read(NetworkSerializable* output); // any type which can be serialized

		void reset_reading_offset();
		void reset();

		const std::vector<uint8_t>& get_data() const { return m_data; }
		uint8_t get_flags() const { return m_flags; }
		uint8_t get_id() const { return m_id; }
		uint32_t get_num() const { return m_num; }

	private:
		uint8_t m_flags, m_id;
		uint32_t m_num;
		size_t m_reading_offset;
		std::vector<uint8_t> m_data;
	};
}

#endif // POLYGUN_NETWORK_NETWORK_PACKET_HPP
