#ifndef __CSINK_H__
#define __CSINK_H__

/* csink.h
 * Author(s): Jim Meier, Cory Stone
 */

/* Headers */
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <glib.h>
#include <errno.h>

#include "cbuf.h"
#include "csinkerr.h"

/* Toplevel code should only check the ->flags member.  Only implementaions
 * that own the csink are alowed to modify that ->flags member.  This
 * will make it so the user code doesn't have to know what kind of csink
 * it is using.
 *
 */


/* The type value for a base csink. */
#define CSINK_TYPE	0xdeadbeef



/* This is not part of glib but it should be. */
void g_ptr_array_add_at_start(GPtrArray *array, gpointer data);

#ifdef ENTITY_EMBED
#include "entity.h"
#define CDEBUG(x) edebug x

#else				/* not ENTITY_EMBED */

/* #include <cdebug.h> */
#include "edebug.h"
#define CDEBUG(x) edebug x

/* Typedefs for mainloop registration. */
typedef enum	/* This looks exactly the same as entity's eio's. */
{
    EIO_READ = 1 << 0,
    EIO_WRITE = 1 << 1,
    EIO_ERROR = 1 << 2
} EIOCond;

typedef int (*EIOFunc) (int fd, EIOCond cond, void *data);
typedef void *(*EIOAddFunc) (int fd, EIOCond cond, EIOFunc, void *data);
typedef void (*EIORemoveFunc) (void *tag);

#endif				/* ENTITY_EMBED */


typedef enum
{
  CSSF_CLOSED		= (0),
  CSSF_TRYING		= (1 << 0),
  CSSF_SHOULD_READ 	= (1 << 1),	/* Not yet, used... */
  CSSF_CAN_WRITE	= (1 << 2),
} CSStatusFlags;

/* Casting macros */
#define CSINK(sink) 		( (CSink*)sink )
typedef struct _CSink CSink;

/* Callback types */
typedef void (*CSinkFreeFunc) (CSink * sink);
typedef void (*CSinkCloseFunc) (CSink * sink);
typedef CBuf *(*CSinkReadFunc) (CSink * sink);
typedef CSink *(*CSinkCreateFunc) (CSink * old_sink);
typedef gint (*CSinkWriteFunc) (CSink * sink, CBuf * data);
typedef void (*CSinkOpenFunc) (CSink * sink);
typedef void (*CSinkCallbackFunc) (CSink * sink);	/* Generic callback. */



struct _CSink {
  int csink_type;		/* The type of csink. */
  CSStatusFlags flags;		/* Top level flags. */

  /* In and out queues both buffer messages up to available memory. */
  GPtrArray *inQueue;		/* Incoming messages, in order. */
  GPtrArray *outQueue;		/* Unsent outgoing messages, in order. */

  int closed;			/* open/closed flag. */
  
  int err;			/* Error flag. Should become status flag. */
  CSink_Error *error_record;	/* The current error. */
  
				/* Some basic method pointers. */
  CSinkReadFunc read;
  CSinkWriteFunc write;
  CSinkOpenFunc open;
  CSinkCloseFunc close;
  CSinkFreeFunc free;
  CSinkCreateFunc create;
  
  CSinkCallbackFunc on_error;		/* Error signalled. */
  CSinkCallbackFunc on_new_data;	/* New data available. */
  CSinkCallbackFunc on_close;		/* Sink connection closed. */
  CSinkCallbackFunc on_connect;		/* Sink connection is active. */
  CSinkCallbackFunc on_empty_send_queue; /* I don't think this is needed. */


  
  gpointer user_data;		/* Associated user data.
				 * Not managed or freed by csink. */

				/* The object system implies delegation. These
				 * two fields provide that structure. */
  CSink *child;			/* Pointer to the wrapped sink. */
  CSink *parent;		/* Pointer to the wrapping sink. */
};



/*===============================*/
  

/* Functions to get and set the user data. */
void *csink_get_user_data (CSink * sink);
void csink_set_user_data (CSink * sink, void *data);

/* Functions to modify the callbacks. */
void csink_set_new_data_func (CSink * sink, CSinkCallbackFunc func);
void csink_set_empty_send_queue_func (CSink * sink, CSinkCallbackFunc func);
void csink_set_error_func (CSink * sink, CSinkCallbackFunc func);
void csink_set_close_func (CSink * sink, CSinkCallbackFunc func);
void csink_set_connect_func (CSink * sink, CSinkCallbackFunc func);

/* Error handling funcs. */
gchar *csink_errstr (CSink * sink);
gint csink_error (CSink * sink);
gchar *csink_errname(CSink *sink);
gchar *csink_errormsg (CSink * sink); /* unimplemented */



/* Initialize and unregister funcs. */
void csink_init (CSink *sink);
void csink_release (CSink *sink);

/* Basic interaction methods. */
void csink_open (CSink * sink);		/* Tries to open a connection. */

CBuf *csink_read (CSink * sink);	/* Read from the sink,
					 * NULL if no message */
gint csink_write (CSink * sink, CBuf * data); /* Write data to the out queue. */

void csink_close (CSink * sink);	/* Close the connection. */
void csink_free (CSink * sink);		/* Free all data associated
					 * with the sink */
CSink * csink_create (CSink * sink);	/* The allocate function. */


/* Information about the buffers. */
gint csink_send_queue_size (CSink * sink); /* in bytes */
gint csink_receive_queue_size (CSink * sink); /* in bytes */

/* Call the associated callbacks and do standard associated actions */
void csink_on_connect (CSink * sink);
void csink_on_new_data (CSink * sink);

/* Set error before calling the on_error func. */
#define csink_on_error(sink, errname) \
        csink_on_error__P (sink, errname, __FILE__, __LINE__)
void csink_on_error__P (CSink * sink, char *errname, 
			char *file, int line);





/*===============================================*/
/* FD Watching interface */
/* CSinks will use whatever functions the user wants to watch activity on
 * fds. Also, a simple polling implementaiton is provided. */

typedef EIOCond CSinkFDCondition;
typedef EIOFunc CSinkFDCallbackFunc;

typedef void *(*CSinkAddFDFunc) (int fd, CSinkFDCondition cond,
			CSinkFDCallbackFunc func, CSink * sink, char * info);
typedef void (*CSinkRemoveFDFunc) (void *tag, char *info);

void csink_init_funcs (CSinkAddFDFunc fd_add_func,
		       CSinkRemoveFDFunc fd_remove_func);
void *csink_add_fd (int fd, CSinkFDCondition cond, CSinkCallbackFunc func,
		    CSink * sink, char * info);
void csink_remove_fd (void * tag, char * info);


/* The polling implementation.  Use csink_set_polling_fd_funcs to set it up, 
 * then call csink_do_poll somewhere in your main loop. */
void csink_set_polling_fd_funcs (void);
void csink_do_poll (void);


/* Add to the queue. */
gint csink_default_write (CSink *sink, CBuf *msg);

/* Sanity checker for write. */
gint csink_write_sanity (CSink * sink, CBuf * message);


#endif



syntax highlighted by Code2HTML, v. 0.9.1