#include "Net.h"

TCPsocket MZSocketD; /* Socket descriptor */
string MZnetBufferRx;
string MZnetBufferTx;
int MZConnRetry = 0;
int MZnetQueuedCommands = 0;
int MZnetQueuedSending = 0;
bool MZnetTRSD = false;
bool MZnetTSSD = false;

int MZnetConnect(const char *host, Uint16 port) {
    IPaddress ip;
    int len;
    MZConnRetry++;
    /* Resolve the host we are connecting to */
    if (MZConnRetry > MZNET_MAXRETRY) {
        fprintf(stderr, "RED: Se supero el maximo de %d reintentos de conexion.\n", MZNET_MAXRETRY);
        exit(EXIT_FAILURE);
    }
    if (SDLNet_ResolveHost(&ip, host, port)) {
        fprintf(stderr, "SDLNet_ResolveHost: %s. Intento numero %d.\n", SDLNet_GetError(), MZConnRetry);
        return (-1);
    }

    /* Open a connection with the IP provided (listen on the host's port) */
    if (!(MZSocketD = SDLNet_TCP_Open(&ip))) {
        fprintf(stderr, "SDLNet_TCP_Open: %s. Intento numero %d.\n", SDLNet_GetError(), MZConnRetry);
        return (-1);
    } else {
        MZConnRetry = 0;
        cout << "CONECTADO!" << endl;
    }
    return 0;
}

int MZnetThreadRcv(void *data) {
    int tick = 0;
    int gLastTick = 0;
    int received = 0;
    int commandEnding = 0;
    char tmpBufferRx[MZNET_PCKTSIZE];
    MZnetConnect(MZNET_HOST, MZNET_PORT);
    while (!MZnetTRSD) {
        tick = SDL_GetTicks();
        tmpBufferRx[0] = '\0';
        if (MZSocketD != NULL && ((received = SDLNet_TCP_Recv(MZSocketD, tmpBufferRx, MZNET_PCKTSIZE)) > 0)) { // recive 
            SDL_mutexP(itfzRXBuffLock);
            string in(tmpBufferRx, received);
            MZnetBufferRx += in;
            commandEnding = -1;
            MZnetQueuedCommands = 0;
            while ((commandEnding = MZnetBufferRx.find('\n', commandEnding + 1)) != -1) {
                MZnetQueuedCommands++;
            }
            SDL_mutexV(itfzRXBuffLock);
        } else {
            SDLNet_TCP_Close(MZSocketD);
            MZnetConnect(MZNET_HOST, MZNET_PORT);
        }

        gLastTick = SDL_GetTicks();
        if (gLastTick - tick <= 100)
            SDL_Delay(100 - (gLastTick - tick));

    }
    return 0;
}

int MZnetThreadSnd(void *data) {
    int tick = 0;
    int gLastTick = 0;
    int len = 0;
    int commandEnding;
    int cola = 0;
    string comando;
    char tmpBufferTx[MZNET_PCKTSIZE];
    tmpBufferTx[0] = '\0';
    while (!MZnetTSSD) {
        tick = SDL_GetTicks();

        if (MZnetQueuedSending) {
            SDL_mutexP(itfzTXBuffLock);
            commandEnding = MZnetBufferTx.find('\n');
            len = commandEnding + 1;
            if (cola + len < MZNET_PCKTSIZE) {
                cola += len;
                comando = MZnetBufferTx.substr(0, len);
                cout << "ENVIANDO: " << comando << endl;
                MZnetBufferTx.erase(0, len);
                MZnetQueuedSending--;
                strcat(tmpBufferTx, comando.c_str());
            }

            SDL_mutexV(itfzTXBuffLock);
        }
        if (cola > 0) {
            if (MZSocketD == NULL || SDLNet_TCP_Send(MZSocketD, tmpBufferTx, cola) < cola) {
                SDLNet_TCP_Close(MZSocketD);
            } else {
                tmpBufferTx[0] = '\0';
                cola = 0;
            }
        }
        gLastTick = SDL_GetTicks();
        if (gLastTick - tick <= 100)
            SDL_Delay(100 - (gLastTick - tick));

    }

    SDLNet_TCP_Close(MZSocketD);
    SDLNet_Quit();
    return 0;
}

void MZnetSend(string data) {
    SDL_mutexP(itfzTXBuffLock);
    MZnetBufferTx += data;
    MZnetBufferTx += "\n";
    MZnetQueuedSending++;
    SDL_mutexV(itfzTXBuffLock);
}

void MZNetShutDown(void) {
    SDL_mutexP(itfzTXBuffLock);
    MZnetTRSD = true;
    MZnetQueuedSending = 0;
    MZnetBufferTx = "";
    SDL_mutexV(itfzTXBuffLock);
    MZnetSend("tsoff");
    MZnetSend("tsoff");
    MZnetSend("X");
    MZnetSend("X");

    while (MZnetQueuedSending > 0) {
        SDL_Delay(500);
    }

    MZnetTSSD = true;
    SDLNet_TCP_Close(MZSocketD);
    SDLNet_Quit();

}



