// $Id: ChunkedIO.h,v 1.3 2003/09/03 05:56:50 vern Exp $
//
// Implements non-blocking chunk-wise I/O.

#ifndef CHUNKEDIO_H
#define CHUNKEDIO_H

#include "config.h"
#include "List.h"
#include "util.h"

// Abstract base class.
class ChunkedIO {
public:
	ChunkedIO()	{ pure = false; }
	virtual ~ChunkedIO()	{ }

	typedef struct {
		char* data;
		uint32 len;
	} Chunk;

	// Tries to read the next chunk of data. If it can be read completely,
	// a pointer to it is returned in 'chunk' (ownership of chunk is passed).
	// If not, 'chunk' is set to nil. Returns false if any I/O error occured
	// (use Eof() to see if it's an end-of-file). If 'mayblock' is true, we
	// explicitly allow blocking.
	virtual bool Read(Chunk** chunk, bool mayblock = false) = 0;

	// Puts the chunk into the write queue and writes as much data
	// as possible (takes ownership of chunk).
	// Returns false on any I/O error.
	virtual bool Write(Chunk* chunk) = 0;

	// Tries to write as much as currently possible.
	// Returns false on any I/O error.
	virtual bool Flush() = 0;

	// If an I/O error has been encountered, returns a string describing it.
	virtual const char* Error() = 0;

	// Return true if there is currently at least of chunk available
	// for reading.
	virtual bool CanRead() = 0;

	// Returns true,if end-of-file has been reached.
	virtual bool Eof() = 0;

	// Returns underlying fd if available, -1 otherwise.
	virtual int Fd()	{ return -1; };

	// Makes sure that no additional protocol data is written into
	// the output stream.  If this is activated, the output cannot
	// be read again by any of these classes!
	void MakePure()	{ pure = true; }
	bool IsPure()	{ return pure; }

private:
	bool pure;
};


// Chunked I/O using a socket.

class ChunkedIOFd : public ChunkedIO {
public:
	// Argument is an open bi-directional socket.
	ChunkedIOFd(int fd);
	virtual ~ChunkedIOFd();

	virtual bool Read(Chunk** chunk, bool mayblock = false);
	virtual bool Write(Chunk* chunk);
	virtual bool Flush();
	virtual const char* Error();
	virtual bool CanRead();
	virtual bool Eof()	{ return eof; }
	virtual int Fd()	{ return fd; }

private:
	bool ReadChunk(Chunk* chunk, bool* all);

	int fd;
	bool eof;

	declare(PList, Chunk);
	typedef PList(Chunk) chunk_list;

	// Robin, please comment these.
	Chunk* lchunk;	// chunk containing the length of the data
	Chunk* dchunk;	// chunk containing the data itself

	uint32 readpos;
	uint32 writepos;

	chunk_list towrite;
};

#endif
