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


using namespace std;

class Animal {
public:
	virtual float weight()=0;
	virtual void make_sound()=0;
};

class Hedgehog : public Animal {
	float weight() {
		return 0.8;
	}

	void make_sound() {
		cout << "Hoghoghog!" << endl;
	}
};

class Elephant : public Animal {
	float weight() {
		return 5000;
	}

	void make_sound() {
		cout << "Toot!" << endl;
	}
};

class Building : public Animal {

public:
	list<unique_ptr<Animal>> animals;

	float weight() {
		float res = 10000.0;
		for (auto &a : animals) {
			res += a->weight();
		}
		return res;
	}

	void make_sound() {
		cout << "listening to a building\n";
		for (auto &a : animals) {
			a->make_sound();
		}
		cout << "stop listening to a building\n";
	}

	size_t elephant_count() {
		size_t count = 0;
		for (auto &a : animals) {
			//if (dynamic_cast<Elephant*>(a.get())) count++;
			count += !!dynamic_cast<Elephant*>(a.get());
			else {
				Building*b;
				if (b = dynamic_cast<Building*>(a.get()))
					count += b->elephant_count();
			}
		}
		return count;
	}
};

unique_ptr<Animal> random_animal() {
	switch (rand() % 2)
	{
		case 0:
			return make_unique<Elephant>();
		case 1:
		default:
			return  make_unique<Hedgehog>();
	}
}


// this is only for testing purposes with unique_ptr
class test {
public:
	int value;

	test(int a) : value(a) {}

	~test() {
		cout << "Deallocated" << endl;
	}
};

int main()
{
#if 1
	Building zoo;

	for(int i=0; i<10;++i) zoo.animals.push_back(random_animal());

	unique_ptr<Building> b;
	b = make_unique<Building>();

	for (int i = 0; i<10; ++i) b->animals.push_back(random_animal());

	zoo.animals.push_back(move(b)); //this removes the ownership of the building

	zoo.make_sound();

	cout << zoo.elephant_count() << endl;

#else
	unique_ptr<test> tp;
	tp = make_unique<test>(5);
#endif


	return 0;
}
