#include "NPC.h"
#include "Main.h"

int NPCState::sNPCStateCount = 0;
int NPCState::sNPCStateLookCount = 0;

NPC::NPC(std::string aName, std::string aByeMessage, NPCState* aInitialState) : mName(aName)
																	,mByeMessage(aByeMessage)
																	,mInitialState(aInitialState)
																	,mCurrentState(aInitialState) 
{
	mInitialState->SetNPC(this);
}

NPC::~NPC()
{
	delete mInitialState;
}

void NPC::Talk()
{
	//Add Score
	if (!mScoreTalked)
	{
		mScoreTalked = true;
		Main::Get()->AddScore(sScoreNewState);
	}

	mCurrentState->Talk();
}

void NPC::ChangeState(NPCState* aState)
{
	mCurrentState = aState;
}

void NPC::InvalidInput()
{
	static int invalidLength = 7;
	static std::string invalid[7] = {
									"What?"
									,"Hmm?"
									,"Pardon?"
									,"Say that again?"
									,"Excuse me?"
									,"Huh?"
									,"What did you say?"
									};

	Main::Get()->mOut.TextQuote(invalid[rand() % invalidLength]);
}

void NPC::SayBye()
{
	Main::Get()->mOut.TextQuote(mByeMessage);
	Main::Get()->mOut.EndLines(1);
	mCurrentState = mInitialState;
	Main::Get()->ClearScreenWait();
}


NPCState::NPCState() : mReferenceCount(0), mScoreTalked(0)
{ ++sNPCStateCount; }

NPCState::~NPCState()
{
	while(!mMoreStates.empty())
	{
		//Makes sure there is only one other state referenceing this one, so only the last reference deletes it
		//Also need to check if there is no states referenceing this one for the initial state
		if (mMoreStates.front()->mReferenceCount == 1 || mMoreStates.front()->mReferenceCount == 0)
		{
			delete mMoreStates.front();
			mMoreStates.front() = 0;
			mMoreStates.pop_front();
		}
		else
		{
			--mMoreStates.front()->mReferenceCount;
			mMoreStates.pop_front();
		}
	}
}

void NPCState::ChangeState(NPC* aNPC, NPCState* aState)
{
	Main::Get()->mSaveLoad.AddAction(Main::Get()->mInput);

	//Add Score
	if (!aState->mScoreTalked)
	{
		mScoreTalked = true;
		Main::Get()->AddScore(sScoreNewState);
	}

	aNPC->ChangeState(aState);
}

void NPCState::AddState(NPCState* aStateToAdd)
{
	//Add state adds a state and also gives it an mNPC. VERY important
	++aStateToAdd->mReferenceCount;
	aStateToAdd->SetNPC(mNPC);
	mMoreStates.push_back(aStateToAdd);
}

void NPCState::PieceSayText(string aText)
{
	Main::Get()->mOut.EndLines(1);
	Main::Get()->mOut.TextQuote(aText);

	if (mNPC->GetInitialState() != this)
	{
		Main::Get()->mOut.EndLines(1);
		Main::Get()->mOut.Text("(talk about something ELSE.)");
	}
}

bool NPCState::PieceCheckStateList()
{
	//Goes through your states, checking if the input is equal to its name. If so, state is now that state
	for (list<NPCState*>::iterator i = mMoreStates.begin(); i != mMoreStates.end(); ++i)
		if (Main::Get()->mParser.First(Main::Get()->mInput, (*i)->GetStateName()))
		{
			ChangeState(mNPC, *i);
			(*i)->Talk();
			return true;
		}

	return false;
}

bool NPCState::PieceCheckElse()
{
	//If you type "else", goes to inital state
	if (mNPC->GetInitialState() != this  &&  Main::Get()->mParser.First(Main::Get()->mInput, "else"))
	{
		ChangeState(mNPC, mNPC->GetInitialState());
		mNPC->GetCurrentState()->Talk();
		return true;
	}

	return false;
}


NPCSayMore::NPCSayMore(std::string aName, std::string aText)
{
	mNPC = 0;
	mName = aName;
	mText = aText;
}

NPCSayMore::NPCSayMore(std::string aText)
{
	//This one is for inital state. Doesn't have name.

	mNPC = 0;
	mText = aText;
}
 
void NPCSayMore::Talk()
{
	PieceSayText(mText);

	do
	{
		Main::Get()->GetInput();

		if (PieceCheckStateList())
			return;

		if (PieceCheckElse())
			return;

		//Only invalid if you aren't leaving
		if (!Main::Get()->mParser.Next(Main::Get()->mInput, "bye", "later", "thank"))
			mNPC->InvalidInput();

	}
	while (!Main::Get()->mParser.Next(Main::Get()->mInput, "bye", "later", "thank"));

	mNPC->SayBye();
}


NPCItemLook::NPCItemLook(bool aDestroy, std::string aName, std::string aText, std::string aLookingText)
{
	++sNPCStateLookCount;
	mGotItem = 0;
	mLookingItem = 0;
	mDestroy = aDestroy;
	mName = aName;
	mLookingText = aLookingText;
	mText = aText;
}

void NPCItemLook::AddLookingItem(Item* aLookingItem)
{
	if (!mLookingItem)
		mLookingItem = aLookingItem;
	else
		Main::Get()->mOut.Text("COULD NOT ADD ITEM, ONE ALREADY EXISTS!");
}

void NPCItemLook::Talk()
{
	//If you are looking for an item
	if (!mGotItem)
	{
		PieceSayText(mLookingText);

		do
		{
			Main::Get()->GetInput();

			if (!mLookingItem)
			{
				Main::Get()->mOut.Text("NO ITEM ATTACHED TO THIS STATE!!");
				return;
			}

			//Check if you have the item needed
			if (Main::Get()->mParser.First(Main::Get()->mInput, mLookingItem->GetName()))
			{
				for (list<Item*>::iterator i = Main::Get()->mInventory.begin(); i != Main::Get()->mInventory.end(); ++i)
					if (Main::Get()->mParser.Next(Main::Get()->mInput, (*i)->GetName()))
					{
						Main::Get()->AddScore(sScoreGiveItem);
						Main::Get()->mSaveLoad.AddAction(Main::Get()->mInput);
						HaveItem();
						
						if (mDestroy)
							Main::Get()->mInventory.erase(i);

						return;
					}

				DontHaveItem();
				continue;
			}

			if (PieceCheckElse())
				return;

			//Only invalid if you aren't leaving
			if (!Main::Get()->mParser.Next(Main::Get()->mInput, "bye", "later", "thank"))
				mNPC->InvalidInput();
		}
		while (!Main::Get()->mParser.Next(Main::Get()->mInput, "bye", "later", "thank"));

		mNPC->SayBye();
	}

	//If you already got the item
	else
	{
		PieceSayText(mText);

		do
		{
			Main::Get()->GetInput();

			if (PieceCheckStateList())
				return;

			if (PieceCheckElse())
				return;

			//Only invalid if you aren't leaving
			if (!Main::Get()->mParser.Next(Main::Get()->mInput, "bye", "later", "thank"))
				mNPC->InvalidInput();
		}
		while (!Main::Get()->mParser.Next(Main::Get()->mInput, "bye", "later", "thank"));

		mNPC->SayBye();
	}
}

void NPCItemLook::DontHaveItem()
{
	static int dontHaveLength = 7;
	static std::string dontHave[7] = {
									"If only someone could give me one."
									,"That's nice, but you don't have one."
									,"Is that a joke?"
									,"Are you dumb? You don't have one!!"
									,"Instead of getting my hopes up, you should try to get one for me."
									,"Haha, if only you had one for me."
									,"Don't kid around like that. You don't have one."
									};

	Main::Get()->mOut.TextQuote(dontHave[rand() % dontHaveLength]);
}

void NPCItemLook::HaveItem()
{
	static int dontHaveLength = 6;
	static std::string dontHave[6] = {
									"Thank you!"
									,"Just what I needed!"
									,"Awesome!"
									,"Wow, I can't believe you just had one on you!"
									,"This should do nicely."
									,"Haha, you are too kind."
									};

	Main::Get()->mOut.TextQuote(dontHave[rand() % dontHaveLength]);

	mGotItem = true;
	Talk();
}


NPCItemGive::NPCItemGive(std::string aName, std::string aText)
{
	mGave = 0;
	mGiveItem = 0;
	mName = aName;
	mText = aText;
}

void NPCItemGive::AddItemToGive(Item* aGiveItem)
{
	if (!mGiveItem)
		mGiveItem = aGiveItem;
	else
		Main::Get()->mOut.Text("COULD NOT ADD ITEM, ONE ALREADY EXISTS!");
}

void NPCItemGive::Talk()
{
	if (!mGave)
	{
		mGave = true;

		//Get the item
		mGiveItem->TakeItemDescriptions();

		Main::Get()->mInventory.push_back(mGiveItem);

		Main::Get()->mIn.WaitForKey();
		Main::Get()->mOut.EndLines(1);
	}

	PieceSayText(mText);

	do
	{
		Main::Get()->GetInput();

		if (PieceCheckStateList())
			return;

		if (PieceCheckElse())
			return;

		//Only invalid if you aren't leaving
		if (!Main::Get()->mParser.Next(Main::Get()->mInput, "bye", "later", "thank"))
			mNPC->InvalidInput();

	}
	while (!Main::Get()->mParser.Next(Main::Get()->mInput, "bye", "later", "thank"));

	mNPC->SayBye();
}