#include <iostream>
#include <fstream>
#include <cstring>

using namespace std;


#include "Name.h"
#include "Date.h"
#include "Person.h"
#include "Set.h"

void main() {
	//Create a Person object
	Person *p1 = new Person("Lou", "Nel", "lou@chat.ca", 20, 6, 1960);
	cout << *p1 << endl;

	//Create some sets
	Set<Person> s,s2;
	Set<int> setints;
	Set<Date> dates;
	 
	//Add the person to a set
	s.add(*p1);

	//Check if the object is copied, or if the address is stored
	if (p1 != &(s.someElement()))
		cout << "\nOBJECTS ARE NOT THE SAME";
	else
		cout << "\nObjects are identical";

	//Add more people to the set
	cout << "\nAdding Frank to first set";
	s.add(*(new Person("Frank", "Smith",  "f123@chat.ca", 20, 3, 1967)));
	cout << "\nAdding Eric to first set";
	s.add(*(new Person("Eric", "Johnson", "eric@chat.ca", Date(25, 4, 1958))));
	cout << "\nAdding Mary to first set";
	s.add(*(new Person("Mary", "Pearson", "mary@chat.ca", Date(25, 4, 1955))));
	cout << "\nAdding John to first set";
	s.add(*(new Person("John", "Smith",  "john@chat.ca", Date(12, 12, 1970))));

	//Create some ints
	cout << "\n\nInitializing Ints";
	int a = 5;
	int b= 12;
	int c= 12;
	int d= 42;

	//Add ints to set
	cout << "\nAdding ints " << a << ", " << b << ", " << c << ", " << d << "\n";
	setints.add(a).add(b).add(c).add(d);

	//Print the set of ints
	cout << "\nPrinting the Set<int>";
	cout << setints << endl;

	//Create and add some Dates to the set
	cout << "\nAdding three dates to set";
	dates.add(*(new Date(1,1,2001))).add(*(new Date(15,12,2001))).add(*(new Date(29,7,2001)));

	//Print the set of Dates
	cout << "\nPrinting the Set<Date>"; //write comment to output file
	cout << dates << endl; //print the dates to the output file

	//Print the people first name first using iterator
	Name::printLastNameFirst(false);
	cout << "\nPrint names with last name first\n";
	for (s.reset(); s.hasMore(); s.advance() ){
		   cout << s.element() << endl;
	}

	//Print the people last name first using iterator
	cout << "\nChanging the order of the name\n";
	Name::printLastNameFirst(true);
	for (s.reset(); s.hasMore(); s.advance() ){
		   cout << s.element() << endl;
	}

	//Add some more Persons to the set
	cout << "\nAdding Alan to set";
	s.add(*(new Person("Alan","Johns", "alan@chat.ca", 20, 3, 1967)));
	cout << "\nAdding Eric to set";
	s.add(*(new Person("Eric", "Turner", "et@chat.ca", 25, 4, 1958)));
	cout << "\nAdding Bruce to set";
	s.add(*(new Person("Bruce", "Jones", "bruce@chat.ca", 25, 4, 1955)));

	//Check if the assignment operator of the Set class works
	cout << "\nSetting second set to equal first set";
	s2 = s;

	//Print out both sets
	cout << "\n\nPrinting first set"<< s << "\n\nPrinting Second set" << s2 << "\n";

	//Check someElement() function
	cout << "\n\nElement returned by someElement() in second set: \n" << s2.someElement();

	//Check includes() functions
	cout << "\n\nIs Lou in the set? ";
	if(s2.includes(*p1))
		cout << "Yes";
	else
		cout << "No";

	//Check remove function()
	cout << "\nTry to remove Lou using remove()";
	s2.remove(*p1);

	//Print out second set
	cout << "\n\nPrinting second set" << s2;

	//Create three Persons, one with the copy constructor
	cout << "\n\nCreating Person";
	Person *aPerson = new Person("A", "Person", "person@chat.ca", 12, 2, 1982);
	cout << "\nCreating another person";
	Person *anotherPerson = new Person("Another", "Person", "another@chat.ca", 24, 4, 1982);
	cout << "\nCreating Person Three";
	Person *personThree = new Person(*anotherPerson);

	//Print the three Persons
	cout << "\n\nA Person: " << *aPerson << "\nAnother Person: " << *anotherPerson << "\nPerson Three: " << *personThree;
	//Check if assignment operator in Person class works (and by association, in the Date class too)
	cout << "\n\nMake A Person = Another Person";
	*aPerson = *anotherPerson;
	cout << "\n\nA Person: " << *aPerson << "\nAnother Person: " << *anotherPerson << "\nPerson Three: " << *personThree;

	//Create three Names: one thing, one with first and last name, one with the copy constructor
	cout << "\n\nCreating Name One: ";
	Name *n1 = new Name("Name1");
	cout << *n1;
	cout << "\nCreating Name Two: ";
	Name *n2 = new Name("Name", "Two");
	cout << *n2;
	cout << "\nCreating Name Three (with n1): ";
	Name *n3 = new Name(*n1);
	cout << *n3;

	//Check if assignment operator in the Name class works
	cout << "\n\nSetting n3 = n2";
	*n3 = *n2;
	cout << "\nName One: " << *n1 << "\nName Two: " << *n2 << "\nName Three: " << *n3;

	//Make sure that the objects are equal, not identical
	if(n3 == n2)
		cout << "\nObject are identical";
	else
		cout << "\nObjects have their own heap space";

	//Delete all the Persons
	cout << "\n\nDeleting first set of Persons";
	for (s.reset(); s.hasMore(); s.advance() )
		delete &(s.element());
	cout << "\nDeleting extra Persons";
	delete aPerson;
	delete anotherPerson;
	delete personThree;

	//Delete the Names
	cout << "\nDeleting extra Names";
	delete n1;
	delete n2;
	delete n3;

	//Delete all the Dates
	cout << "\nDeleting set of Dates";
	for (dates.reset(); dates.hasMore(); dates.advance() )
		delete &(dates.element());

	cout << endl << endl;;
} //end main 