#ifndef _BSSTREAM_H
#define _BSSTREAM_H

#include <vector>
#include <list>

namespace text_tools {

using namespace std;

class bstringstream {
   vector< char > buffer;

   void cpy(char * ptr, size_t size) {
      for(size_t i = 0; i < size; i++, ptr++) {
         buffer.push_back(*ptr); 
      } 
   }

   void read(char * ptr, size_t size) {
      for(size_t i = 0; i < size; i++, ptr++) {
         *ptr = buffer[0];
         buffer.erase(buffer.begin());
      } 
   }

public:
   bstringstream() {
   }

   bstringstream(const bstringstream & cp) {
      buffer = cp.buffer;
   }

   bstringstream(char * buffer, size_t sz) {
      cpy(buffer, sz);
   }

   ~bstringstream() {
       buffer.clear();
   }

   bstringstream & operator=(const bstringstream & cp) {
      buffer = cp.buffer;
      return *this;
   }

   size_t size() const {
      return buffer.size();
   }

   vector< char > & get_data() {
       return buffer;
   }

   char * get_new_buffer() const {
      char * ret = new char [ buffer.size() ];
      char * p = ret;
      
      for(vector< char >::const_iterator ptr = buffer.begin(); ptr != buffer.end(); ptr++, p++) {
         *p = *ptr;
      }
      
      return ret;
   }

   bstringstream & operator<<(const long l) {
      char * ptr = (char*)&l;
      cpy(ptr, sizeof(long));
      return *this;
   }

   bstringstream & operator<<(const int l) {
      char * ptr = (char*)&l;
      cpy(ptr, sizeof(int));
      return *this;
   }

   bstringstream & operator<<(const float l) {
      char * ptr = (char*)&l;
      cpy(ptr, sizeof(float));
      return *this;
   }

   bstringstream & operator<<(const double l) {
      char * ptr = (char*)&l;
      cpy(ptr, sizeof(double));
      return *this;
   }

   bstringstream & operator<<(const short l) {
      char * ptr = (char*)&l;
      cpy(ptr, sizeof(short));
      return *this;
   }

   bstringstream & operator<<(const char l) {
      char * ptr = (char*)&l;
      cpy(ptr, sizeof(char));
      return *this;
   }

   bstringstream & operator<<(const unsigned long l) {
      char * ptr = (char*)&l;
      cpy(ptr, sizeof(unsigned long));
      return *this;
   }

   bstringstream & operator<<(const unsigned int l) {
      char * ptr = (char*)&l;
      cpy(ptr, sizeof(unsigned int));
      return *this;
   }

   bstringstream & operator<<(const unsigned short l) {
      char * ptr = (char*)&l;
      cpy(ptr, sizeof(unsigned short));
      return *this;
   }

   bstringstream & operator<<(const unsigned char l) {
      char * ptr = (char*)&l;
      cpy(ptr, sizeof(unsigned char));
      return *this;
   }

   bstringstream & operator<<(const bool l) {
      char * ptr = (char*)&l;
      cpy(ptr, sizeof(bool));
      return *this;
   }

   bstringstream & operator<<(const string & l) {
      size_t sz = l.size() + 1;
      char * ptr = (char*)&sz;
      cpy(ptr, sizeof(size_t));
      cpy((char*)l.c_str(), l.size());
      char ch[1] = { '\0' };
      cpy(ch, 1);
      return *this;
   }

   bstringstream & operator>>(string & str) {
      size_t sz = 0U;
      read((char*)&sz, sizeof(size_t));
      char * buffer = new char[sz];
      read(buffer, sz);
      str = buffer;
      delete [] buffer;
      return *this;
   }

   bstringstream & operator>>(const unsigned int & ival) {
      read((char*)&ival, sizeof(unsigned int));
      return *this;
   }

   bstringstream & operator>>(const int & ival) {
      read((char*)&ival, sizeof(int));
      return *this;
   }

   bstringstream & operator>>(const unsigned long int & ival) {
      read((char*)&ival, sizeof(unsigned long int));
      return *this;
   }

   bstringstream & operator>>(const long int & ival) {
      read((char*)&ival, sizeof(long int));
      return *this;
   }

   template< class T_ostream >
   void write(T_ostream & out) {
      vector< char >::iterator ptr = buffer.begin();
      for(register size_t index = 0; index < buffer.size(); index++, ptr++) {
         out << *ptr;
      }
   }

   template< class T_stream >
   void load(T_stream & in, const size_t sz) {
      char * buf = new char[sz];
      in.read(buf, sz);
      cpy(buf, sz);
      delete [] buf;
   }
};

}

#endif /* _BSSTREAM_H */
