// Common, group Buffers
// Copyright Alexander Liss

#ifndef __COMMBUF_H__
#define __COMMBUF_H__


	// ReadControl

	// limit zero - no limit
	// offset zero - read from write_start()
	// last_bits - bits to read in last byte (for crypto)

struct ReadControl
{ 
	int offset, limit, last_bits; 

ReadControl():offset(0),limit(0),last_bits(8){}
void reset(){offset=limit=0;last_bits=8;}
void move(int n){offset+=n;}
int check()const
{if(offset<0 || limit<0 || last_bits<0 || last_bits>8) return 1; return 0;}
};


	// CommBuffer

	// an array of bytes (unsigned char) with a write-offset for headers
	// can be interpreted as a string if needed:
	//  data==0 or start()[data_size]==0 
	//  back_allocated() >= data_size+1 
	// encoding types are in encoding.h

class CommBuffer
{
public:

	int data_size, allocated, write_offset, encoding;
	unsigned char * data;

CommBuffer(int Increment=128):
	increment(Increment),data_size(0),allocated(0),write_offset(0),encoding(0),data(0)
	{allocate(increment);}
CommBuffer(const char * from,int size):
	increment(128),data_size(0),allocated(0),write_offset(0),encoding(0),data(0)
	{set(from,size);}
CommBuffer(const CommBuffer& s):
	increment(s.increment),data_size(0),allocated(0),data(0)
	{ if(s.data){allocate(s.allocated); copy(s);}}
~CommBuffer();
CommBuffer& operator=(const CommBuffer& s)
{ if(&s != this){if(!data) allocate(s.allocated); copy(s);}; return *this;}

int front_allocated()const
	{return write_offset;}
int back_allocated()const
	{return allocated-write_offset;}
int space_left()const
	{ int r=allocated-write_offset-data_size;return r>=0?r:0;}
int data_left(const ReadControl& c)const
	{ return data_size-c.offset;}
int check(const ReadControl& c)const
	{ if(c.check()) return 1; if(data_left(c)<0) return 2;	return 0;}

unsigned char * write_start()const
	{return data+write_offset;}
unsigned char * read_start(const ReadControl& c)const
	{ return write_start()+c.offset;}

int reset(){ data_size=write_offset=0; return 0;}

int reallocate(int new_size);

	// set functions override old data
int set(const CommBuffer& s,ReadControl& c)
	{ return set(s.read_start(c),s.data_left(c));}
int set(const char * string);
int set(const unsigned char * from,int size);
int set(const char * from,int size)
	{return set((unsigned char *)from,size);}
int set(int number, char symbol);

	// append functions add data to old data
int append(const CommBuffer& s,ReadControl& c)
	{return append(s.read_start(c),s.data_left(c));}
int append(const char * string);
int append(const unsigned char * from,int size);
int append(const char * from,int size)
	{return append ((unsigned char *)from,size);}
int append(int number, char symbol);

	// prepend functions add data in front of existing data
int prepend(const CommBuffer& s,ReadControl& c)
	{return prepend(s.read_start(c),s.data_left(c));}
int prepend(const unsigned char * from,int size);
int prepend(const char * from,int size)
	{return prepend((unsigned char *)from,size);}
int prepend(int number, char symbol);

// a byte data[n+write_offset] becomes data[write_offset], drops first written n bytes
int shift(int n);

private:

	int increment;
	int copy(const CommBuffer& s);
	int allocate(int size);
};

/*
	// inline functions

inline
unsigned char * read_start(const CommBuffer& b,const ReadControl& c)
{ return b.write_start()+c.offset;}

inline
int data_left(const CommBuffer& b,const ReadControl& c)
{ return b.data_size-c.offset;}

inline
int space_left(const CommBuffer& b)
{  int r=b.allocated-b.write_offset-b.data_size;return r>=0?r:0;}

inline
int check(const CommBuffer& b,const ReadControl& c)
{ if(c.check()) return 1; if(data_left(b,c)<0) return 2;	return 0;}

inline
int set(CommBuffer& d,const CommBuffer& s,ReadControl& c)
{ return d.set(read_start(s,c),data_left(s,c));}

inline
int append(CommBuffer& d,const CommBuffer& s,ReadControl& c)
{return d.append(read_start(s,c),data_left(s,c));}
*/

#endif