#include <iostream>
#include <list>
#include <memory>

using namespace std;

class Base {
  public:
  virtual void f() { cout << "Base f() called" << endl; };
};

class Derived : public Base {
  public:
  void f() { cout << "Derived f() called" << endl; };
};

////////
class animal{
  public:
  virtual void scream()=0;
  virtual int weight()=0;
  virtual ~animal() {}
};

class dog : public animal{
  int w;

  public:
  
  dog(int weight) : w(weight) {}

  void scream(){cout<<"ouf" << endl;}

  int weight(){
    return w;
  }

  ~dog() { cout << "Dog is going away" << endl; }
};

class pig : public animal{
  public:
  void scream(){
    cout << "oink" << endl;
  }

  int weight(){
    return 100;
  }

  ~pig() { cout << "Pig is going away" << endl; }
};

class kangaroo : public animal{
  unique_ptr<animal> pocket;
  
  public:

  void scream(){
    cout << " pocket scream " << endl;
    pocket->scream();
    cout << " --- pocket scream --- " << endl;
    cout << "kangaroo" << endl;
  }

  int weight() {
    return pocket->weight() + 50;
  }

  kangaroo(unique_ptr<animal> &&a) : pocket(move(a)) {}
};

class farmhouse : public animal {

  public:
  std::list<unique_ptr<animal>> animals;

  void scream() {
    cout << "House sounds:" << endl;
    for(auto& a : animals) a->scream();
    cout << "House sounds end" << endl; 
  }

  int weight() {
    int total = 0;
    for(auto& a : animals) total += a->weight();
    return total;
  }

  farmhouse(std::list<unique_ptr<animal>> &&a) : animals(move(a)) {}
};

int main() { //make_unique<T> (...)
  std::list<unique_ptr<animal> > farm;
  farm.push_back(make_unique<pig>());
  farm.push_back(make_unique<dog>(20));
  farm.push_back(make_unique<dog>(80));
  //unique_ptr<animal> a=make_unique<pig>();
  //farm.push_back(make_unique<kangaroo>(a));
  farm.push_back(make_unique<kangaroo>(make_unique<dog>(10)));

  {
    std::list<unique_ptr<animal> > contents;
    contents.push_back(make_unique<dog>(10));
    contents.push_back(make_unique<pig>());
    farm.push_back(make_unique<farmhouse>(move(contents)));
  }

  ///
  
  dynamic_cast<farmhouse*>(farm.back().get())
    ->animals.push_back(make_unique<dog>(123));
  
  int sum=0;
  for (auto &a : farm){
    sum+=a->weight();
  }
  cout << "total weight: "<<sum<<endl;
  for (auto &a : farm)
    a->scream();
}

///////
int main2() {
  Base b;
  Derived d;

  Base *p;
  p = &d;

  p->f();

  b.f();
  d.f();

  std::cout << sizeof(Base) << std::endl;
  return 0;
}
