#ifndef PIPE_PIPE_H
#define PIPE_PIPE_H

#include "base/dblock.h"

///@name pipe
//@{

//Pipe catagories
//PCAT_???
//anything above 0 is an "end pipe"
//anthing below 0 is a normal pipe
//0 is undefine
#define PCAT_PIPE	-1	//this is a plain pipe.
#define PCAT_NONE	0	//no pipe/uninitialized
#define PCAT_END	1	//this is an end pipe.

#define PCAT_FACE	-2	//this is a pipe face

#define PCAT_SOCK	2	//this is actaully a socket. don't try and go back any further


#define PSTATUS_NORMAL	0x0000	//default state
//these flags are set on Pipe->status
#define PSTATUS_CLOSED	0x0001	//pipe has been closed
#define PSTATUS_OPENED	0x0002	//pipe has been opened
#define PSTATUS_READY	0x0004	//pipe has been opened
//these flags are returned with Pipe->status when calling pipeStatus (DON'T set Pipe->status with these flags)
#define PSTATUS_READ	0x0010	//pipe has data available that can be read now
#define PSTATUS_WRITE	0x0020	//pipe has data that can be written out now
#define PSTATUS_READX	0x0040	//pipe has data somewhere in the chain but probably can't be read now (maybe after a call to pipeGenericRead)
#define PSTATUS_WRITEX	0x0080	//pipe has data somewhere that wants to be written but can't be (maybe after a call to pipeGenericWrite)


/**
The pipe structure.
todo: document this more
*/
typedef struct Pipe {
	DataBlock *inBuffer;
	DataBlock *outBuffer;
	struct Pipe *backPipe;
	struct Pipe *forwardPipe;	//used to trace a chain of pipes the other direction
//using these forms to declare the functions would be ideal but the 
//functions would refernce "struct Pipe *" before it is defined
	//PipeFuncIn backPipeInFunction;
	//PipeFuncOut backPipeOutFunction;
	//PipeFuncAttach attachFunction;
	//PipeFuncDetach detachFunction;
	//PipeFuncClose closeFunction;
	//PipeFuncStatus statusFunction;
	void  (*backPipeInFunction)(struct Pipe *, struct Pipe **);	//func to call to get data from the backpipe
	void (*backPipeOutFunction)(struct Pipe *, struct Pipe **);	//func to call to put data into the backpipe
	void (*attachFunction)(struct Pipe *);
	void (*detachFunction)(struct Pipe *);
	void (*closeFunction)(struct Pipe *);
	void (*statusFunction)(struct Pipe *, int *);
	int PipeCatagory;
	int status;					//bunch of flags to signal status of the pipe
} Pipe;


//------------------------	--buffers---	-pipe chain-	-----functions---------------------
#define BLANKPIPE_PTR_BITS	NULL, NULL, 	NULL, NULL, 	NULL, NULL, NULL, NULL, NULL, NULL

#define BLANKPIPE_NONE	{BLANKPIPE_PTR_BITS,	PCAT_NONE,	PSTATUS_NORMAL}
#define BLANKPIPE_PIPE	{BLANKPIPE_PTR_BITS,	PCAT_PIPE,	PSTATUS_NORMAL}
#define BLANKPIPE_FACE	{BLANKPIPE_PTR_BITS,	PCAT_FACE,	PSTATUS_NORMAL}
#define BLANKPIPE_END	{BLANKPIPE_PTR_BITS,	PCAT_END,	PSTATUS_NORMAL}
#define BLANKPIPE_SOCK	{BLANKPIPE_PTR_BITS,	PCAT_SOCK,	PSTATUS_NORMAL}


//typedefs used for the casting of functions
/**
InFunc(Pipe *thisPipe, Pipe **errorPipe); <BR>
returns NULL via errorPipe on success or a pointer to the pipe that had an error
//Custom in/out functions must call pipeGenericRead/pipeGenericWrite on thispipe->backpipe
//The in and out function will be called even if backPipe is NULL or 
//PipeCatagory is an "end pipe".
*/
typedef void (*PipeFuncIn)(struct Pipe *, struct Pipe **);
/**
OutFunc(Pipe *thisPipe, Pipe **errorPipe);<BR>
returns NULL via errorPipe on success or a pointer to the pipe that had an error
//Custom in/out functions must call pipeGenericRead/pipeGenericWrite on thispipe->backpipe
//The in and out function will be called even if backPipe is NULL or 
//PipeCatagory is an "end pipe".
*/
typedef void (*PipeFuncOut)(struct Pipe *, struct Pipe **);
/**
//attachFunction(Pipe *thispipe)
//	something has been attached to our forwardpipe
*/
typedef void (*PipeFuncAttach)(struct Pipe *);
/**
//detachFunction(Pipe *thispipe)
//	something will be detached from our forwardpipe
*/
typedef void (*PipeFuncDetach)(struct Pipe *);
/**
//closeFunction(Pipe *thispipe)
//  this chain of pipes is now being formally closed
*/
typedef void (*PipeFuncClose)(struct Pipe *);
/**
//statusFunction(int *status)
//  status will contain the status already taken from the back pipe
//	use this to clear flags that aren't really true.
//	e.g. a crypto pipe that works 1024 byte blocks only will need to clear the PSTATUS_READ flag if the backpipe has less 1024 bytes available
*/
typedef void (*PipeFuncStatus)(struct Pipe *, int *);




void pipeInit(Pipe *pipe);
//todo: changes this over to PipeFunc* typedefs
void pipeInitFunctions(Pipe *pipe,
					   void (*backpipein)(struct Pipe *, struct Pipe **), void (*backpipeout)(struct Pipe *, struct Pipe **), 
					   void (*attach)(struct Pipe *), void (*detach)(struct Pipe *), 
					   void (*closefunc)(struct Pipe *), void (*status)(struct Pipe *, int *));
void pipeFree(Pipe *pipe);

Pipe *pipeGenericRead(Pipe *thispipe);
Pipe *pipeGenericWrite(Pipe *thispipe);

Pipe *pipeRead(Pipe *thispipe, DataBlock **db, int maxlength);
Pipe *pipeWrite(Pipe *thispipe, DataBlock **db, int maxlength);

Pipe *pipeReadString(Pipe *thispipe, char **s);
Pipe *pipeWriteString(Pipe *thispipe, char *s);

Pipe *pipeGetStart(Pipe *pipe);
Pipe *pipeGetEnd(Pipe *pipe);

int pipeAttach(Pipe *oldpipe, Pipe *newpipe);
int pipeDetach(Pipe *pipe);
int pipeClose(Pipe *pipe);

int pipeStatus(Pipe *pipe);


//@}

#endif //PIPE_PIPE_H
