#include "Client.h"
#include "Constants.h"
#include "Protocoll.h"

#include <iostream>
#include <thread>

Client::Client(std::string _serverIP, int port) : connected(new Connected(this)),
                                                  connecting(new Connecting(this)),
                                                  disconnected(new Disconnected(this))
{

    udpSocket = SDLNet_UDP_Open(constants::CLIENT_PORT);

    if (udpSocket == nullptr)
    {
        std::cout << "\tSDLNet_UDP_Open failed : " << SDLNet_GetError() << std::endl;
    }

    // Set IP and port number with correct endianess
    if (SDLNet_ResolveHost(&serverIP, _serverIP.c_str(), port) == -1)
    {
        std::cout << "\tSDLNet_ResolveHost failed : " << SDLNet_GetError() << std::endl;
    }

    connectionRequest = SDLNet_AllocPacket(512);

    if (connectionRequest == nullptr)
    {
        std::cout << "\tSDLNet_AllocPacket failed : " << SDLNet_GetError() << std::endl;
    }
    ConnectionRequest conReq = ConnectionRequest();
    memcpy(connectionRequest->data, &conReq, sizeof(ConnectionRequest));
    connectionRequest->len = sizeof(ConnectionRequest);

    receivedPacket = SDLNet_AllocPacket(512);

    if (receivedPacket == nullptr)
    {
        std::cout << "\tSDLNet_AllocPacket failed : " << SDLNet_GetError() << std::endl;
    }

    this->setClientState(connecting);
}

void Client::setClientState(ClientState *state)
{
    std::cout << "State changed!" << std::endl;
    currentState = state;
}

void Client::update(unsigned int delta)
{
    currentState->update(delta);
    using namespace std::chrono_literals;
    std::this_thread::sleep_for(2s);
}

bool Client::sendConnectionRequest(IPaddress dest)
{
    connectionRequest->address.host = dest.host;
    connectionRequest->address.port = dest.port;
    return this->sendPacket(*connectionRequest);
}

bool Client::sendPacket(UDPpacket &packet)
{
    // Send
    // SDLNet_UDP_Send returns number of packets sent. 0 means error
    if (SDLNet_UDP_Send(this->udpSocket, -1, &packet) == 0)
    {
        std::cout << "\tSDLNet_UDP_Send failed : " << SDLNet_GetError() << "\n"
                  << "==========================================================================================================\n";
        return false;
    }
    return true;
}

Client::~Client()
{
    delete connected;
    delete connecting;
    delete disconnected;
    SDLNet_FreePacket(connectionRequest);
    SDLNet_FreePacket(receivedPacket);
    SDLNet_UDP_Close(udpSocket);
}