// File "ListTest.cc".  C++ translation of ListTest.java, by KWR, Assgt. 1.
// Few comments in this file, so you can compare syntax with the C++ version.
// Study Guide: understand or ask about every "///" comment, and then delete
// them so that the code doesn't keep looking so cluttered.

// Commented-out lines show some optional alternatives.  For features such as
// const and ":" constructor-initializer syntax and "virtual", you get credit
// if you used them *somewhere*, while "explicit" was not on grading scheme.
// Delete all //commented-out lines to see a minimal perfect answer.

#include<string>
#include<vector>
#include<iostream>
#include<typeinfo>   ///needed for "dynamic_cast" translating Java "instanceof"
using namespace std; ///needed for Sun CC but not g++ with default settings

//-------------------------------------------------------------------------
#include <stdio.h>  // for sprintf  (KLUDGE)

string itoa(long int x) {  //Converts [long, short] int to an ANSI string.
   char b[100]; sprintf(b, "%d", x); string s = b; return s;
}
//-------------------------------------------------------------------------

class Foo{
   string fooVal;
 public:
   Foo() : fooVal("Empty") { }   
   explicit Foo(string str) : fooVal(str) { }    ///disables Foo x = "hello";
   Foo(int x) : fooVal(itoa(x)) { }       ///no "explicit" enables Foo x = 5;
   virtual string getFooVal() const { return fooVal; }
   virtual void setFooVal(string newFooVal) { fooVal = newFooVal; }
   virtual string toString() const { return "My fooVal is " + fooVal; }
   //virtual operator const char* () { return fooVal.c_str(); }
}; ///^^^try commenting this in and doing cout << *q->get() << endl below;

class FooList {   
 public:
   class Cell {    ///nested Cell class---syntax is same way as in Java.
    public:
      Foo* info;   ///you would need a ~Cell() destructor to delete this field
      Cell* next;
      explicit Cell(Foo* info) : info(info), next(this) { }
      ///Cell(Foo* inf) : info(inf), next(this) { }             ///also OK.
      Cell(Foo* info, Cell* n) : info(info), next(n) { }
      // virtual ~Cell() { delete(info); } ///we will do "real" data-structure
   }; ///destructors later, using high-level code to empty them, then cleanup.
      ///To Study: "delete(rear);" causes infinite-loop in circle-linked list.
 private:
   Cell* rear;

   ///Note: Java "default" access must == "public" in C++, or use "friend".
   ///(friend will be taught later)
 public:
   FooList()  : rear(new Cell(new Foo(0))) { }
   //virtual ~FooList() { delete(rear); } 
   virtual bool empty() const { return rear == rear->next; }
   virtual void add(Foo* i) {
      rear->info = i;
      rear = rear->next = new Cell(new Foo(0), rear->next);
   }
   virtual void push(Foo* i) {
      rear->next = new Cell(i, rear->next);
   }
   virtual Foo* get() const {   ///To Study: this satisfies the compiler def^n
                                ///of "const" but not the meaningful def^n.
      if( empty() ) return new Foo();
      Cell* front = rear->next;
      rear->next = front->next;            ///unlinks node
      //Foo* temp = new Foo(front->info);
      //delete(front);                     ///really deletes node
      //return temp;
      return front->info;
   }
};

class Queue: public  FooList {
 public:
   Queue() : FooList() { }  ///see note in "Stack"
   //virtual ~Queue()  { }  ///ditto
   virtual Foo* get() const { return FooList::get(); }  
   virtual void put(Foo* x) { add(x); }  ///"FooList::add" AOK but not needed.
};

class Stack: public FooList {
 public:        ///OK to omit call to base-class zero-parameter (aka. "default")
   Stack() { } ///constructor since it is called automatically before the { },
   //virtual ~Stack() { }  ///while base-class destructor is called after { }.
   virtual Foo* pop() { return get(); }  
   virtual void push(Foo* x) { FooList::push(x); }  //See IMPT NOTE below.
};

int main() {
   Stack* s = new Stack();
   Queue* q = new Queue();
   int n = 9;
   for(int i = 1; i <= n; i++) {
      s->push(new Foo(i)); q->put(new Foo(i));
   }
   cout << "Stack\t\tQueue\n";
   for(int i = 1; i <= n; i++) {
      cout << s->pop()->toString() << "\t";
      cout << q->get()->toString() << endl;
      //cout << *(q->get()) << endl; ///only if you enable "operator char*()"
   }
   //delete(s); delete(q);  ///good but not required since program is exiting
}

