/*******************************************************************************
 * Copyright (c) 2014 IBM Corp.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Eclipse Distribution License v1.0 which accompany this distribution.
 *
 * The Eclipse Public License is available at
 *    http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at
 *   http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * Contributors:
 *    Ian Craggs - initial API and implementation and/or initial documentation
 *    Sergio R. Caprile - "commonalization" from prior samples and/or documentation extension
 *******************************************************************************/

#include "transport.h"

#include "lwip/opt.h"
#include "lwip/arch.h"
#include "lwip/api.h"
#include "lwip/inet.h"
#include "lwip/sockets.h"

#include "string.h"

/**
This simple low-level implementation assumes a single connection for a single thread. Thus, a static
variable is used for that connection.
On other scenarios, the user must solve this by taking into account that the current implementation of
MQTTPacket_read() has a function pointer for a function call to get the data to a buffer, but no provisions
to know the caller or other indicator (the socket id): int (*getfn)(unsigned char*, int)
*/
static int mysock = -1;

int32_t transport_sendPacketBuffer(int sock, unsigned char* buf, int buflen)
{
    int rc = 0;
    rc = write(sock, buf, buflen);
    return rc;
}

int32_t transport_getdata(unsigned char* buf, int count)
{
    int rc = recv(mysock, buf, count, 0);
//    printf("received %d bytes count %d buf %s\n", rc, (int)count, buf);
    return rc;
}

int transport_getdatanb(void *sck, unsigned char* buf, int count)
{
    /* sck: pointer to whatever the system may use to identify the transport */
    int sock = *((int *)sck);
    /* this call will return after the timeout set on initialization if no bytes;
    in your system you will use whatever you use to get whichever outstanding
    bytes your socket equivalent has ready to be extracted right now, if any,
    or return immediately */
    int rc = recv(sock, buf, count, 0);
    if (rc == -1)
    {
        /* check error conditions from your system here, and return -1 */
        return 0;
    }
    return rc;
}

/**
return >=0 for a socket descriptor, <0 for an error code
@todo Basically moved from the sample without changes, should accomodate same usage for 'sock' for clarity,
removing indirections
*/
int32_t transport_open(char* addr, int port)
{
    int *sock = &mysock;
    struct sockaddr_in address;
    static struct timeval tv;
    
    memset(&address,0,sizeof(address));
    /* Initialize server address information */
    address.sin_len         = sizeof(address);
    address.sin_family      = AF_INET;
    address.sin_port        = PP_HTONS(port);
    address.sin_addr.s_addr = inet_addr((const char*)addr);
    
    *sock = -1;
    /* Creating a socket */
    *sock = socket(AF_INET, SOCK_STREAM, 0);
    
    /* Connect to server */
    if (connect(*sock, (struct sockaddr*)&address, sizeof(address)) != 0)
    {
        /* Close connection */
        close(*sock);
        return -1;
    }
    
    /* 1 second Timeout */
    tv.tv_sec = 1;
    tv.tv_usec = 0;
    /* Setting the timeout */
    setsockopt(mysock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
    
    /* Return a valid socket */
    return mysock;
}

int transport_close(int sock)
{
    int rc;

    rc = shutdown(sock, SHUT_WR);
    rc = recv(sock, NULL, (size_t)0, 0);
    rc = close(sock);

    return rc;
}
