/**
 * @file comms_al.c
 *
 * @brief #TODO
 *
 * #TODO
 */
/*********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <comms_al.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>

int max(int x, int y)
{
    if (x > y)
        return x;
    else
        return y;
}

/**
 * @brief api that is specifically used to send a data to the udp server
 */

int8_t udp_send(void * intf_handle, uint32_t addr, uint32_t port, uint8_t *data, uint8_t size)
{
    int8_t socket_desc;
    int8_t status;
    struct sockaddr_in server_addr;
    int8_t server_struct_length = sizeof(server_addr);

    //Create socket:
    socket_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    if(socket_desc < 0){

        status = socket_desc;

    }
    else
    {
        //Set port and IP:
        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(5001);
        server_addr.sin_addr.s_addr = inet_addr("192.168.10.2");
        status = sendto(socket_desc, data, size, 0,
                         (struct sockaddr*)&server_addr, server_struct_length);
    }

    close(socket_desc);
    
    return status;
}

int32_t tcp_send(uint32_t addr, uint32_t port, uint8_t *data, uint32_t size)
{
    int32_t status;
    int sockfd;
    struct sockaddr_in servaddr;

    // socket create and verification
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        printf("socket creation failed...\n");
        status = sockfd;
    }
    else
    {
        bzero(&servaddr, sizeof(servaddr));

        // assign IP, PORT
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr = addr;
        servaddr.sin_port = htons(port);

        //printf(" connecting to server ..");
        // connect the client socket to server socket
        while (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
        {

            //printf(".");
            /* wait for server */

        }

        //printf("SOCKET: connected to the server..\n");
        status = write(sockfd, data, size);
        printf("[SOCKET] Successfully transferred data .. %d\n", status);

        // close the socket
        close(sockfd);
    }
    return status;
}

int8_t tcp_recv(uint32_t addr, uint32_t port, uint8_t *data, uint8_t size)
{
    int sockfd, ret,maxsd=0,sd;
    struct sockaddr_in serverAddr;
    int i, socketcount, bytesize;
    int newSocket;
    int clientsocket[10];
    struct sockaddr_in newAddr;
    fd_set readfds;
    FD_ZERO(&readfds);

    socklen_t addr_size;

    char buffer[1024];

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0){
        printf("[-]Error in connection.\n");
        exit(1);
    }
    printf("[+]Server Socket is created.\n");

    memset(&serverAddr, '\0', sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);
    serverAddr.sin_addr.s_addr = addr;
    
    for (i = 0; i < 10; i++)
    {
        clientsocket[i] = 0;
    }

    ret = bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
    if(ret < 0){
        printf("[-]Error in binding..\n");
        exit(1);
    }

    if(listen(sockfd, 10) == 0){
        printf("[+]Listening....\n");
    }else
    {
        printf("[-]Error in listening.\n");
    }
    
    while(1)
    {
        bzero(buffer, sizeof(buffer));
        FD_ZERO(&readfds);
        FD_SET( sockfd, &readfds);
        maxsd = sockfd;
        
        for(i=0;i<10;i++)
        {
            sd = clientsocket[i];
            if(sd>0)
                FD_SET(clientsocket[i],&readfds);
            if(sd>maxsd)
            {
                maxsd = sd;
            }
        }
        
        socketcount = select( maxsd+1, &readfds, NULL, NULL, NULL );
        
        if(socketcount<1)
        {
            printf("[-]Error in select");
        }
        
        if(FD_ISSET(sockfd, &readfds))
        {
            newSocket = accept(sockfd, (struct sockaddr*)&newAddr, &addr_size);
            if(newSocket < 0)
            {
                printf("[-]Error in accepting.\n");
                exit(1);
            }
            //printf("[+]Connection accepted from %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
            for(i=0;i<10;i++)
            {
                if(clientsocket[i]==0)
                    clientsocket[i]=newSocket;
                break;
            }
        }
        else
        {
            for(i=0;i<10;i++)
            {
                sd = clientsocket[i];
                if(FD_ISSET(sd, &readfds))
                {
                    bytesize = recv(sd, data, size,MSG_WAITALL);
                    printf(" recevied size is %d\n", bytesize);
                    if(bytesize==0)
                    {
                        close(sd);
                        clientsocket[i]=0;
                    }
                    else
                    {
                        //TODO This is not right. Server shouldn't return
                         close(sockfd);
                        return bytesize;
                    }
               }
            }
        }    
    }
    close(sockfd);
    return 0;
}

