//: C16:Recycle.cpp
// Containers & polymorphism
#include "TStack.h"
#include <fstream>
#include <cstdlib>
#include <ctime>
using namespace std;
ofstream out("recycle.out");
enum TrashType { AluminumT, PaperT, GlassT };
class Trash {
  float _weight;
public:
  Trash(float wt) : _weight(wt) {}
  virtual TrashType trashType() const = 0;
  virtual const char* name() const = 0;
  virtual float value() const = 0;
  float weight() const { return _weight; }
  virtual ~Trash() {}
};
class Aluminum : public Trash {
  static float val;
public:
  Aluminum(float wt) : Trash(wt) {}
  TrashType trashType() const { return AluminumT; }
  virtual const char* name() const {
    return "Aluminum";
  }
  float value() const { return val; }
  static void value(int newval) {
    val = newval;
  }
};
float Aluminum::val = 1.67;
class Paper : public Trash {
  static float val;
public:
  Paper(float wt) : Trash(wt) {}
  TrashType trashType() const { return PaperT; }
  virtual const char* name() const {
    return "Paper";
  }
  float value() const { return val; }
  static void value(int newval) {
    val = newval;
  }
};
float Paper::val = 0.10;
class Glass : public Trash {
  static float val;
public:
  Glass(float wt) : Trash(wt) {}
  TrashType trashType() const { return GlassT; }
  virtual const char* name() const {
    return "Glass";
  }
  float value() const { return val; }
  static void value(int newval) {
    val = newval;
  }
};
float Glass::val = 0.23;
// Sums up the value of the Trash in a bin:
void sumValue(const TStack<Trash>& bin,ostream& os){
  TStackIterator<Trash> tally(bin);
  float val = 0;
  while(tally) {
    val += tally->weight() * tally->value();
    os << "weight of " << tally->name()
        << " = " << tally->weight() << endl;
    tally++;
  }
  os << "Total value = " << val << endl;
}
int main() {
  srand(time(0)); // Seed random number generator
  TStack<Trash> bin; // Default to ownership
  // Fill up the Trash bin:
  for(int i = 0; i < 30; i++)
    switch(rand() % 3) {
      case 0 :
        bin.push(new Aluminum(rand() % 100));
        break;
      case 1 :
        bin.push(new Paper(rand() % 100));
        break;
      case 2 :
        bin.push(new Glass(rand() % 100));
        break;
    }
  // Bins to sort into:
  TStack<Trash> glassBin(0); // No ownership
  TStack<Trash> paperBin(0);
  TStack<Trash> alBin(0);
  TStackIterator<Trash> sorter(bin);
  // Sort the Trash:
  // (RTTI offers a nicer solution)
  while(sorter) {
    // Smart pointer call:
    switch(sorter->trashType()) {
      case AluminumT:
        alBin.push(sorter.current());
        break;
      case PaperT:
        paperBin.push(sorter.current());
        break;
      case GlassT:
        glassBin.push(sorter.current());
        break;
    }
    sorter++;
  }
  sumValue(alBin, out);
  sumValue(paperBin, out);
  sumValue(glassBin, out);
  sumValue(bin, out);