/*
 * Method definitions for a Cat.
 * 
 * Author: Zach Tomaszewski
 */
#include <iostream>
#include "Cat.hpp"

using std::cout;
using std::endl;

/* Constructor */
Cat::Cat(const std::string name, int lives) {
  //any call to new here needs a matching delete in the destructor
  this->name = new std::string(name);  
  this->lives = lives;

  //just so we can see when this is called in this example
  cout << "new Cat(" << *this->name << ", " << lives << ")" << endl;
}


/* Destructor */
Cat::~Cat() {
  //debug
  cout << "bye-bye Cat(" << *this->name << ", " << lives << ")" << endl;
  
  //real job of this destructor:
  delete this->name;  
}

/* Reduces this Cat's lives by 1 if not already 0 or less. */
void Cat::badLuck() {
  if (lives > 0) {
    lives--;
  }
}

//such simple accessors could be inlined, but not covering that here

std::string Cat::getName() {
  //not returning a reference, so returns a copy of this string
  return *name;
}

int Cat::getLives() {
  return lives;
}


/* Copy-constructor */
Cat::Cat(const Cat& cat) {
  // The copy constructor gets called whenever a new object is initialized
  // based on an existing Cat object.  This happens, for example, when calling
  // a function that takes a Cat as a parameter.  The default behavior of
  // the copy-constructor is to do a bitwise copy, as done when assigning
  // one struct to another.  This would cause problems for this Cat, because
  // then both objects would contain a pointer to the same string name.
  // When the two Cat objects are destroyed later, this would result in a
  // double call to delete on the same string in memory.
  //
  // Therefore, we need manually create a new string for the new Cat object
  // and also copy over all other member data.
  //
  // Since we can't call one constructor from another in traditional C++,
  // we need to do this manually.
  //
  this->name = new std::string(*cat.name + "-copy");  //going to append a bit for debugging
  this->lives = cat.lives;
  
  //debug
  cout << "copy new Cat(" << *this->name << ", " << lives << ")" << endl;
}

/* Assignment operator */
Cat& Cat::operator=(const Cat& cat) {
  // Like the copy-constructor, we need to override this function to 
  // change the default struct-copying behavior.  This function gets
  // called when one Cat object is assigned to another existing Cat
  // object.  In this case, we need to delete the old Cat's name before
  // performing the copy.  If we did not, we'd have a member leak.
  
  //debug first
  cout << "assign Cat(" << *this->name << ", " << lives << ") <== ";
  cout << "Cat(" << *cat.name << ", " << cat.lives << ")" << endl;
  
  delete this->name;
  this->name = new std::string(*cat.name + "-assigned");
  this->lives = cat.lives;
}
