// game.h
#ifndef GAME_H
#define GAME_H
#include <vector>

enum struct characterType
{
	object,
	humanplayer,
	enemy,
	editing
};

enum struct movementType
{
	upNoCheck,
	downNoCheck,
	leftNoCheck,
	rightNoCheck,
	up,
	down,
	left,
	right,
	jump,
	wait
};

enum struct moverType
{
	pusher,
	pushed
};

enum struct modeType
{
	play,
	record
};

// not yet used
enum struct layerType
{
	background,
	mid,
	foreground
};

struct movementArray
{
	movementType moveType;	// type of move
	unsigned int repNumber;	// how many times to repeat this move?
};


class DrawScreen;

class Game
{
	
public:
	Game();
	~Game();

	// game qualities
	static void initialiseGame(std::vector<std::vector<Game>> & obj, DrawScreen &Draw);

	// character qualities
	inline void setCharacter(const characterType & i) { character = i; }
	inline void setBornCharacter(const characterType & i) { setCharacter(bornCharacter = i); }
	inline void setMovement(const movementType & i) { movement = i; }
	inline void setMoverType(const moverType & i) { mover = i; }
	inline void setLayer(const layerType & i) { layer = i; }
	inline void setMode(const modeType & i) { mode = i; }
	inline void setSequenceNumber(const unsigned int & i) { sequenceNumber = i; }
	inline void setSequenceRep(const unsigned int & i) { sequenceRep = i; }
	inline void setNoTurn(const bool & i) { hasNoTurn = i; }
	inline void setPlayerNum(const int & i) { playerNum = i; }
	inline characterType getCharacter() const { return character; }
	inline characterType getBornCharacter() const { return bornCharacter; }
	inline movementType getMovement() const { return movement; }
	inline moverType getMoverType() const { return mover; }
	inline layerType getLayer() const { return layer; }
	inline modeType getMode() const { return mode; }
	inline unsigned int getSequenceNumber() const { return sequenceNumber; }
	inline unsigned int getSequenceRep() const { return sequenceRep; }
	inline bool getNoTurn() const { return hasNoTurn; }
	inline int getPlayerNum() const {return playerNum; }
	
	// character morphing qualities
	void changeCharacter(const int & key);
	bool becomeCharacter(std::vector<std::vector<Game>> & obj, DrawScreen &drawGame, const int &currentSection, const int &objNum);
	void createCharacter(std::vector<std::vector<Game>> & obj, DrawScreen &drawGame, const int &currentSection, const int &objNum);
	void clearCharacter(std::vector<std::vector<Game>> & obj, DrawScreen &Draw, const int &currentSection, const int &objNum);
	bool changePlayer(std::vector<std::vector<Game>> & obj, DrawScreen &Draw, const int &currentSection, const int &objNum);

	// character position on board
	inline void setPosY(const int &y) { posY = y; }
	inline void setPosX(const int &x) { posX = x; }
	inline void setMoveDistance(const int &i) { moveDistance = i; }
	inline int getPosY() const { return posY; }
	inline int getPosX() const { return posX; }
	inline int getMoveDistance() const { return moveDistance; }
			
	// movement methods
	void moveUp(std::vector<std::vector<Game>> & obj, DrawScreen &drawGame, const int &currentSection, const int &objNum);
	void moveDown(std::vector<std::vector<Game>> & obj, DrawScreen &drawGame, const int &currentSection, const int &objNum);
	void moveLeft(std::vector<std::vector<Game>> & obj, DrawScreen &drawGame, const int &currentSection, const int &objNum);
	void moveRight(std::vector<std::vector<Game>> & obj, DrawScreen &drawGame, const int &currentSection, const int &objNum);
	void moveInitiateJump(std::vector<std::vector<Game>> & obj, DrawScreen &drawGame, const int &currentSection, const int &objNum);
	bool moveJump(std::vector<std::vector<Game>> & obj, DrawScreen &drawGame, const int &currentSection, const int &objNum);
	void moveGravity(std::vector<std::vector<Game>> & obj, DrawScreen &drawGame, const int &currentSection, const int &objNum);
	bool moveObj(std::vector<std::vector<Game>> & obj, DrawScreen &Draw, const int &currentSection, const int &objNum, const int &direction);

	// jumping information
	inline void setJumpPos(const int &i) { jumpPos = i; }	// set position within jump
	inline void setMaxJump(const int &i) { maxJump = i; }	// height of jump
	inline int getJumpPos() const { return jumpPos; }		//
	inline int getMaxJump() const { return maxJump; }		//

	// object control methods
	int collision(std::vector<std::vector<Game>> & obj, DrawScreen &drawGame, const int &currentSection, const int &objNum, const int &angleToCheck);
	int moveCharacter(std::vector<std::vector<Game>> & obj, DrawScreen &drawGame, const int &currentSection, const int &objNum);
	void keyboardCommand(std::vector<std::vector<Game>> & obj, DrawScreen &Draw, const int &currentSection, const int &objNum);
	void objSize(std::vector<std::vector<Game>> & obj, const int &currentSection, const int &objNum1, std::vector<int> * ybottom, std::vector<int> * xleft, std::vector<int> * ytop, std::vector<int> * xright);
	void moveNow(std::vector<std::vector<Game>> & obj, DrawScreen &Draw, const int &currentSection, const int &objNum, const int &direction, const int &distance);
	void moveSection(std::vector<std::vector<Game>> & obj, DrawScreen &Draw, const int &currentSection, const int &objNum, const int &direction, const int &distance);
	void recordMovement();
	void toggleEdit(DrawScreen &Draw);
	void playMode(std::vector<std::vector<Game>> & obj, DrawScreen  &Draw, const int &currentSection, const int &objNum);
	void playMovement(std::vector<std::vector<Game>> & obj, DrawScreen  &Draw, const int &currentSection, const int &objNum);

	// debug information
	void printStats(std::vector<std::vector<Game>> & obj, DrawScreen &Draw, const int &currentSection, const int &objNum);
		
private:

	// personal character data
	characterType bornCharacter =
	characterType::humanplayer;			// innate character
	characterType character =
	characterType::humanplayer;			// current playing character
	movementType movement =
	movementType::wait;					// current enemy movement
	movementType lastMove;				// current enemy movement
	moverType mover;						// can the object move other objects?
	layerType layer;						// bkgrounnd, foreground...
	modeType mode = modeType::play;		// eg. play, edit, record...
	std::vector<movementArray> moveSeq;	// movement sequence for objects & enemies

	// character qualities
	int posY = 5;						// y location on board
	int posX = 10;						// x location on board
	int playerNum = 0;					// what player number
	int jumpPos = 0;						// jump
	int maxJump = 10;					// height of jump
	unsigned int moveDistance = 1;		// distance character moves each turn
	unsigned int sequenceNumber = 0;		// sequence move number
	unsigned int sequenceRep = 0;			// sequence repetition number
	bool hasNoTurn = false;				// needed for section changing...
};

#endif // Game_H 
