/* StringRingbuffer.cpp  -- with string objects */
#include <iostream>
#include <string>
using namespace std;


class StringRingbuffer {
  static const int len = 5;

  string sa[len];                // string array
  int inx;                       // input index
  int outx;                      // output index
  int entries;                   // number of current entries
public:
  StringRingbuffer();
  void reset();                  // empty buffer
  bool isEmpty() const;          // answer whether buffer is empty
  bool isFull() const;           // answer whether buffer is full
  bool in(const string& str);    // input string and answer if successful
  const string out();            // output string or ""-string if empty
  void print() const;            // print state of ringbuffer
};




inline StringRingbuffer::StringRingbuffer() : inx(0), outx(0), entries(0) { }


inline void StringRingbuffer::reset() {
  inx = outx = entries = 0;
}


inline bool StringRingbuffer::isEmpty() const {
  return entries == 0;
}


inline bool StringRingbuffer::isFull() const {
  return entries == len;
}


inline bool StringRingbuffer::in(const string& str) {
  if (!isFull()) {
    sa[inx] = string(str);
    inx = (inx + 1) % len;
    entries++;
    return true;
  }
  return false;
}


inline const string StringRingbuffer::out() {
  if (!isEmpty()) {
    int toutx = outx;
    outx = (outx + 1) % len;
    entries--;
    return sa[toutx];
  }
  return "<null>";
}


void StringRingbuffer::print() const {
  cout << "inx =     " << inx << endl;
  cout << "outx =    " << outx << endl;
  cout << "entries = " << entries << endl;

  for (int i = outx; i < outx + entries; ++i) {
    cout << i % len << ": " << sa[i % len] << endl;
  }
}




void inoutTest() {
  cout << "START" << endl;
  StringRingbuffer rb;
  rb.print();

  const string sa[] = {
    "00000000000",
    "1111111111",
    "222222222",
    "33333333",
    "4444444",
    "555555",
    "66666",
    "7777",
    "888",
    "99",
  };


  for (int i = 0; i < 7; ++i) {
    cout << endl << "IN" << endl;
    rb.in(sa[i]);
    rb.print();
  }

  cout << endl << "OUT" << endl;
  rb.out();
  rb.print();

  cout  << endl<< "IN" << endl;
  rb.in(sa[9]);
  rb.print();

  cout << endl << "OUT" << endl;
  rb.out();
  rb.print();

  cout << endl << "IN" << endl;
  rb.in(sa[8]);
  rb.print();


  cout << endl << "RESET" << endl;
  rb.reset();
  rb.print();
}



void assignTest() {
  StringRingbuffer rb2, rb3;
  {
    StringRingbuffer rb1;
    rb1.in("00000");
    rb1.in("11111");
    rb1.in("22222");

    rb2 = rb1;
    rb3 = rb1;
  }

  cout << endl << "COPY RB2" << endl;
  rb2.print();

  cout << endl << "COPY RB3" << endl;
  rb3.print();

  cout << endl << "OUT RB2" << endl;
  rb2.out();
  rb2.print();

  cout << endl << "RB2" << endl;
  rb2.print();

  cout << endl << "RB3" << endl;
  rb3.print();
}



void copyTest() {
  StringRingbuffer rb1;

  rb1.in("00000");
  rb1.in("11111");
  rb1.in("22222");
  rb1.out();
  rb1.out();
  rb1.in("33333");
  rb1.in("44444");
  rb1.in("55555");

  cout << endl << "RB1" << endl;
  rb1.print();

  StringRingbuffer rb2(rb1);
  cout << endl << "RB2" << endl;
  rb2.print();
}



void heapTest() {
  StringRingbuffer *rbp1;
  rbp1 = new StringRingbuffer;

  rbp1->in("00000");
  rbp1->in("11111");
  rbp1->in("22222");
  rbp1->out();
  rbp1->out();
  rbp1->in("33333");
  rbp1->in("44444");
  rbp1->in("55555");

  cout << endl << "RB1" << endl;
  rbp1->print();


  StringRingbuffer *rbp2 = new StringRingbuffer(*rbp1);

  cout << endl << "RB2" << endl;
  rbp2->print();

  cout << endl << "OUT RB1" << endl;
  rbp1->out();
  rbp1->print();

  cout << endl << "RB2" << endl;
  rbp2->print();
}





int main() {
  inoutTest();
  assignTest();
  copyTest();
  heapTest();

  return 0;
}

