#include "td/network/Connexion.h"
#include "td/protocol/PacketDispatcher.h"
#include "td/protocol/PacketFactory.h"
#include "td/misc/Compression.h"

#include "td/misc/Time.h"

#include <iostream>
#include <chrono>

namespace td {
namespace protocol {

Connexion::Connexion() : protocol::PacketHandler(nullptr) {

}

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, network::TCPSocket& socket) : protocol::PacketHandler(dispatcher), m_Socket(std::move(socket)) {

}

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

	while (true) {
		DataBuffer buffer;
		m_Socket.Receive(buffer, sizeof(std::uint64_t));
		if (buffer.GetSize() == 0)
			break;
		std::uint64_t packetLenght;
		buffer >> packetLenght;

		m_Socket.Receive(buffer, packetLenght);

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

		protocol::PacketType packetType;
		decompressed >> packetType;

		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);
}

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

Connexion::~Connexion() {

}

} // namespace server
} // namespace td
