/* Lecture Code 14.0
 *
 * The Engines example.  Comments have been added to the relevant sections.
 */

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

/* Base class for all Engines.  Defines vroom and the parametrized constructor. */
class Engine
{
public:
	explicit Engine(const string &engineName);

	/* Mark destructor virtual so deleting polymorphic pointers will actually
	 * call the correct destructor.
	 */
	virtual ~Engine() {}
	virtual void vroom() const
	{
		cout << "Vroom!" << endl;
	}
	string getEngineName() const
	{
		return name;
	}

private:
	string name;
};

Engine::Engine(const string &engineName) : name(engineName)
{
}

/* CarEngine: Like an Engine, but with a redefined vroom. */
class CarEngine: public Engine
{
public:
	/* Constructor invokes Engine constructor with parameter "Car Engine" */
	CarEngine(): Engine("Car Engine") {}
	virtual void vroom() const
	{
		cout << "Vroom at 65 mph!" << endl;
	}
};

/* JetEngine is a louder form of the Engine. */
class JetEngine: public Engine
{
public:
	JetEngine(): Engine("Jet Engine") {}
	virtual void vroom() const
	{
		cout << "\aVVVRRROOOOOOOOOMMM!!!\a" << endl;
	}
protected:

	/* Protected constructor helps to ferry information up to the Engine
	 * class so derived classes like GoldPlatedJetEngine will work correctly.
	 */
	JetEngine(const string &name): Engine(name) {}
};

/* A Gold-Plated Jet Engine*/
class GoldPlatedJetEngine: public JetEngine
{
public:
	/* Invoke the protected JetEngine constructor to ferry information up the
	 * chain.
	 */
	explicit GoldPlatedJetEngine(int price): JetEngine("Gold-Plated Jet Engine"), cost(price) {}
	virtual void vroom() const
	{
		/* Explicitly invoke JetEngine's version of vroom. */
		JetEngine::vroom();
		cout << "(Except more expensive.)" << endl;
	}
	int getCost() const
	{
		return cost;
	}
private:
	int cost;
};

/* Personalized GoldPlatedJetEngine that stores your name. */
class MyGoldPlatedJetEngine: public GoldPlatedJetEngine
{
public:
	MyGoldPlatedJetEngine(int cost, const char *yourName);
	MyGoldPlatedJetEngine(const MyGoldPlatedJetEngine &other);
	MyGoldPlatedJetEngine& operator= (const MyGoldPlatedJetEngine &other);
	~MyGoldPlatedJetEngine();

	const char* getOwnerName() const
	{
		return myName;
	}

private:
	void copyOther(const MyGoldPlatedJetEngine &other);
	void clear();
	char *myName;
};

MyGoldPlatedJetEngine::MyGoldPlatedJetEngine(int cost, const char *name)
: GoldPlatedJetEngine(cost)
{
	myName = new char[strlen(name) + 1];
	strcpy(myName, name);
}

void MyGoldPlatedJetEngine::copyOther(const MyGoldPlatedJetEngine &other)
{
	myName = new char[strlen(other.myName) + 1];
	strcpy(myName, other.myName);
}

/* Copy constructor invokes GoldPlatedJetEngine copy constructor. */
MyGoldPlatedJetEngine::MyGoldPlatedJetEngine
(const MyGoldPlatedJetEngine &other): GoldPlatedJetEngine(other)
{
	copyOther(other);
}

MyGoldPlatedJetEngine&
MyGoldPlatedJetEngine::operator =(const MyGoldPlatedJetEngine &other)
{
	if(this != &other)
	{
		clear();
		/* Explicitly invoke GoldPlatedJetEngine assignment operator. */
		GoldPlatedJetEngine::operator =(other);
		copyOther(other);
	}
	return *this;
}

MyGoldPlatedJetEngine::~MyGoldPlatedJetEngine()
{
	clear();
}

void MyGoldPlatedJetEngine::clear()
{
	delete [] myName;
	myName = NULL;
}