/* Lecture Code 13.0
 *
 * The Scary Things example, inspired by "Night on Bald Mountain" by Modest Musorgsky
 * with edits by Rimsky-Korsakov.  Comments have been added to the relevant sections.
 */

#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;

const int NUM_SCARY_OBJECTS = 25;

/* Enumerated type used for randomly generating the vector<ScaryThing *> */
enum scaryT {Ghost, Ghoul, Banshee, Witch, NUM_TYPES};

/* Abstract class representing scary things. */
class ScaryThing
{
public:
	virtual void doScaryDance() const = 0;
	virtual void doScaryChant() const = 0;
	virtual void beEvil() const; // Not pure virtual
};

/* Default behavior for scary things is to announce how evil they are. */
void ScaryThing::beEvil() const
{
	cout << "I am very evil!" << endl;
}

/* A Ghoul class. */
class ScaryGhoul: public ScaryThing
{
public:
	void doScaryDance() const
	{
		cout << "Hoppity Hoppity Hoppity" << endl;
	}

	void doScaryChant() const
	{
		cout << "Mwahahahaha!" << endl;
	}
};

/* A Ghost class. */
class ScaryGhost: public ScaryThing
{
public:
	void doScaryDance() const
	{
		cout << "Swishhhh.....  Swishhhh...." << endl;
	}

	void doScaryChant() const
	{
		cout << "Boo!" << endl;
	}
};

/* A Banshee class. */
class ScaryBanshee: public ScaryThing
{
public:
	void doScaryDance() const
	{
		cout << "The Banshee Waltz... 1, 2, 3, 1, 2, 3..." << endl;
	}

	void doScaryChant() const
	{
		cout << "Screeeeeeeeeeeeeeeeeeeeeech!" << endl;
	}
};

/* A Witch class.  Note that beEvil is overridden by this class. */
class ScaryWitch: public ScaryThing
{
public:
	void doScaryDance() const
	{
		cout << "Witch Break Dance!" << endl;
	}

	void doScaryChant() const
	{
		cout << "Cackle Cackle Cackle!" << endl;
	}

	void beEvil() const
	{
		cout << "Boil, bubble, toil and trouble!" << endl;
	}
};

void FillScary(vector<ScaryThing *> &scary)
{
	srand((unsigned int)time(NULL));
	for(int i = 0; i < NUM_SCARY_OBJECTS; i++)
	{
		/* Generate a random number and based on the result, create a different type of ScaryThing. */
		switch(scaryT(rand() % NUM_TYPES))
		{
			case Ghost:
				scary.push_back(new ScaryGhost);
				break;
			case Ghoul:
				scary.push_back(new ScaryGhoul);
				break;
			case Banshee:
				scary.push_back(new ScaryBanshee);
				break;
			case Witch:
				scary.push_back(new ScaryWitch);
				break;
		}
	}
}

int main()
{
	vector<ScaryThing *> scary;
	FillScary(scary);

	/* Loop over the elements and have them be scary in various ways. */
	for(int i = 0; i < scary.size(); i++)
	{
		scary[i]->beEvil();
		scary[i]->doScaryDance();
		scary[i]->doScaryChant();
		
		/* Free dynamically-allocated memory. */
		delete scary[i];
	}

	return 0;
}