// ==========================================================================
// $Id: stack.cpp,v 1.1 2016/11/02 18:13:25 jlang Exp $
// CSI2372 example Code for lecture 7
// ==========================================================================
// (C)opyright:
//
//   Jochen Lang
//   SITE, University of Ottawa
//   800 King Edward Ave.
//   Ottawa, On., K1N 6N5
//   Canada. 
//   http://www.site.uottawa.ca
// 
// Creator: jlang (Jochen Lang)
// Email:   jlang@site.uottawa.ca
// ==========================================================================
// $Log: stack.cpp,v $
// Revision 1.1  2016/11/02 18:13:25  jlang
// Added stack example for copy control
//
// ==========================================================================

#include <iostream>
#include <string>

using std::string;
using std::cout;
using std::cerr;
using std::endl;


#define OWN_COPY
#define OWN_ASSIGN


class Stack {
  int d_capacity;
  int d_size;
  string* d_stack;
public:
  Stack( int _capacity = 10 ) : d_capacity(_capacity), d_size(0) {
    d_stack = new string[d_capacity];
  }
#ifdef OWN_COPY
  // Copy Constructor with pointer member
  Stack( const Stack& oS ) : d_capacity(oS.d_capacity), d_size(oS.d_size) {
    cout << "Copy ctor!" << endl;
    d_stack = new string[d_capacity];
    for ( int i=0; i<d_size; ++i ) {
      d_stack[i] = oS.d_stack[i];
    }
  }
#endif

  // Destructor with pointer member
  ~Stack() {
    cout << "dtor!" << endl;
    delete [] d_stack;
  }
  
#ifdef OWN_ASSIGN
  // Assignment operator with pointer member
  Stack& operator=( const Stack& oS ) {
    cout << "Assignment operator!" << endl;
    // Check for self-assignment
    if ( this != &oS ) {
      delete [] d_stack;
      d_size = oS.d_size;
      d_capacity = oS.d_capacity;
      d_stack = new string[d_capacity];
      for ( int i=0; i<d_size; ++i ) {
	d_stack[i] = oS.d_stack[i];
      }
    }
    return *this;
  }
#endif
 
  Stack& push( const string& s);
  string pop();
  string top() const;

  void print() const;
};

Stack& Stack::push( const string& s) {
  if ( d_size >= d_capacity ) throw string("Stack is full!");
  d_stack[d_size] = s;
  ++d_size;
  return *this;
}

string Stack::pop() {
  if ( d_size == 0 ) throw string("Stack is empty!");
  --d_size;
  return d_stack[d_size];
}

string Stack::top() const {
  if ( d_size == 0 ) throw string("Stack is empty!");
  return d_stack[d_size-1];
}

void Stack::print() const {
  for (int i=0; i<d_size; ++i)
    cout << d_stack[i] << ", ";
  cout << endl;
  return;
}


Stack& transfer( Stack& dst, const Stack& src ) {
  try { 
    for (;;) {
      dst.push(src.top());
    }
  } catch (string s) {
    cerr << s << endl;
  }
  return dst;
}


int main() {
  Stack stA, stB(15);
  for (int i=0; i<5; ++i) {
    stA.push("A");
  }
  stA.print();
  for (int i=0; i<11; ++i) {
    stB.push("B");
  }
  stB.print();
  cout << "------------------" << endl;
  Stack stC(stA);
  stA.push("aa");
  stA.print();
  stC.print();
  cout << "------------------" << endl;
  stA = stB;
  stA.print();
  cout << "------------------" << endl;
  stB.push("bb");
  stA.print();
  stB.print();
  cout << "------------------" << endl;
  stC = transfer(stA,stB);
  stA.pop(); stA.push("aa");
  stA.print();
  stB.print();
  stC.print();
  return 0;
}
