#include <iostream>
#include <string>
using namespace std;

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

public:
  Animal(std::string n, int a);
  virtual void makeSound();
  virtual void eat(); // метод не був віртуальним              !!!!!!!!!!
  virtual void sleep();
};

class Mammal : public Animal {  // було protected             !!!!!!!!!!!
protected:
  bool isSleeping;     // He getSleeping                  !!!!!!!

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

class Dog : public Mammal {
private:
  bool isTailWagging;

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

class Cat : public Mammal {
private:
  int numberOfLives;

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

class Tail : public Dog {
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; }
  
  Mammal::Mammal(std::string n, int a) : Animal(n,a)  { isSleeping = false; }//не передали вік тварини !!!!!!!!
  
  void Mammal::makeSound() {
    std::cout << "This is a generic mammal sound." << std::endl;
  }
  
  void Mammal::eat() { 
  	if (isSleeping) {
    cout << "Can't eat, sleeping\n";
    return;
  }
  	std::cout << "The mammal is eating." << std::endl; }
  
  void Mammal::sleep() {
    std::cout << "The mammal is sleeping." << std::endl;
    isSleeping = true;
  }
  
  Dog::Dog(std::string n, int a) : Mammal(n, a) { isTailWagging = false; }
  
  void Dog::makeSound() { std::cout << "Woof!" << std::endl; }
  
  void Dog::eat() { std::cout << "The dog is eating." << std::endl; }
  
  void Dog::sleep() {
    std::cout << "The dog is sleeping." << std::endl;
    isSleeping = true;
  }
  
  void Dog::fetch() { std::cout << "The dog is fetching." << std::endl; }
  
  void Dog::wagTail() {
    if (isSleeping) {
      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;
    } // логика                 !!!!!!!!!!!
  }
  
  Cat::Cat(std::string n, int a) : Mammal(n, a) { numberOfLives = 9; }
  
  void Cat::makeSound() { std::cout << "Meow!" << std::endl; }
  
  void Cat::eat() { std::cout << "The cat is eating." << std::endl; }
  
  void Cat::sleep() {
    std::cout << "The cat is sleeping." << std::endl;
    isSleeping = true;
  }
  
  Tail::Tail(std::string n, int a) : Dog(n,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++){
    Dog* dog = dynamic_cast<Dog*>(arr[i]);
    if (dog) dog->wagTail();
  }
  
  //for (int i = 0; i < 3; i++){				!!!!!!!!!!!!
  //  arr[i]->wagTail();
  //}

  // do they really need to sleep forever? :'(
  
  // Hah, that's stange :)
  Tail t("Taily", 2);
  t.makeSound();
}