#include <cassert>
#include <utility>

#include "network/Server.h"

Server::Client::Client(ENetPeer* peer, int id) : peer(peer), id(id) {
}

Server::Client::~Client() {
    if(peer != nullptr) {
        enet_peer_disconnect(peer, 0);
    }
}

Server::Client::Client(Client&& other) : Client(nullptr, -1) {
    std::swap(peer, other.peer);
    std::swap(id, other.id);
}

Server::Client& Server::Client::operator=(Client&& other) {
    std::swap(peer, other.peer);
    std::swap(id, other.id);
    return *this;
}

int Server::Client::getId() const {
    return id;
}

void Server::Client::send(OutPacket& p) {
    if(p.packet != nullptr) {
        p.packet->dataLength = p.index;
        enet_peer_send(peer, p.channel, p.packet);
        p.packet = nullptr;
    }
}

Server::Server() : server(nullptr), idCounter(1) {
    ENet::add();
}

Server::~Server() {
    for(Client& client : clients.values()) {
        enet_peer_reset(client.peer);
    }
    enet_host_destroy(server);
    ENet::remove();
}

Error Server::start(Port port, int maxClients) {
    assert(server == nullptr);
    if(ENet::hasError()) {
        return {"cannot initialize enet"};
    }
    ENetAddress address;
    memset(&address, 0, sizeof(ENetAddress));
    address.host = ENET_HOST_ANY;
    address.port = port;

    server = enet_host_create(&address, maxClients, 3, 0, 0);
    if(server == nullptr) {
        return {"cannot create enet server host"};
    }
    return {};
}

void Server::send(OutPacket& p) {
    assert(server != nullptr);
    if(p.packet != nullptr) {
        p.packet->dataLength = p.index;
        enet_host_broadcast(server, p.channel, p.packet);
        p.packet = nullptr;
    }
}

void Server::disconnect(Client& client) {
    enet_peer_reset(client.peer);
    clients.remove(client.getId());
}