#ifndef _ROOM_H_
#define _ROOM_H_

#include "Item.h"
#include "NPC.h"
#include <string>
#include <list>

class Room;

struct Exit
{
private:
	std::string mName;
	Room* mToRoom;

public:
	Exit(std::string aName, Room* aToRoom);

	virtual void Move();
	virtual void UpdateExit() {}
	std::string GetName() const { return mName; }
	Room* GetToRoom() const { return mToRoom; }
};

struct ExitIfItem : public Exit
{
private:
	std::list <ItemHolder*> mItems;
	std::string mCantGo;
	std::string mEnableMessage;
	bool mEnabled;

public:
	ExitIfItem(std::string aName, Room* aToRoom, std::string aCantGo, std::string aEnableMessage);

	void AddItemHolder(ItemHolder* aItemHolder);
	void UpdateExit();
	void Move();
	bool GetEnabled() const { return mEnabled; }
};


class Room
{
protected:
	int mId;
	std::string mName;
	std::string mVerboseDes;

	std::string GetDescription();

public:
	Room(std::string aName, std::string aVerboseDes);
	~Room();

	static int sRoomCount;
	static int sPuzzleRoomCount;

	std::list <Item*> mItems;
	std::list <NPC*> mNPCs;
	std::list <Exit*> mExits;
	bool mVisited; //This one is for checking if you have been there for verbose description
	bool mScoreVisited; //This one is for checking if you have been th

	virtual void Move(Exit* aUsedExit);
	void UpdateExits();
	void ShowDescription();
	virtual void Update() {} //For the puzzle rooms
	int GetID() const { return mId; }
	std::string GetName() const { return mName; }
};

class RoomPuzzleTime : public Room
{
	bool mSolved;
	bool mStarted;

	int mTurnsToSolve;
	int mTurnCounter;

	ExitIfItem* mPuzzleExit;
	Item* mItemTakeToStart;
	std::list <Item*> mPuzzleItems;
	std::list <Item*> mPuzzleItemsOrg;
	std::list <Item*> mPuzzleItemsHeld; //This saves the holders' items so you can re load them on RestartRoom

	void RestartRoom();

public:
	RoomPuzzleTime(std::string aName, std::string aVerboseDes, int aTurns, Item* aItemTakeToStart);
	~RoomPuzzleTime() {} //May need to fill this out later

	void AddPuzzleExit(ExitIfItem* aExit);
	void AddPuzzleItem(Item* aItem); //This will include all that can be reset, including the win condition ones (holders)
	void Move(Exit* aUsedExit);
	void SetRestartState(); //This sets the rooms current state to one it will go to when it is restarted
	void Update();
};


static const char mEmptyChar = '.';
static const char mWallChar = '*';
static const char mBoxChar = '@';
static const char mSwitchChar = '!';

class RoomPuzzleBox : public Room
{
	enum BoxPuzzle
	{
		eEmpty,
		eWall,
		eBox,
		eSwitch,
	};

	bool mSolved;
	bool mShowRoomStart;
	ExitIfItem* mPuzzleExit;
	ItemPushable* mBox;
	ItemHolder* mSwitch;

	int* mRoomArray;
	int mMaxX;
	int mMaxY;
	int mBoxPos;
	int mSwitchPos;

	void InitializeBoxPuzzle();
	void InvalidBoxMove(); //The box cant be placed into that position (usually a wall)
	void InvalidPlayerMove(); //The player cant be placed into that position (usuall would need to be on a wall)
	void DontMoveFinishedMessage();
	void ShowRoom();

public:
	RoomPuzzleBox(std::string aName, std::string aVerboseDes, int aMaxX, int aMaxY, int aBoxPos, int aSwitchPos);
	~RoomPuzzleBox();

	void Update();
	void Move(Exit* aUsedExit);
	void AddWall(int aPos);
	void Push(int x, int y);
	void Pull(int x, int y);
	void AddPuzzleExit(ExitIfItem* aExit);
	void AddPuzzleBox(ItemPushable* aBox);
	void AddPuzzleSwitch(ItemHolder* aSwitch);
};

#endif //Close _ROOM_H_