// Purpose.  Bridge design pattern lab
//
// Problem.  Our Stack class needs to allow the client to specify at
// run-time what implementation strategy to employ (i.e. list vs array).
//
// Assignment.
// o Rename the current Stack class to ArrayImp
// o Create a base class called StackImp
// o StackImp is a "pure abstract base class".  It should declare 4 pure
//   virtual functions: push(), pop(), isEmpty(), and isFull()
// o Derive classes ArrayImp and ListImp from class StackImp
// o Create an interface (or wrapper, or handle) class called Stack
// o The class Stack should contain a pointer to the abstract base class
//   StackImp.
// o To initialize the StackImp pointer, Stack needs a constructor that
//   accepts one argument of type ImplementationType.  In the body, you
//   create an instance of the derived class requested.  If the client does
//   not supply an argument for the constructor, provide a default argument
//   of ArrayImplementation.
// o Don't forget to write a destructor to clean-up the StackImp pointer
// o The class Stack should have a method for anything a client might want to
//   do to a Stack object.  Each method simply forwards the client request to
//   the appropriate method in its StackImp object.
// o Un-comment the code in main() and test your results

#include <iostream.h>
enum ImplementationType { ArrayImplementation, ListImplementation };


class Stack {
public:
   Stack( int = 10 );
   ~Stack();
   void push( int val );
   int  pop();
   int  isEmpty();
   int  isFull();
private:
   int* _array;
   int  _sp;
   int  _size;
};


class Node {
public:
   Node( int val, Node* next );
   int getValue();
   Node* getNext();
private:
   int    _value;
   Node*  _next;
};

class ListImp {
public:
    ListImp();
    ~ListImp();
    void push( int val );
    int  pop();
    int  isEmpty();
    int  isFull();
private:
    Node* _head;
};

void main ( void ) {
   Stack stack1;
   // Stack stack2( ListImplementation );

   for (int i=1; i < 16; i++) {
      stack1.push( i );
      // stack2.push( i );
   }

   cout << "Array stack: ";
   for (i=1; i < 18 ; i++)
      cout << stack1.pop() << "  ";
   cout << endl;

   // cout << "List stack:  ";
   // for (i=1; i < 18 ; i++)
   //    cout << stack2.pop() << "  ";
   // cout << endl;
}

// Array stack: 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0 
// List stack:  15  14  13  12  11  10  9  8  7  6  5  4  3  2  1  0  0 


Stack::Stack( int size ) {
   _array = new int[size];
   _size = size;
   _sp = 0; }
Stack::~Stack() { delete _array; }
void Stack::push( int val ) {
   if ( ! isFull())
      _array[_sp++] = val; }
int Stack::pop() {
   if (isEmpty()) return 0;
   else return _array[--_sp]; }
int Stack::isEmpty() { return _sp == 0 ? 1 : 0; }
int Stack::isFull()  { return _sp == _size ? 1 : 0; }

Node::Node( int val, Node* next ) {
   _value = val;
   _next = next; }
int   Node::getValue() { return _value; }
Node* Node::getNext()  { return _next; }

ListImp::ListImp() { _head = NULL; }
ListImp::~ListImp() {
   Node  *current, *previous;
   current = _head;
   while (current) {
      previous = current;
      current = current->getNext();
      delete previous; }
}
void ListImp::push( int val ) {
   Node*  temp = new Node( val, _head );
   _head = temp; }
int ListImp::pop() {
   if (isEmpty()) return 0;
   Node*  temp = _head;
   int    val  = _head->getValue();
   _head = _head->getNext();
   delete temp;
   return val; }
int ListImp::isEmpty() { return _head ? 0 : 1; }
int ListImp::isFull()  { return 0; }