// Project 1
// CS2604 : Data Structures
// Hussein Suleman
// 10 July 1999

// ---------------------------------------------------------------------

#include <iostream.h>

#define MAXBUFFER 16

// ---------------------------------------------------------------------

// class KeyboardBuffer that implements a buffer in the form of
// an array-based circular queue with insertion and removal.

class KeyboardBuffer
{
private:
   unsigned char Buffer[MAXBUFFER];  // array to store keystrokes
   unsigned int Head;                // position of next keystroke to enter 
   unsigned int Tail;                // position to retrieve next keystroke
   unsigned int Empty;               // flag to check if buffer is empty
   unsigned int ErrorValue;          // error in last operation
public:
   KeyboardBuffer ();
   void Enter ( unsigned char aKey );
   unsigned char Retrieve ();
   int Error ();
};

// constructor - initialize pointers and error values

KeyboardBuffer::KeyboardBuffer ()
{
   Empty = 1;
   Head = 0;
   Tail = 0;
   ErrorValue = 0;
}

// enter a keystroke into the buffer

void KeyboardBuffer::Enter ( unsigned char aKey )
{
   if ((Head == Tail) && (Empty == 0))  // check if buffer is full
      ErrorValue = 1;
   else
   {
      ErrorValue = 0;
      Buffer[Tail] = aKey;              // add new keystroke
      Tail++;                           // move tail pointer
      if (Tail == MAXBUFFER)            // and wrap around if necessary
         Tail = 0;
      if (Head == Tail)                 // set full/empty status
         Empty = 0;
   }
}

// retrieve a keystroke from the buffer

unsigned char KeyboardBuffer::Retrieve ()
{
   unsigned char RetValue = 65;         // default value to return
   if ((Head == Tail) && (Empty == 1))  // check if buffer is empty
      ErrorValue = 2;
   else
   {
      ErrorValue = 0;
      RetValue = Buffer[Head];          // get keystroke from buffer
      Head++;                           // move head pointer
      if (Head == MAXBUFFER)            // and wrap around if necessary
         Head = 0;
      if (Head == Tail)                 // set full/empty status
         Empty = 1;
   }
   return RetValue;
}

// return error value of last operation

int KeyboardBuffer::Error ()
{
   return ErrorValue;
}

// ---------------------------------------------------------------------

char *ErrorMsg[] = {"", "Error : overflow\n", "Error : underflow\n"};

// main program body to test keyboard buffer

int main ()
{
   KeyboardBuffer kb;
   char i;

   // check that enter and retrieve work
   cout << "Test 1 : 26 alternating enters/retrieves\n";
   for ( i='a'; i<='z'; i++ )
   {
      cout << "Entering : " << i << "\n";
      kb.Enter (i);
      cout << ErrorMsg[kb.Error ()];
      cout << "Retrieving : " << kb.Retrieve () << "\n";
      cout << ErrorMsg[kb.Error ()];
   }   
   cout << "\n\n";

   // check that overflow works
   cout << "Test 2 : 26 enters - overflow\n";
   for ( i='a'; i<='z'; i++ )
   {
      cout << "Entering : " << i << "\n";
      kb.Enter (i);
      cout << ErrorMsg[kb.Error ()];
   }
   cout << "\n\n";
   
   // check that underflow works
   cout << "Test 3 : 26 retrieves - underflow\n";
   for ( i='a'; i<='z'; i++ )
   {
      cout << "Retrieving : " << kb.Retrieve () << "\n";
      cout << ErrorMsg[kb.Error ()];
   }
   cout << "\n\n";
}