#include "LinkedList.h"
#include "Media.h"
#include "CompactDisc.h"
#include "DigitalDisk.h"
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;

void addCD(LinkedList<CompactDisc> &);
void addDVD(LinkedList<DigitalDisk> &);
void subCD(LinkedList<CompactDisc> &);
void subDVD(LinkedList<DigitalDisk> &);
void modCD(LinkedList<CompactDisc> &);
void modDVD(LinkedList<DigitalDisk> &);
void quitManager(LinkedList<CompactDisc> &, LinkedList<DigitalDisk> &);

int main()
{
	LinkedList<CompactDisc> cdCollection;
	LinkedList<DigitalDisk> dvdCollection;
	int choice = 1;
	cout << "Welcome to media manager. What would you like to do? ";
	cout << "\n1. Add a CD\n2. Add a DVD\n3. Remove a CD\n4. Remove a DVD\n5. Change a CD\n6. Change a DVD\n7.Quit and display collection\n";
	cin >> choice;
	while (choice != 7)
	{
		if (choice == 1)
		{
			addCD(cdCollection);
		}
		else if (choice == 2)
		{
			addDVD(dvdCollection);
		}
		else if (choice == 3)
		{
			subCD(cdCollection);
		}
		else if (choice == 4)
		{
			subDVD(dvdCollection);
		}
		else if (choice == 5)
		{
			modCD(cdCollection);
		}
		else if (choice == 6)
		{
			modDVD(dvdCollection);
		}
		else
		{
			cout << "\nEnter a valid choice";
		}
		cout << "\n1. Add a CD\n2. Add a DVD\n3. Remove a CD\n4. Remove a DVD\n5. Change a CD\n6. Change a DVD\n7.Quit and display collection\n";
		cin >> choice;
	}
	quitManager(cdCollection, dvdCollection);

	return 0;
}

void addCD(LinkedList<CompactDisc> &cds)
{
	string tempname;
	double temptime;
	string tempartist;
	CompactDisc tempdisk;
	cout << "\nEnter the name of the CD to add: ";
	cin.ignore();
	getline(cin, tempname);
	cout << "Enter the total length of the CD: ";
	cin >> temptime;
	cin.ignore();
	cout << "Enter the name of the CD artist: ";
	getline(cin, tempartist);
	tempdisk.setMediaName(tempname);
	tempdisk.setMediaLength(temptime);
	tempdisk.setArtistName(tempartist);
	cout << tempdisk.getMediaName();
	cds.appendNode(tempdisk);
	cout << "CD added\n";
}

void addDVD(LinkedList<DigitalDisk> &dvds)
{
	string tempname;
	double temptime;
	int tempyear;
	DigitalDisk tempdisk;
	cout << "\nEnter the name of the DVD to add: ";
	cin.ignore();
	getline(cin, tempname);
	cout << "Enter the length of the movie: ";
	cin >> temptime;
	cout << "Enter the year the movie was released: ";
	cin >> tempyear;
	tempdisk.setMediaName(tempname);
	tempdisk.setMediaLength(temptime);
	tempdisk.setYearReleased(tempyear);
	dvds.appendNode(tempdisk);
	cout << "DVD added\n";
}

void subCD(LinkedList<CompactDisc> &cds)
{
	string tempname;
	CompactDisc tempdisk;
	cout << "\nEnter the name of the CD to delete: ";
	cin.ignore();
	getline(cin, tempname);
	tempdisk.setMediaName(tempname);
	tempdisk = cds.searchList(tempdisk);
	if (tempdisk.getMediaLength() != 0)
	{
		cds.deleteNode(tempdisk);
		cout << "CD deleted\n";
	}
	else
		cout << "CD not in collection.  Cannot Delete.\n";
}

void subDVD(LinkedList<DigitalDisk> &dvds)
{
	string tempname;
	DigitalDisk tempdisk;
	cout << "\nEnter the name of the movie to delete: ";
	cin.ignore();
	getline(cin, tempname);
	tempdisk.setMediaName(tempname);
	tempdisk = dvds.searchList(tempdisk);
	if (tempdisk.getMediaLength() != 0)
	{
		dvds.deleteNode(tempdisk);
		cout << "\nDVD deleted";
	}
	else
		cout << "\nDVD not in collection.  Cannot Delete.";
}

void modCD(LinkedList<CompactDisc> &cds)
{
	int changeme;
	string tempname;
	CompactDisc tempdisc;
	cout << "\nEnter the name of a CD to change: ";
	cin.ignore();
	getline(cin, tempname);
	tempdisc.setMediaName(tempname);
	tempdisc = cds.searchList(tempdisc);
	while (tempdisc.getMediaLength() == 0)
	{
		cout << "\nEnter a valid name of a CD to change: ";
		cin.ignore();
		getline(cin, tempname);
		tempdisc.setMediaName(tempname);
		tempdisc = cds.searchList(tempdisc);
	}
	cout << "\nWhat would you like to change about this CD: ";
	cout << "\n1. Artist Name\n2.CD Length\n3. Add Song\n4. Delete Song\n5. CD Name\n6.Exit Modifier\n";
	cin >> changeme;
	cin.ignore();
	while (changeme != 6)
	{
		if (changeme == 1)
		{
			string tempname;
			cout << "\nEnter a new artist name: ";
			cin.ignore();
			getline(cin, tempname);
			tempdisc.setArtistName(tempname);
			cout << "\nName changed successfully";
		}
		else if (changeme == 2)
		{
			double temptime;
			cout << "\nEnter a new CD length: ";
			cin >> temptime;
			cin.ignore();
			tempdisc.setMediaLength(temptime);
			cout << "\nTime changed successfully";
		}
		else if (changeme == 3)
		{
			string tempname;
			double temptime;
			cout << "\nEnter a song name: ";
			cin.ignore();
			getline(cin, tempname);
			cout << "\nEnter a song length: ";
			cin >> temptime;
			cin.ignore();
			tempdisc.addSong(tempname, temptime);
		}
		else if (changeme == 4)
		{
			string tempname;
			cout << "\nEnter the name of a song to delete: ";
			getline(cin, tempname);
			if (tempdisc.deleteSong(tempname))
			{
				cout << "\nSong deleted successfully";
			}
			else
				cout << "\nSong does not exist in this CD to delete";
		}
		else
		{
			string tempname;
			cout << "\nEnter the new name of this CD: ";
			getline(cin, tempname);
			tempdisc.setMediaName(tempname);
			cout << "\nName changed successfully";
		}
		cout << "\nWhat would you like to change about this CD: ";
		cout << "\n1. Artist Name\n2.CD Length\n3. Add Song\n4. Delete Song\n5. CD Name\n6.Exit Modifier\n";
		cin >> changeme;
		cin.ignore();
	}
	cout << "\nNow exiting CD modifier...";
}

void modDVD(LinkedList<DigitalDisk> &dvds)
{
	int changeme;
	string tempname;
	DigitalDisk tempdisc;
	cout << "\nEnter the name of a DVD to change: ";
	cin.ignore();
	getline(cin, tempname);
	tempdisc.setMediaName(tempname);
	tempdisc = dvds.searchList(tempdisc);
	while (tempdisc.getMediaLength() == 0)
	{
		cout << "\nEnter a valid name of a DVD to change: ";
		getline(cin, tempname);
		tempdisc.setMediaName(tempname);
		tempdisc = dvds.searchList(tempdisc);
	}
	cout << "\nWhat would you like to change about this DVD: ";
	cout << "\n1. Actor or Character name\n2.DVD Length\n3. Add Actor/Character\n4. Delete ActorCharacter\n5. Year Released\n6. DVD name";
	cout << "\n7.Exit Modifier\n";
	cin >> changeme;
	cin.ignore();
	while (changeme != 7)
	{
		if (changeme == 1)
		{
			int whichtochange;
			cout << "\nChange: \n1. Actor name\n2.Character name";
			cin >> whichtochange;
			cin.ignore();
			if (whichtochange == 1)
			{
				string tempname;
				cout << "\nEnter a new actor name: ";
				cin.ignore();
				getline(cin, tempname);
				if (tempdisc.changeActor(tempname))
					cout << "\nActor changed successfully";
				else
					cout << "\nActor does not exist to change";
			}
			else
			{
				string tempaname;
				string tempcname;
				cout << "\nEnter an actor to change their character's name: ";
				cin.ignore();
				getline(cin, tempaname);
				cout << "\nEnter their new character's name: ";
				cin.ignore();
				getline(cin, tempcname);
				if (tempdisc.changeCharacter(tempaname, tempcname))
					cout << "\nCharacter changed successfully";
				else
					cout << "\nActor does not exist to change character name";
			}
		}
		else if (changeme == 2)
		{
			double temptime;
			cout << "\nEnter a new movie length: ";
			cin >> temptime;
			cin.ignore();
			tempdisc.setMediaLength(temptime);
			cout << "\nTime changed successfully";
		}
		else if (changeme == 3)
		{
			string tempaname;
			string tempcname;
			cout << "\nEnter a new actor name: ";
			getline(cin, tempaname);
			cout << "\nEnter a new character name: ";
			getline(cin, tempcname);
			tempdisc.addPlayer(tempaname, tempcname);
		}
		else if (changeme == 4)
		{
			string tempname;
			cout << "\nEnter the name of an actor to delete: ";
			if (tempdisc.deletePlayer(tempname))
			{
				cout << "\nActor deleted successfully";
			}
			else
				cout << "\nActor does not exist in this movie to delete";
		}
		else if (changeme == 5)
		{
			int tempyear;
			cout << "\nEnter a new year of release for this movie: ";
			cin >> tempyear;
			cin.ignore();
			tempdisc.setYearReleased(tempyear);
			cout << "\nYear changed successfully";
		}
		else
		{
			string tempname;
			cout << "Enter the new name of this DVD: ";
			getline(cin, tempname);
			tempdisc.setMediaName(tempname);
			cout << "\nName changed successfully";
		}

		cout << "\nWhat would you like to change about this DVD: ";
		cout << "\n1. Actor or Character name\n2.DVD Length\n3. Add Actor/Character\n4. Delete ActorCharacter\n5. Year Released\n6. DVD name";
		cout << "\n7.Exit Modifier\n";
		cin >> changeme;
		cin.ignore();
	}
	cout << "\nNow exiting DVD modifier...";
}

void quitManager(LinkedList<CompactDisc> &cds, LinkedList<DigitalDisk> &dvds)
{
	cout << "\nThank you for using Media Manager. Your collection is as follows: " << endl << endl;
	cout << "DVD Collection\n ~~~~~~~~~~~~~~~~~~\n";
	cout << "Movie Title " << setw(20) << "Length of Movie" << setw(20) << "Year Released" << setw(10) << "Actors" << setw(10) << "Character";
	dvds.displayList();
	
	cout << endl;
}
----------------------------------------------
#ifndef DIGITALDISK_H
#define DIGITALDISK_H
#include <iostream>
#include <iomanip>
#include <string>
#include "LinkedList.h"
#include "Media.h"
#include "Player.h"

class DigitalDisk;
ostream &operator << (ostream &, const DigitalDisk &);

class DigitalDisk : public Media
{
private:
	int yearReleased;
	LinkedList<Player> credits;
public:
	DigitalDisk() :Media()
	{
		yearReleased = 0;
	}
	DigitalDisk(std::string mn, double ml, int yr) : Media(mn, ml)
	{
		yearReleased = yr;
	}

	void setYearReleased(int yr)
	{
		yearReleased = yr;
	}

	int getYearReleased()
	{
		return yearReleased;
	}

	void addPlayer(string an, string cn)
	{
		Player temp;
		temp.setActorName(an);
		temp.setCharacterName(cn);
		credits.appendNode(temp);
		credits.displayList();
		cout << "\nActor/Character added";
	}

	bool deletePlayer(std::string an)
	{
		Player temp;
		temp.setActorName(an);
		temp = credits.searchList(temp);
		if (temp.getCharacterName() != "")
		{
			credits.deleteNode(temp);
			return true;
		}
		else
			return false;
	}

	bool changeActor(std::string an)
	{
		Player temp1;
		Player temp2;
		temp2.setActorName(an);
		temp2 = credits.searchList(temp2);
		if (temp2.getCharacterName() != "")
		{
			temp1 = temp2;
			temp1.setActorName(an);
			credits.deleteNode(temp2);
			credits.appendNode(temp1);
			return true;
		}
		else
			return false;
	}

	bool changeCharacter(std::string an, std::string cn)
	{
		Player temp1;
		Player temp2;
		temp2.setActorName(an);
		temp2 = credits.searchList(temp2);
		if (temp2.getCharacterName() != "")
		{
			temp1 = temp2;
			temp1.setCharacterName(cn);
			credits.deleteNode(temp2);
			credits.appendNode(temp1);
			return true;
		}
		else
			return false;
	}

	bool operator == (DigitalDisk &right)
	{
		if (mediaName == right.getMediaName())
			return true;
		else
			return false;
	}

	bool operator != (DigitalDisk &right)
	{
		if (mediaName != right.getMediaName())
			return true;
		else
			return false;
	}

	DigitalDisk operator = (DigitalDisk &right)
	{
		mediaName = right.getMediaName();
		mediaLength = right.getMediaLength();
		yearReleased = right.getYearReleased();
		return *this;
	}

	void displayCredits()
	{
		credits.displayList();
	}

	friend ostream &operator << (ostream & strm, const DigitalDisk &obj)
	{
		strm << endl << obj.mediaName << setw(10) << obj.mediaLength << setw(10) << obj.yearReleased << setw(10);
		return strm;
	}
};
#endif

----------------------------------------------

#ifndef COMPACTDISC_H
#define COMPACTDISC_H
#include <string>
#include "LinkedList.h"
#include "Media.h"

class CompactDisc : public Media
{
	struct song
	{
		std::string songName;
		double songLength;
		bool operator ==(song &right)
		{
			if (songName == right.songName && songLength == right.songLength)
				return true;
			else
				return false;
		}
		bool operator !=(song &right)
		{
			if (songName != right.songName && songLength != right.songLength)
				return true;
			else
				return false;
		}
		song operator = (song &right)
		{
			song temp;
			temp.songName = right.songName;
			temp.songLength = right.songLength;
			return temp;
		}
		void displaySong()
		{
			cout << songName << songLength;
		}
	};
private:
	LinkedList<song> setlist;
	std::string artistName;
public:
	CompactDisc() : Media()
	{
		artistName = "";
	}
	CompactDisc(std::string mn, double ml, std::string an) : Media(mn, ml)
	{
		artistName = an;
	}

	void setArtistName(std::string an)
	{
		artistName = an;
	}

	std::string getArtistName()
	{
		return artistName;
	}

	void addSong(std::string sn, double sl)
	{
		song temp;
		temp.songName = sn;
		temp.songLength = sl;
		setlist.appendNode(temp);
	}
	
	bool deleteSong(std::string sn)
	{
		song temp;
		temp.songName = sn;
		temp = setlist.searchList(temp);
		if (temp.songLength != 0)
		{
			setlist.deleteNode(temp);
			return true;
		}
		else
			return false;
	}

	bool operator == (CompactDisc &right)
	{
		if (mediaName == right.getMediaName())
			return true;
		else
			return false;
	}

	bool operator != (CompactDisc &right)
	{
		if (mediaName != right.getMediaName())
			return true;
		else
			return false;
	}

	CompactDisc operator = (CompactDisc &right)
	{
		mediaName = right.getMediaName();
		mediaLength = right.getMediaLength();
		artistName = right.getArtistName();
		return *this;
	}

};
#endif;

----------------------------------------------

#ifndef MEDIA_H
#define MEDIA_H
#include <iostream>
#include <string>
using namespace std;

class Media
{
protected:
	string mediaName;
	double mediaLength;
public:
	Media()
	{
		mediaName = "";
		mediaLength = 0;
	}
	Media(string mn, double ml)
	{
		mediaName = mn;
		mediaLength = ml;
	}

	void setMediaName(string mn)
	{
		mediaName = mn;
	}

	void setMediaLength(double ml)
	{
		mediaLength = ml;
	}

	string getMediaName()
	{
		return mediaName;
	}

	double getMediaLength()
	{
		return mediaLength;
	}


};

#endif

----------------------------------------------

#ifndef PLAYER_H
#define PLAYER_H
#include <string>
#include <iostream>
#include <iomanip>
using namespace std;

class Player;
ostream &operator << (ostream &, const Player &);

class Player
{
private:
	string actorName;
	string characterName;
public:
	Player()
	{
		actorName = "";
		characterName = "";
	}

	void setActorName(string an)
	{
		actorName = an;
	}

	void setCharacterName(string cn)
	{
		characterName = cn;
	}

	string getCharacterName()
	{
		return characterName;
	}

	string getActorName()
	{
		return actorName;
	}

	bool operator == (Player &right)
	{
		if (actorName == right.getActorName())
			return true;
		else
			return false;
	}
	bool operator != (Player &right)
	{
		if (actorName != right.getActorName())
			return true;
		else
			return false;
	}
	Player operator = (Player &right)
	{
		actorName = right.getActorName();
		characterName = right.getCharacterName();
		return *this;
	}

	inline friend ostream &operator << (ostream & strm, const Player &obj)
	{
		strm << setw(30) << obj.actorName << "/" << obj.characterName << endl;
		return strm;
	}
};

#endif

----------------------------------------------

//Class declaration for LinkedList.  This class creates a
//template class for a LinkedList that can be appended to,
//have data inserted to or deleted from, and searched for a
//position of a certain piece of data.

#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include <string>
#include <iostream>
using namespace std;

template<class T>
class LinkedList
{
private:
	struct ListNode
	{
		T value;
		struct ListNode *next;
	};

	ListNode *head;
public:
	//Constructor that starts a new linked list.
	LinkedList()
	{
		head = nullptr;
	}

	//Destructor that will destroy the list.
	~LinkedList();

	void appendNode(T);
	void insertNode(T);
	void deleteNode(T);
	void displayList() const;
	T searchList(T);
};

//Function definition for appendNode
//This function takes new information for a new list and
//creates the list with the information entered in the order it
//is recieved.
template <class T>
void LinkedList<T>::appendNode(T newValue)
{
	ListNode *newNode;
	ListNode *nodePtr;
	newNode = new ListNode;
	newNode->value = newValue;
	newNode->next = nullptr;
	if (!head)
		head = newNode;
	else
	{
		nodePtr = head;
		while (nodePtr->next)
			nodePtr = nodePtr->next;
		nodePtr->next = newNode;
	}
}

//Function definition for displayList.
//This function shows the list as it sits.
template <class T>
inline void LinkedList<T>::displayList() const
{
	ListNode *nodePtr;
	nodePtr = head;
	while (nodePtr)
	{
		cout << nodePtr->value;
		nodePtr = nodePtr->next;
	}
}

//Function definition for insertNode.
//This function will create and insert data into an
//existing list.  This function will insert the data
//into the list in a sorted manner.  I.E. if the list
//is 4, 5, 7, 8, then 6 would be inserted in the middle.
template <class T>
void LinkedList<T>::insertNode(T newValue)
{
	ListNode *newNode;
	ListNode *nodePtr;
	ListNode *previousNode = nullptr;
	newNode = new ListNode;
	newNode->value = newValue;
	if (!head)
	{
		head = newNode;
		newNode->next = nullptr;
	}
	else
	{
		nodePtr = head;
		previousNode = nullptr;
		while (nodePtr != nullptr && nodePtr->value < newValue)
		{
			previousNode = nodePtr;
			nodePtr = nodePtr->next;
		}
		if (previousNode == nullptr)
		{
			head = newNode;
			newNode->next = nodePtr;
		}
		else
		{
			previousNode->next = newNode;
			newNode->next = nodePtr;
		}
	}
}

//Function definition for deleteNode.
//This function searches for a specified node
//and deletes it and the place of the node in the
//list so there is not just one huge gap in the list.
template <class T>
void LinkedList<T>::deleteNode(T searchValue)
{
	ListNode *nodePtr;
	ListNode *previousNode = nullptr;
	if (!head)
		return;
	if (head->value == searchValue)
	{
		nodePtr = head->next;
		delete head;
		head = nodePtr;
	}
	else
	{
		nodePtr = head;
		while (nodePtr != nullptr && nodePtr->value != searchValue)
		{
			previousNode = nodePtr;
			nodePtr = nodePtr->next;
		}
		if (nodePtr)
		{
			previousNode->next = nodePtr->next;
			delete nodePtr;
		}
	}
}

//Destructor definition for class LinkedList.
//This destructor destroys the whole list.
template <class T>
LinkedList<T>::~LinkedList()
{
	ListNode *nodePtr;
	ListNode *nextNode;
	nodePtr = head;
	while (nodePtr != nullptr)
	{
		nextNode = nodePtr->next;
		delete nodePtr;
		nodePtr = nextNode;
	}
}

//Function definition for searchList.
//This function searches for a specified data member.
//If the number is found it returns the place of the data.
//If the searched for is not found, then it returns negative 1.
template <class T>
T LinkedList<T>::searchList(T searchValue)
{
	ListNode *nodePtr;
	nodePtr = head;
	while (nodePtr != nullptr)
	{
		if (nodePtr-> value == searchValue)
		{
			searchValue = nodePtr->value;
			return searchValue;
		}
		nodePtr = nodePtr->next;
	}
	return searchValue;
}


#endif