#include "common/network/network_packet.hpp"

#include "common/binary_utils.hpp"

using namespace polygun::network;

NetworkPacket::NetworkPacket(uint8_t flags, uint8_t id, uint32_t num) :
	m_flags(flags),
	m_id(id),
	m_num(num),
	m_reading_offset(0),
	m_data()
{
	write(flags);
	if(flags & NetworkPacketFlag::FLAG_RELIABLE)
		write(num);
	write(id);
}

NetworkPacket::NetworkPacket() :
	m_flags(0),
	m_id(0),
	m_num(0),
	m_reading_offset(0),
	m_data()
{}

void NetworkPacket::write(uint8_t val) {
	m_data.push_back(val);
}

void NetworkPacket::write(uint16_t val) {
	char temp[2];
	utils::uint16_to_bytes(val, temp);
	m_data.push_back(temp[0]);
	m_data.push_back(temp[1]);
}

void NetworkPacket::write(uint32_t val) {
	char temp[4];
	utils::uint32_to_bytes(val, temp);
	m_data.push_back(temp[0]);
	m_data.push_back(temp[1]);
	m_data.push_back(temp[2]);
	m_data.push_back(temp[3]);
}

void NetworkPacket::write(float val) {
	char temp[4];
	utils::float_to_bytes(val, temp);
	m_data.push_back(temp[0]);
	m_data.push_back(temp[1]);
	m_data.push_back(temp[2]);
	m_data.push_back(temp[3]);
}

bool NetworkPacket::load(const uint8_t* data, size_t size) {
	if(size>=2) {
		m_reading_offset = 0;
		m_flags = read_uint8();
		if((m_flags & NetworkPacketFlag::FLAG_RELIABLE) && m_reading_offset+4<=size)
			m_num = read_uint32();
		m_id = read_uint8();
		m_data.assign(data, data+size);
		return true;
	}
	return false;
}

uint8_t NetworkPacket::read_uint8() {
	if(m_reading_offset==m_data.size())
		return 0;
	return m_data[m_reading_offset++];
}

uint16_t NetworkPacket::read_uint16() {
	if(m_reading_offset+2>=m_data.size())
		return 0;
	uint16_t output=utils::bytes_to_uint16((const char*)&m_data[m_reading_offset]);
	m_reading_offset+=2;
	return output;
}

uint32_t NetworkPacket::read_uint32() {
	if(m_reading_offset+4>=m_data.size())
		return 0;
	uint32_t output=utils::bytes_to_uint32((const char*)&m_data[m_reading_offset]);
	m_reading_offset+=4;
	return output;
}

float NetworkPacket::read_float() {
	if(m_reading_offset+4>=m_data.size())
		return 0;
	float output=utils::bytes_to_float((const char*)&m_data[m_reading_offset]);
	m_reading_offset+=4;
	return output;
}

void NetworkPacket::reset_reading_offset() {
	m_reading_offset = 0;
}

void NetworkPacket::reset() {
	m_reading_offset = 0;
	m_data.clear();
}
