// FIFO buffer implementation.

#include "buffer.h"

// Constructor; for default construct, value of capacity is 100.
// Note that the buffer can only actually hold capacity-1 items,
// due to the way that a full buffer is detected.
buffer::buffer(unsigned capacity)
{
  buf = new int [capacity];
  head = tail = 0;
  last = capacity - 1;
}

// Add new item to buffer at the end of the queue.
// Note that if the buffer is full we silently ignore the request.
void buffer::add(int x)
{
  if (!isfull())
  {
    buf[tail] = x;
    increment(tail);
  }
}
    
// Get but don't remove next item from buffer.
// If nothing in the buffer, return -1.
int buffer::peek()
{
  int x = -1;
  if (!isempty())
    x = buf[head];
  return x;
}      

// Get and remove next item from buffer.
// If nothing in the buffer, return -1.
int buffer::remove()
{
  int x = -1;
  if (!isempty())
  {
    x = buf[head];
    increment(head);
  }
  return x;
}      

// Count the number of items in the buffer.
unsigned buffer::size()
{
  unsigned count = 0;
  int i = head;
  while (i != tail)
  {
    ++count;
    increment(i);
  }
  return count;
}

// Increment an index into the buffer modulo its length
// (i.e., "wrapping around" the end of the array back to the begining).
void buffer::increment(int & i) 
{       
  if (i == last)
    i = 0;
  else
    ++i;
}

// Check if anything is in the buffer.
// The buffer is empty when the head and tail indexes are the same.
bool buffer::isempty() 
{ 
  return head == tail; 
}

// Check if there is any room left in the buffer for new items.
// The buffer is full if the head index is one more than the tail index.
bool buffer::isfull() 
{ 
  int i = tail;
  increment(i);
  return head == i; 
}

// Overload the assignment operator to copy the data storage area (buf) contents,
// rather than the default of just copying the pointer itself.
// If the capacity of the buffer being assigned to is smaller than that being
// assigned from, any extra items are silently discarded.
buffer & buffer::operator=(buffer & b)
{
  if (this != &b)        // Make sure we are not assigning b = b.
  {
    head = tail = b.head;
	while (tail != b.tail && !isfull())
	{
      buf[tail] = b.buf[tail];
	  increment(tail);
	}
  }
  return *this;
}
