/***************************************************************************
                         ADM_vs
                             -------------------
    begin                : Mon Jun 3 2002
    copyright            : (C) 2002 by mean
    email                : fixounet@free.fr
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifdef _WIN32
#include "winsock2.h"
#define SERROR SOCKET_ERROR
#else
#include "sys/socket.h"
#define SERROR -1
#endif
// clang-format off
#include "config.h"
#include "ADM_default.h"
#include "ADM_coreAvsProtocol.h"
// clang-format on
/**
 *
 */
avsSocket::avsSocket()
{
    mySocket = 0;
}
/**
 *
 * @param newSocket
 */
avsSocket::avsSocket(int newSocket) : ADM_socket(newSocket)
{
}
/**
 *
 * @param cmd
 * @param frame
 * @param payloadSize
 * @param payload
 * @return
 */
bool avsSocket::receive(uint32_t *cmd, uint32_t *frame, uint32_t *payloadSize, uint8_t *payload)
{
    SktHeader header;
    memset(&header, 0, sizeof(header));

    int rx = ::recv(mySocket, (char *)&header, sizeof(header), 0);
    if (sizeof(header) != rx)
    {
        ADM_warning("Error in receivedata: header, expected %d, received %d\n", (int)sizeof(header), rx);
        fflush(stdout);
        return false;
    }
    *cmd = header.cmd;
    *payloadSize = header.payloadLen;
    *frame = header.frame;
    if (header.magic != (uint32_t)MAGGIC)
    {
        ADM_warning("Wrong magic\n");
        fflush(stdout);
        return false;
    }
    if (header.payloadLen)
    {
        int togo = header.payloadLen;
        int chunk;
        while (togo)
        {
            chunk = recv(mySocket, (char *)payload, togo, 0);
            if (chunk < 0)
            {
                ADM_warning("Error in senddata: body\n");
                fflush(stdout);
                return false;
            }
            togo -= chunk;
            payload += chunk;
        }
    }
    return true;
}
/**
 *
 * @param timeoutMs
 * @return
 */
avsSocket *avsSocket::waitForConnect(uint32_t timeoutMs)
{
    if (!mySocket)
    {
        ADM_error("Wait for connect called with no socket opened\n");
        return NULL;
    }
    // Wait for connect...
    fd_set set;
    FD_ZERO(&set);
    FD_SET(mySocket, &set);
    struct timeval timeout;

    uint32_t sec = timeoutMs / 1000;

    timeout.tv_sec = sec;
    timeout.tv_usec = ((timeoutMs - sec * 1000)) * 1000; // us
    // ADM_info("Selecting\n");
    int evt = select(1 + mySocket, &set, NULL, NULL, &timeout);
    if (evt <= 0)
    {
        ADM_error("Select failed\n");
        return NULL;
    }

    int workSocket = SERROR;
    ADM_info("Accepting...\n");
    workSocket = accept(mySocket, NULL, NULL);
    if (SERROR == workSocket)
    {
        ADM_error("Accept failed\n");
        return NULL;
    }
    return new avsSocket(workSocket);
}
/**
 *
 * @param cmd
 * @param frame
 * @param payload_size
 * @param payload
 * @return
 */
bool avsSocket::sendData(uint32_t cmd, uint32_t frame, uint32_t payload_size, uint8_t *payload)
{
    SktHeader header;
    memset(&header, 0, sizeof(header));

    header.cmd = cmd;
    header.payloadLen = payload_size;
    header.frame = frame;
    header.magic = (uint32_t)MAGGIC;

    if (sizeof(header) != send(mySocket, (char *)&header, sizeof(header), 0))
    {
        ADM_warning("Error in senddata: header\n");
        fflush(stdout);
        return false;
    }
    int togo = payload_size;
    int chunk;
    while (togo)
    {
        chunk = send(mySocket, (char *)payload, togo, 0);
        if (chunk < 0)
        {
            ADM_warning("Error in senddata: body\n");
            fflush(stdout);
            return false;
        }
        togo -= chunk;
        payload += chunk;
    }
    return true;
}
// EOF
