#include "blitz/network/Connexion.h"
#include "blitz/misc/Compression.h"
#include "blitz/misc/Format.h"
#include "blitz/misc/Log.h"
#include "blitz/misc/Time.h"
#include "blitz/protocol/PacketDispatcher.h"
#include "blitz/protocol/PacketFactory.h"

namespace blitz {
namespace network {

Connexion::Connexion(Connexion&& move) : protocol::PacketHandler(&m_Dispatcher), m_Socket(std::move(move.m_Socket)) {}

Connexion::Connexion(protocol::PacketDispatcher* dispatcher) : protocol::PacketHandler(dispatcher) {}

Connexion::Connexion(protocol::PacketDispatcher* dispatcher, TCPSocket& socket) :
	protocol::PacketHandler(dispatcher), m_Socket(std::move(socket)) {}

bool Connexion::UpdateSocket() {
	if (m_Socket.GetStatus() != TCPSocket::Status::Connected)
		return false;

	while (true) {
		DataBuffer buffer;
		m_Socket.Receive(buffer, sizeof(std::uint64_t));

		if (buffer.GetSize() <= 1)
			break;

		std::uint64_t packetBufferLenght;
		buffer >> packetBufferLenght;

		m_Socket.Receive(buffer, packetBufferLenght);

		DataBuffer decompressed = utils::Decompress(buffer, packetBufferLenght);

		protocol::PacketType packetType;
		decompressed >> packetType;

		protocol::PacketPtr packet = protocol::PacketFactory::CreatePacket(packetType, decompressed);
		GetDispatcher()->Dispatch(packet);
	}
	return true;
}

bool Connexion::Connect(const std::string& address, std::uint16_t port) {
	if (!m_Socket.Connect(address, port)) {
		return false;
	}
	m_Socket.SetBlocking(false);
	return true;
}

void Connexion::SendPacket(const protocol::Packet* packet) {
	network::SendPacket(packet->Serialize(), m_Socket);
	utils::LOGD(utils::Format("Sent packet id %i", packet->GetID()));
}

void Connexion::CloseConnection() {
	m_Socket.Disconnect();
}

Connexion::~Connexion() {}

}  // namespace network
}  // namespace blitz
