#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <cstring>
#include <stdexcept>
#include <unistd.h>
#include <poll.h>

#include "client/network/Client.h"
#include "common/stream/Stream.h"

Client::Client() {
}

Client::~Client() {
    if(connectionSocket != -1) {
        close(connectionSocket);
    }
}

bool Client::start(const string& ip, unsigned short port, IClientListener* listener) {
    connectionSocket = socket(AF_INET, SOCK_STREAM, 0);
    if(connectionSocket == -1) {
        throw runtime_error(string("cannot create socket: ") + strerror(errno));
    }

    struct sockaddr_in socketData;
    memset(&socketData, 0, sizeof (struct sockaddr_in));
    socketData.sin_family = AF_INET;
    socketData.sin_port = htons(port);
    if(inet_aton(ip.data(), &socketData.sin_addr) == 0) {
        throw runtime_error(ip + " is not a valid ip");
    }

    if(connect(connectionSocket, (struct sockaddr*) &socketData, sizeof (struct sockaddr_in)) == 0) {
        clientListener = listener;
        shouldRun = true;
        serverListenThread = thread(&Client::listenOnServer, this);
        return true;
    }
    return false;
}

void Client::stop() {
    shouldRun = false;
    serverListenThread.join();
}

void Client::listenOnServer() {
    struct pollfd fds;
    fds.fd = connectionSocket;
    fds.events = POLLIN;
    fds.revents = 0;

    clientListener->onServerJoin(connectionSocket);

    Stream st;

    while(shouldRun) {
        int pollData = poll(&fds, 1, 100);
        if(pollData > 0) {
            st.readSocket(connectionSocket);
            if(st.hasData()) {
                clientListener->onServerPackage(connectionSocket, st);
            } else {
                // server closed connection
                clientListener->onServerClose(connectionSocket);
                break;
            }
        } else if(pollData == -1) {
            cout << "poll error: " << strerror(errno) << endl;
        }
    }
}