#include <vppinfra/clib.h>
#include <vppinfra/vec.h>
#include <vppinfra/hash.h>
#include <vppinfra/bitmap.h>
#include <vppinfra/fifo.h>
#include <vppinfra/time.h>
#include <vppinfra/heap.h>
#include <vppinfra/pool.h>
#include <vppinfra/format.h>
#include <vppinfra/error.h>
#include <vlibapi/api_common.h>
#include <vppinfra/string.h>

#include <vnet/vnet.h>
#include <vlib/vlib.h>
#include <vlibapi/api.h>
#include <vlib/unix/unix.h>
#include <vlibapi/api.h>
#include <vlibmemory/api.h>

#include <vpp/api/vpe_msg_enum.h>

#include <vnet/ip/ip.h>
#include <vnet/interface.h>
#include <vnet/interface.api_types.h>

#define vl_typedefs             /* define message structures */
#include <vpp/api/vpe_all_api_h.h>
#undef vl_typedefs

#define vl_endianfun            /* define message structures */
#include <vpp/api/vpe_all_api_h.h>
#undef vl_endianfun

/* instantiate all the print functions we know about */
#define vl_print(handle, ...)
#define vl_printfun
#include <vpp/api/vpe_all_api_h.h>
#undef vl_printfun

#define foreach_api_msg                                                 \
_(SW_INTERFACE_SET_FLAGS_REPLY, sw_interface_set_flags_reply)           \
_(SW_INTERFACE_ADD_DEL_ADDRESS_REPLY, sw_interface_add_del_address_reply)


api_main_t *api_main;
static int api_connected;
static char api_connection_name[250];
static unix_shared_memory_queue_t *api_vl_input_queue;
static u32 api_client_index;
static volatile int api_result_ready;
static volatile int api_result_retval;
static clib_time_t api_clib_time;
vlib_main_t vlib_global_main;
vlib_main_t **vlib_mains;

u32 vpp_client_context = 0xdeadbeef;

static void
  vl_api_sw_interface_add_del_address_reply_t_handler
  (vl_api_sw_interface_add_del_address_reply_t * mp)
{
  printf("add_del_address reply %d\n", ntohl (mp->retval));
}

static void
  vl_api_sw_interface_set_flags_reply_t_handler
  (vl_api_sw_interface_set_flags_reply_t * mp)
{
  printf("set flags reply: reply %d\n", ntohl (mp->retval));
}

static void
noop_handler (void *notused)
{
}


int vpp_connect_to_vlib( )
{
	char* error = NULL;
	int rc = -1;
	api_main_t *am = vlibapi_get_main ();


	rc = vl_client_connect_to_vlib("/vpe-api", "app_client", 32);

        if ( rc < 0 )
        {
            printf("vl_client_connect_to_vlib fails for error code_1 = %d ",rc);
	    svm_region_exit();
            return -1;
        }
	else
	{
            printf("vl_client_connect_to_vlib successful_2 \n ");
	}

#define _(N,n)                                                  \
    vl_msg_api_set_handlers(VL_API_##N, #n,                     \
                           vl_api_##n##_t_handler,              \
                           noop_handler,                        \
                           vl_api_##n##_t_endian,               \
                           vl_api_##n##_t_print,                \
                           sizeof(vl_api_##n##_t), 1);
  foreach_api_msg;
#undef _

        //am = &api_main;
        api_vl_input_queue = am->shmem_hdr->vl_input_queue;
        api_client_index = am->my_client_index;
        api_connected = 1;

	printf(" api_client_index = %d \n",api_client_index);
	printf(" api_client_index = %d \n",am->our_pid);
	printf(" api_client_index = %d \n",am->shmem_hdr->vl_pid);

        return 0;
}



void 
main()
{
   clib_mem_init (0, 64 << 20);
   vpp_connect_to_vlib();

   int ifindex_host_eth2 = 1;
   int ifindex_host_eth3 = 2;


   //plumb the IP address on the host-eth3
   vpp_add_del_interface_address (1,   //enable_disable
                               ifindex_host_eth3, //ifindex for host-eth3
                               1, //isIPv4
                               "10.22.6.20");


   //Set admin state down for the host-eth3
   vpp_set_admin_state_up(1,ifindex_host_eth3);


   vl_client_disconnect_from_vlib();

   sleep(60);

   return;
}

int
vpp_set_admin_state_up(int up_down,int ifindex)
{
        vl_api_sw_interface_set_flags_t *mp;

        mp = vl_msg_api_alloc (sizeof (*mp));
        clib_memset (mp, 0, sizeof (*mp));

        mp->_vl_msg_id = clib_host_to_net_u16  (VL_API_SW_INTERFACE_SET_FLAGS);
        mp->client_index = api_client_index;
        mp->context = vpp_client_context;
        mp->sw_if_index = clib_host_to_net_u32  (ifindex);
        //mp->flags = IF_STATUS_API_FLAG_ADMIN_UP;
        mp->flags = IF_STATUS_API_FLAG_LINK_UP & IF_STATUS_API_FLAG_ADMIN_UP;
        vl_msg_api_send_shmem (api_vl_input_queue, (u8 *) & mp);
        return 0;
}

int
vpp_add_del_interface_address (int enable_disable,
                               int ifindex,
                               int isIPv4,
                               char* if_ip)
{
	vl_api_sw_interface_add_del_address_t *mp;
	errno_t err;
	rsize_t len = 0;
        char* error = NULL;

        len = ( isIPv4 == 1 ) ? 24 : 16;
	u8 ip[4] = { 0xA, 0xe4, 0x06, 0x14 };

        mp = vl_msg_api_alloc(sizeof (*mp));
	    memset (mp, 0, sizeof (*mp));
        mp->_vl_msg_id = clib_host_to_net_u16  (VL_API_SW_INTERFACE_ADD_DEL_ADDRESS);
        mp->client_index = api_client_index;
        mp->context = vpp_client_context;
        mp->prefix.address.af = ( isIPv4 == 1 ) ? ADDRESS_IP4 : ADDRESS_IP6;
        mp->sw_if_index = clib_host_to_net_u32  (ifindex);
        mp->is_add = enable_disable;

        if( enable_disable == 0 )
        {
            mp->del_all = 1;
        }
        else
        {
            mp->prefix.len = len;
	    memcpy(mp->prefix.address.un.ip4,ip,4);
        }
        vl_msg_api_send_shmem(api_vl_input_queue,(u8 *) &mp); 

        return 0;
}

