#include <iostream>
#include <string>

class Animal {
protected:
  std::string name;
  int age;

public:
  Animal(std::string n, int a);
  virtual void makeSound();
  virtual void eat();
  virtual void sleep();
  virtual void awake();
};

class Mammal : protected Animal {
protected:
  bool isSleeping;

public:
  Mammal(std::string n, int a);
  void makeSound();
  void eat();
  void sleep();
  virtual void wagTail() {};
  void awake();
};

class Dog : public Mammal {
private:
  bool isTailWagging;

public:
  Dog(std::string n, int a);
  void makeSound();
  void eat();
  void sleep();
  void fetch();
  void wagTail();
  void awake();
};

class Cat : public Mammal {
private:
  int numberOfLives;

public:
  Cat(std::string n, int a);
  void makeSound();
  void eat();
  void sleep();
  void awake();
};

class Tail {
public:
  //Tail(std::string n, int a);
};

Animal::Animal(std::string n, int a) {
    name = n;
    age = a;
  }
  
  void Animal::makeSound() {
    std::cout << "This is a generic animal sound." << std::endl;
  }
  
  void Animal::eat() { std::cout << "The animal is eating." << std::endl; }
  
  void Animal::sleep() { std::cout << "The animal is sleeping." << std::endl; }

  void Animal::awake() { std::cout << "The animal is awake." << std::endl; }
  
  Mammal::Mammal(std::string n, int a) : Animal(n,a) { isSleeping = false; }
  
  void Mammal::makeSound() {
  	if (isSleeping==false) {
  		std::cout << "This is a generic mammal sound." << std::endl;
  	}
  }
  
  void Mammal::eat() { 
     if (isSleeping==false) {
        std::cout << "The mammal is eating." << std::endl; 
     }
  }
  
  void Mammal::sleep() {
    std::cout << "The mammal is sleeping." << std::endl;
    isSleeping = true;
  }
  
  void Mammal::awake() {
  	std::cout << "The mammal is awake." << std::endl;
  	isSleeping = false;
  }
  
  Dog::Dog(std::string n, int a) : Mammal(n, a) { isTailWagging = false; }
  
  void Dog::makeSound() { 
     if (isSleeping==false) {
        std::cout << "Woof!" << std::endl; 
     }
   }
  
  void Dog::eat() {
  	if (isSleeping==false) {
  		std::cout << "The dog is eating." << std::endl;
  		}
  }
  
  void Dog::sleep() {
    std::cout << "The dog is sleeping." << std::endl;
    isSleeping = true;
    isTailWagging = false;
  }
  
  void Dog::fetch() {
  	if (isSleeping==false) {
  		std::cout << "The dog is fetching." << std::endl;
  	}
  }
  
  void Dog::wagTail() {
    if (isSleeping==true) {
      std::cout << "The dog can't wag its tail because it's sleeping."
                << std::endl;
    } else {
      std::cout << "The dog is wagging its tail." << std::endl;
      isTailWagging = true;
    }
  }
  
  void Dog::awake() {
  	std::cout << "The dog is awake." << std::endl;
  	isSleeping = false;
  }
  
  Cat::Cat(std::string n, int a) : Mammal(n, a) { numberOfLives = 9; }
  
  void Cat::makeSound() { 
  if (isSleeping==false) {
     std::cout << "Meow!" << std::endl; 
  }
}
  
  void Cat::eat() {
  	if (isSleeping==false) {
  		std::cout << "The cat is eating." << std::endl;
  	}
  }
  
  void Cat::sleep() {
    std::cout << "The cat is sleeping." << std::endl;
    isSleeping = true;
  }
  
  void Cat::awake() {
  	std::cout << "The cat is awake." << std::endl;
  	isSleeping = false;
  }
  
  //Tail::Tail(std::string n, int a) : Dog() {}
  
  //int Cat::eat = eat();

int main() {
  Dog d("Fido", 3);
  Cat c("Fluffy", 5);
  Dog d1("Barky", 3);

  Mammal *arr[] = {&d, &c, &d1};

  // should woof, meow, woof
  for (int i = 0; i < 3; i++){
    arr[i]->makeSound();
  }

  // should eat in dog, cat, dog order
  for (int i = 0; i < 3; i++){
    arr[i]->eat();
  }

  // should woof, meow, woof
  for (int i = 0; i < 3; i++){
    arr[i]->makeSound();
  }

  // should sleep in dog, cat, dog order
  for (int i = 0; i < 3; i++){
    arr[i]->sleep();
  } 

  // shoudn't do anything as they're sleeping
  for (int i = 0; i < 3; i++){
    arr[i]->makeSound();
  }

  // shoudn't eat actually, as they are sleeping
  for (int i = 0; i < 3; i++){
    arr[i]->eat();
  }

  // shouldn't wag tails, they are sleeping, but some of them do not wag tail at all
  for (int i = 0; i < 3; i++){
    arr[i]->wagTail();
  }

  // do they really need to sleep forever? :'(
  for (int i = 0; i < 3; i++){
  	arr[i]->awake();
  }
  // Hah, that's stange :)
  //Tail t("Taily", 2);
  //t.makeSound();
}