/* Lecture code 15.0
 *
 * Engines example!
 */
#include <iostream>
#include <cstring>
using namespace std;

/* Base class for all Engines.  Stores a name and can go VROOM! */
class Engine
{
public:
	/* Default constructor creates engine with no name.  Parametrized
	 * constructor creates engine with the specified name.
	 */
	Engine();
	explicit Engine(const char *name);

	/* Copy ctor, op=, and destructor. */
	Engine(const Engine &other);
	Engine& operator= (const Engine &other);
	virtual ~Engine();

	/* Vroom makes noise.  getEngineName returns the stored name. */
	virtual void vroom() const;
	const char *getEngineName() const;

private:
	void copyOther(const Engine &other);
	void clear();

	char *name;
};

/* An engine that stores a name in addition to the engine name. */
class PersonalEngine: public Engine
{
public:
	/* Default constructor stores engine name in superclass and makes a local
	 * copy of the named parameter.
	 */
	PersonalEngine(const char *engineName, const char *ourName) : Engine(engineName)
	{
		this->ourName = new char[strlen(ourName) + 1];
		strcpy(this->ourName, ourName);
	}

	/* Copy constructor invokes superclass copy constructor in addition to
	 * copying its own data.
	 */
	PersonalEngine(const PersonalEngine& other) : Engine (other)
	{
		copyOther(other);
	}
	
	/**
	 * Op= is like the regular assignment operator, but it also invokes the
	 * superclass assignment operator explicitly.
	 */
	PersonalEngine& operator = (const PersonalEngine& other)
	{
		if(this != &other)
		{
			clear();

			/* Invoke superclass assignment operator. */
			Engine::operator =(other);

			copyOther(other);
		}
		return *this;
	}
	~PersonalEngine()
	{
		clear();
	}
	const char *getOwnerName() const
	{
		return ourName;
	}
private:
	char *ourName;
	void clear() { delete [] ourName; }
	void copyOther(const PersonalEngine& other)
	{
		ourName = new char[strlen(other.ourName) + 1];
		strcpy(ourName, other.ourName);
	}
};

class CarEngine: public Engine
{
public:
	CarEngine() : Engine("Car Engine") {}
	virtual void vroom() const
	{
		cout << "Vroom at 65 mph!" << endl;
	}
protected:
	/* Protected constructor lets subclasses pass information up to
	 * superclass.
	 */
	CarEngine(const char *name) : Engine(name) {}
};

class SportsCarEngine: public CarEngine
{
public:
	SportsCarEngine() : CarEngine("Sports Car Engine") {}
	void vroom(int numTimes) const
	{
		for(int i = 0; i < numTimes; ++i)
			cout << "Revvvvvv..." << endl;
	}
	/* To avoid issues with name hiding, import the vroom function from the
	 * superclass.
	 */
	using CarEngine::vroom;
};

class JetEngine: public Engine
{
public:
	JetEngine() : Engine("Jet Engine") {}
	virtual void vroom() const
	{
		cout << "\aVVVRRROOOOOOOOOMMM!!!\a" << endl;
	}
};

class GoldPlatedJetEngine: public JetEngine
{
public:
	virtual void vroom() const
	{
		/* Invoke the superclass function.  Note that this access the member
		 * non-virtually.
		 */
		JetEngine::vroom();
		cout << "(Except more expensive.)" << endl;
	}
};

/* Basic Engine implementation.  Nothing particularly interesting here. */
Engine::Engine()
{
	this->name = new char[1];
	strcpy(this->name, "");
}

Engine::Engine(const char *name)
{
	this->name = new char[strlen(name) + 1];
	strcpy(this->name, name);
}

void Engine::copyOther(const Engine &other)
{
	this->name = new char[strlen(other.name) + 1];
	strcpy(this->name, other.name);
}

Engine::Engine(const Engine &other)
{
	copyOther(other);
}

Engine& Engine::operator =(const Engine &other)
{
	if(this != &other)
	{
		clear();
		copyOther(other);
	}
	return *this;
}

Engine::~Engine()
{
	clear();
}

void Engine::clear()
{
	delete [] name;
	name = NULL;
}

void Engine::vroom() const
{
	cout << "Vroom!" << endl;
}

const char *Engine::getEngineName() const
{
	return name;
}