#include <iostream>
#include <string>

class Pet {
  string name;
public:
  Pet(const string & aName) : name(aName) {}
  virtual void talk() = 0;
  // add virtual later
  virtual string print() const { return name; } 
};

class Dog : public Pet {
public:
  Dog(const string & aName) : Pet(aName) {}
  void talk() { cout << "Woof woof" << endl; }
}; 

class Cat : public Pet {
public:
  Cat(const string & aName) : Pet(aName) {}
  void talk() { cout << "Meow meow" << endl; }
  void climb() { cout << "Climbing..." << endl; }
};

class Magic {
  string word;
public:
  Magic(const string & aWord) : word(aWord) {}
  virtual void talk() { cout << "It's magic!" << endl; }
  string print() const { return word; }
  void guess(const string & guess) { 
    cout << ( (guess == word) ? "Right!" : "Wrong!") << endl;
  }
};

ostream & operator<<(ostream & os, const Pet & pet) {
  return (os << pet.print());
}

ostream & operator<<(ostream & os, const Magic & magic) {
  return (os << magic.print()); 
}

// write in class
class MagicCat : public Cat, public Magic {
public:
  MagicCat(const string & aName, const string & aWord) : Cat(aName), Magic(aWord) {}; 
  string print() const { return (Cat::print() + " " + Magic::print()); }
};

// write in class
ostream & operator<<(ostream & os, const MagicCat & magCat) {
  //return (os << magCat.print());
  return (os << magCat.Cat::print() << " " << magCat.Magic::print());
}

// write in class
class Chihuahua : public Dog, public Cat {
public:
  Chihuahua(const string & aName) : Dog(aName), Cat(aName) {}
  // add later
  Chihuahua(const string & dName, const string & cName) : Dog(dName), Cat(cName) {}
};

int main() {
  Cat tom("Tom");
  Dog fido("Fido");
  cout << tom << " and " << fido << endl;
  tom.talk();
  tom.climb();
  
  Pet & mypet = tom;
  cout << mypet << endl;
  mypet.talk();
  dynamic_cast<Cat&>(mypet).climb();

  MagicCat felix("Felix", "food");
  cout << felix << endl;
  
  felix.guess("mouse");
  felix.guess("food");

  Cat & kitty = felix;
  cout << kitty << endl;
  // Note the cast to Magic instead of MagicCat
  dynamic_cast<Magic &>(kitty).guess("food");
  
  Chihuahua taco("Taco");
  // taco.talk();
  taco.Dog::talk();
  dynamic_cast<Cat &>(taco).talk();

  Dog & tdog = taco;
  Cat & tcat = taco;
  tdog.talk();
  tcat.talk();

  // Pet & tpet = taco;
  Pet & tpet = dynamic_cast<Dog &>(taco);

  Chihuahua chi("Chi", "huahua");
  cout << dynamic_cast<Cat &>(chi) << endl;
  cout << dynamic_cast<Dog &>(chi) << endl;
}

