#ifndef TOOLS_BUFFER_H
#define TOOLS_BUFFER_H

#include "tools.h"
#include "cqueue.h"
#include "cfileno.h"

struct cBufferData {
	size_t m_Size;
	size_t m_Offset;
	bool   m_Filling;

	static cBufferData *Construct(size_t Size);

	operator char * () { return (char*)(this + 1) + m_Offset; }
	size_t Available(void) const { return m_Size - m_Offset; }

	cBufferData &operator += (size_t Bytes) { m_Offset += Bytes; return *this;}
};

class cBuffer: protected cQueue<cBufferData*> {
private:
	size_t m_BlockSize;
	uint   m_MaxCount;
	bool   m_MayRead;
	bool   m_MayWrite;

	uint   m_MaxUsed;

public:
	cBuffer(size_t BlockSize, uint MaxCount, bool Input = true);
	virtual ~cBuffer();

	friend cTBFileNo &operator<<(cTBFileNo &dest, cBuffer &src);
	friend cTBFileNo &operator>>(cTBFileNo &dest, cBuffer &src);

	bool Put(const char *Data, size_t Length);
	const char *Get(void) const { return isEmpty() ? NULL 
			: (const char*)*last(); }

	bool HasSpace(void) const;
	bool HasData(void) const;

	bool MayRead(void) const { return m_MayRead; }
	bool MayWrite(void) const { return m_MayWrite; }

	void Commit(void);

	uint MaxUsed(void) const { return m_MaxUsed; }
};

inline bool cBuffer::HasSpace(void) const {
	if (!m_MayRead) 
		return false;

	if (isEmpty())
		return true;

	return (first()->m_Filling || count() < m_MaxCount);
}

inline bool cBuffer::HasData(void) const {
	if (!m_MayWrite)
		return false;

	if (isEmpty())
		return false;

	return !last()->m_Filling;
}

#endif // TOOLS_BUFFER_H
