
//
// ******** buffer.h  ******************
//
#ifndef BUFFER_H
#define BUFFER_H

#ifndef SYSTEMC_H
#include "systemc.h"
#endif


#define BUFFER_SIZE 10

template <class itemT>
class buffer 
{
public:
  buffer();
  virtual ~buffer() {} 
  itemT get();  // get item from the top of buffer
  bool put(itemT);  // put item at the bottom of buffer
  bool full();	    // buffer full
  bool empty();	    // buffer empty

private:
  int nr_items; // items in buffer
  itemT array[BUFFER_SIZE];
  bool full_bit;
  bool empty_bit;
  void shift_right(void); // shifts items in the buffer to the right

};

template <class itemT>
buffer<itemT>::buffer() {
  // initialize buffer variables
  full_bit=false; // buffer is not full
  empty_bit=true; // buffer is empty
  nr_items = 0;
	for(int i=0; i<BUFFER_SIZE; i++)
		array[i] =0;
}

template <class itemT>
bool buffer<itemT>::full(void) { return full_bit; }

template <class itemT>
bool buffer<itemT>::empty(void) { return empty_bit; }

template <class itemT>
void buffer<itemT>::shift_right(void) 
{
  if (nr_items)
  {
    for (int i=nr_items; i > 0 ; i--) 
	  array[i]=array[i-1];
  }
}

template <class itemT>
itemT buffer<itemT>::get(void) 
{
  itemT item;
  // get item from the top of buffer
  if (empty_bit) 
  {
    // invalid operation
    // throw an exception
    cout << "get() called on an empty buffer" << endl;
    assert(false);
  }
  else 
  {
    itemT item;
    nr_items -= 1;
    item = array[nr_items];
    if (nr_items < 1) empty_bit=true;
    full_bit=false;  // not full
  }
    return item;
 }

template <class itemT>
bool buffer<itemT>::put(itemT item) {
  // put item at the bottom of buffer
  if (full_bit) 
  {
    // invalid operation
    // throw an exception
    cout << "put() called on a full buffer" << endl;
    return false;
  }
  else {
    empty_bit=false;  // not empty
    shift_right();
    array[0] = item;
    nr_items += 1;
    if (nr_items == BUFFER_SIZE) full_bit=true; 
    cout << "  Array after shifting = " ;
    for (int j=0; j<10; j++)
    {
      cout << array[j] <<" " ;
    }
    cout << endl;
    return true;
  }
 }
#endif
