#ifdef EPS_SIMU_ENABLE
#include <stdio.h>

#ifdef LINUX_TEMP_PORT
#include <netdb.h>
#include <netinet/in.h>
#endif

#ifdef EPS_SIMU_ENABLE
#include <sys/socket.h>
#include <arpa/inet.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h> 
#include "stdint.h"
#include "eps.h"
#include "eps_config.h"
#include "exo_common.h"
#include "exo_osal.h"
#include "log_eps.h"
#include "logger.h"
#include "obc_main.h"

#define MAX 80
#define SA struct sockaddr


int eps_len;
int port;

struct sockaddr_in servaddr;
int connfd;
int sockfd;
int epsfd;
s_obc_sock_info eps_soc_inf;
uint8_t sock_sim_cntct_flag = 0;

/*
 * @brief This API initialize the server socket connection
 */
void eps_simu_server_skt_init()
{

    // socket create and verification
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        DEBUG_CPRINT(("\nEPS_simu socket creation failed...\n"));
        log_id(LOG_INFO_L2, LOG_EPS,EPS_SIMU_SOCKET_CREATION_FAILED);
    }
    else
        DEBUG_CPRINT(("\nEPS simu Socket successfully created..\n"));
    log_id(LOG_INFO_L2, LOG_EPS,EPS_SIMU_SOCKET_SUCCESSFULLY_CREATED);
    bzero(&servaddr, sizeof(struct sockaddr_in));
    // assign IP, PORT

#ifdef LINUX_TEMP_PORT
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr(eps_soc_inf.ip_addr);
    port = (eps_soc_inf.port);
#else
    ip4_addr_t eps_simu_ipaddr;
#ifdef EPS_SIMU_SOC_VIA_ETH
    IP4_ADDR(&eps_simu_ipaddr, ETH_IP_ADDR0, ETH_IP_ADDR1, ETH_IP_ADDR2, ETH_IP_ADDR3);
#else
    IP4_ADDR(&eps_simu_ipaddr, USB_IP_ADDR0, USB_IP_ADDR1, USB_IP_ADDR2, USB_IP_ADDR3);
#endif
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = eps_simu_ipaddr.addr;
    //servaddr.sin_port = PORT;
    //servaddr.sin_port = EPS_SIMU_IP_PORT;
    port = EPS_SIMU_IP_PORT;
#endif
    servaddr.sin_port = htons(port);
    int sts = bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
    if (sts != 0) {
        DEBUG_CPRINT(("\nEPS_simu socket bind failed...\n"));
        log_id(LOG_ERROR, LOG_EPS,EPS_SIMU_SOCKET_BIND_FAILED);
    }
    else
        DEBUG_CPRINT(("\nEPS_simu Socket successfully binded..\n"));
    log_id(LOG_INFO_L2, LOG_EPS,EPS_SIMU_SOCKET_SUCCESSFULLY_BINDED);
    // Now server is ready to listen and verification
    if ((listen(sockfd, 10)) != 0) {
        DEBUG_CPRINT(("\nEPS Listen failed...\n"));
        log_id(LOG_ERROR, LOG_EPS,EPS_LISTEN_FAILED);
    }
    else
        DEBUG_CPRINT(("\nEPS Server listening..\n"));
    log_id(LOG_INFO_L2, LOG_EPS,EPS_SERVER_LISTENING);

}

/*
 * @brief This API accept the client request
 */
void eps_socket_con()
{
    socklen_t len = sizeof(servaddr);
    // Accept the data packet from client and verification
    connfd = accept(sockfd, (SA*)&servaddr,&len);
    if (connfd < 0) {
        sock_sim_cntct_flag = 0;
        DEBUG_CPRINT(("\nEPS server accept failed...\n"));
        log_id(LOG_ERROR, LOG_EPS,EPS_SERVER_ACCEPT_FAILED);
    }
    else
    {
        sock_sim_cntct_flag = 1;

        DEBUG_CPRINT(("\nEPS server client connected...\n"));
        log_id(LOG_INFO_L2, LOG_EPS,EPS_SERVER_CLIENT_CONNECTED);
    }
}

/*
 * @brief This API write the data
 */
uint8_t eps_simu_data_write(uint8_t* buff, uint16_t length)
{
    int ret=-1;
    /*    DEBUG_CPRINT(("EPS write data=="));
          for (int i=0;i<length;i++)
          {
          DEBUG_CPRINT(("%x\t",buff[i]));
          }
          DEBUG_CPRINT(("\n"));*/
    if(sock_sim_cntct_flag)
    {
        if(check_socket_disconnected(connfd))
        {
            printf("Socket disconneted");
            sock_sim_cntct_flag = 0;
            ret = 1;
            close(connfd);
            //Socket disconnected
        }
        else
        {
            ret = write(connfd,buff,length);
            if(ret!=-1)
            {
                //    DEBUG_CPRINT(("\nEPS_simu socket write success\n"));
                ret=0;
            }
            else
            {
                DEBUG_CPRINT(("\nEPS_simu socket write fail\n"));
                log_id(LOG_ERROR, LOG_EPS,EPS_SIMU_SOCKET_WRITE_FAIL);
                ret=1;
                sock_sim_cntct_flag = 0;
                close(connfd);
            }
        }
    }

    return ret;
}

/*
 * @brief This API read the data
 */
uint8_t eps_simu_data_read(uint8_t* buff, uint16_t length)
{
    int ret=-1;


    if(sock_sim_cntct_flag)
    {
        if(check_socket_disconnected(connfd))
        {
            printf("Socket disconneted");
            sock_sim_cntct_flag = 0;
            close(connfd);
            //Socket disconnected
        }
        else
        {
            ret = read(connfd,buff,length);
            if(ret==0)
            {
                sock_sim_cntct_flag = 0;
                close(connfd);
                return 0;
            }

            if(ret!=-1)
            {
                //  DEBUG_CPRINT(("\nEPS_simu socket Read success\n"));
                ret=0;
            }
            else
            {
                DEBUG_CPRINT(("\nEPS_simu socket Read fail\n"));
                log_id(LOG_ERROR, LOG_EPS,EPS_SIMU_SOCKET_READ_FAIL);
                ret=1;
            }
        }

    }
    /*    DEBUG_CPRINT(("EPS Response==\n"));
          for (int i=0;i<length;i++)
          {
          DEBUG_CPRINT(("%x\t",buff[i]));
          }*/
    return ret;
}


void* eps_skt_simu(void* args)
{
    eps_simu_server_skt_init();
    while(1)
    {
        if(sock_sim_cntct_flag == 0)
        {
            eps_socket_con();
        }
#ifdef LINUX_TEMP_PORT
        sleep(1);
#else
        os_delay(1000);
#endif
    }
}

#endif
