#ifndef ASTERISK_NBIO_H
#define ASTERISK_NBIO_H

#include <sys/poll.h>
#include <inttypes.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define NBIO_CONNECTION_CB(func) ((nbio_connection_cb_t)func)
#define NBIO_EVENT_CB(func) ((nbio_event_cb_t)func)

typedef struct _nbio_socket nbio_socket_t;

typedef int (*nbio_event_cb_t)(nbio_socket_t * nbio, int event, void * user_data);
typedef int (*nbio_connection_cb_t)(int server_fd, int new_fd, struct sockaddr * sin, void * user_data);

#define AST_NBIO_TYPE_LISTEN   0x00000001
#define AST_NBIO_TYPE_INCOMING 0x00000002
#define AST_NBIO_TYPE_OUTGOING 0x00000004
#define AST_NBIO_TYPE_CONTROL  0x00000008

#define AST_NBIO_FLAG_NODELAY  0x00000010
#define AST_NBIO_FLAG_BLOCK    0x00000020

enum {
	AST_NBIO_EVENT_NVAL,
	AST_NBIO_EVENT_ERR,
	AST_NBIO_EVENT_HUP,
	AST_NBIO_EVENT_IN
} nbio_event_t;

typedef struct {
	/*
	 * Data is ready - Read as much from the socket as you want, and
	 * return how many bytes were read.  Note that a read() might return
	 * 0 if the remote end has closed the socket.
	 *
	 * Remember the socket is non blocking, so
	 *
	 */
	nbio_event_cb_t data;
	nbio_event_cb_t close;
	nbio_event_cb_t error;
} nbio_eventset_incoming_t;

struct _nbio_socket {
	int fd;								/* FD */
	uint8_t flags; 						/* NBIO flags (See above) */
	char * desc;						/* Short description for this thread */
	void * user_data;					/* User data */
	int sin_len;						/* Length of sockaddr for this protocol */

	/* Outgoing Buffer Support */
	void * buffer_out_ptr;				/* malloc()'ed outgoing buffer space */
	int buffer_out_pos;					/* Current Position in outgoing buffer */
	int buffer_out_len;					/* Current length of outgoing buffer */

	union {								/* Function to use on POLLIN */
		nbio_connection_cb_t listen;	/*  For AST_NBIO_TYPE_LISTEN socket */
	} incoming;

	union {
		nbio_eventset_incoming_t * incoming;
	} cb;



};

//! Adds a listening socket for NBIO to monitor
/*
 * \param fd        FD to monitor for incoming connections
 * \param desc      Description for this socket
 * \param callback  Function to call when a connection is made to this socket
 * \param user_data Pointer for data to be passed to callback function
 *
 * Returns 0 on success, -1 on error.
 *
 */

int
ast_nbio_listen(int fd, int flags, const char * desc, nbio_connection_cb_t callback, int sockaddr_len, void * user_data);

//! Creates a listening TCP socket and adds to the NBIO manager
/*
 * \param addr      sockaddr_in The address/port to bind to
 * \param flags     Flags for this socket - see above.
 * \param desc      Description for this socket
 * \param callback  Function to call when a connection to this socket happens
 * \param user_data Pointer to data to pass with callback
 *
 * Returns the new FD, or -1 on error.
 *
 */

int
ast_nbio_listen_tcp(struct sockaddr_in * addr, int flags, const char * desc, nbio_connection_cb_t callback, void * user_data);


nbio_socket_t *
ast_nbio_incoming(int fd, int flags, nbio_eventset_incoming_t * cbs, void * user_data);


#endif /* ASTERISK_NBIO_H */
