/* ----------------------------------------------------------------------------
** The entity stuffs.
**
** Entities.
** --------------------------------------------------------------------------*/
#ifndef ENTITIES_H
#define ENTITIES_H
#define DEBUG

/* ----------------------------------------------------------------------------
** Includes section
** --------------------------------------------------------------------------*/

// local game includes
#include <common.hpp>
#include <quest.hpp>
#include <inventory.hpp>
#include <texture.hpp>

/* ----------------------------------------------------------------------------
** Structures section
** --------------------------------------------------------------------------*/

/**
 * An entity type enumerator for identifying entities.
 */
enum _TYPE {
	OBJECTT = -2,	/**< an object (Object) */
	STRUCTURET,		/**< a structure (Structures *) */
	PLAYERT,		/**< the player (Player *) */
	NPCT,			/**< an NPC (NPC *) */
	MERCHT,			/**< a merchant (Merchant *) */
	MOBT			/**< A mob (Mob *) */
};

/**
 * An enumerator for entity gender.
 */
enum GENDER{
	MALE,	/**< male */
	FEMALE  /**< female */
};

/**
 * An enumerator for mob types.. 'species'.
 * The subtype of a Mob will affect what texture is used to draw it as well as
 * how the Mob will behave.
 */
enum MOB_SUB {
	MS_RABBIT = 1,	/**< rabbits */
	MS_BIRD,		/**< birds */
	MS_TRIGGER,		/**< triggers, used to cue cutscenes */
	MS_DOOR,		/**< doors, for exiting arenas */
	MS_PAGE			/**< pages, cues page overlay */
};

/**
 * An enumerator for strcture types.
 * The subtype of a structure will affect how it is drawn and how it functions.
 */
enum BUILD_SUB{
	TOWN_HALL = 0,		/**< a town hall */
	HOUSE,				/**< a generic house */
	HOUSE2,				/**< a generic house of a different style */
	HOUSE3,				/**< a generic house of a different style */
	HOUSE4,				/**< a generic house of a different style */
	FOUNTAIN,			/**< a fountain, creates water particles */
	LAMP_POST,			/**< a lamppost, creates light */
	FIRE_PIT,			/**< a firepit, creates fire particles / light */
	STALL_MARKET = 70,	/**< a stall for a merchant */
	STALL_TRADER		/**< TODO */
};

/**
 * A structure for tracking potential trades between the player and a merchant.
 */
struct Trade {
	// the names of the items up for trade
	std::string item[2];
	// how much of each item to trade
	int quantity[2];

	// constructs a trade with the given values
	Trade(int qo, std::string o, int qt, std::string t) {
		item[0] = o;
		item[1] = t;
		quantity[0] = qo;
		quantity[1] = qt;
	}

	// creates an empty trade item
	Trade(void) {
		item[0] = "";
		item[1] = "";
		quantity[0] = 0;
		quantity[1] = 0;
	}
};
typedef struct Trade Trade;

/* ----------------------------------------------------------------------------
** Variables section
** --------------------------------------------------------------------------*/

// the size of the player's inventory
extern const unsigned int PLAYER_INV_SIZE;
// the size of an NPC's inventory
extern const unsigned int NPC_INV_SIZE;

/* ----------------------------------------------------------------------------
** Classes / function prototypes section
** --------------------------------------------------------------------------*/

// a prototype of the world class, necessary for some function prototypes
class World;

/**
 * The particle class, handles a single particle.
 */
class Particles{
public:
	// the location of the particle
	vec2 loc;

	// the width of the particle, in pixels
	float width;

	// the height of the particle, in pixels
	float height;

	// the velocity of the particle, in pixels
	vec2 vel;

	// the color of the particle
	Color color;

	// TODO
	vec2 index;

	// the amount of milliseconds left for the particle to live
	float duration;

	// when true, the particle will move
	bool canMove;

	// TODO
	bool fountain;

	// when true, the particle will be affected by gravity
	bool gravity;

	// when true, draws the particle behind structures
	bool behind;

	// when true, the particle will bounce on impact with ground
	bool bounce;

	// creates a particle with the desired characteristics
	Particles(float x, float y, float w, float h, float vx, float vy, Color c, float d){
		loc = vec2 {x, y};
		vel = vec2 {vx, vy};
		width = w;
		height = h;
		color = c;
		duration = d;
		gravity = true;
		fountain = false;
		behind = false;
		bounce = false;
		index = Texture::getIndex(c);
	}

	// allows the particle to be destroyed
	~Particles(void){}

	// draws the particle
	void draw(void) const {
		glColor3ub(255, 255, 255);
		glBegin(GL_QUADS);
			vec2 tc = vec2 {0.25f * index.x, 0.125f * index.y};
			glTexCoord2f(tc.x, tc.y); glVertex2i(loc.x        , loc.y);
			glTexCoord2f(tc.x, tc.y); glVertex2i(loc.x + width, loc.y);
			glTexCoord2f(tc.x, tc.y); glVertex2i(loc.x + width, loc.y + height);
			glTexCoord2f(tc.x, tc.y); glVertex2i(loc.x        , loc.y + height);
		glEnd();
	}

	// updates a particle
	void update(float _gravity, float ground_y) {
		// handle ground collision
		if (loc.y < ground_y) {
			loc.y = ground_y;

			// handle bounce
			if (bounce) {
				vel.y *= -0.2f;
				vel.x /= 4.0f;
			} else {
				vel = 0.0f;
				canMove = false;
			}
		}

		// handle gravity
		else if (gravity && vel.y > -1.0f) {
			vel.y -= _gravity * deltaTime;
		}
	}

	// returns true if the particle should be killed
	bool kill(float delta) {
		return (duration -= delta) <= 0;
	}
};

/**
 * The entity class.
 * This class contains common functions and variables for all types of
 * entities, i.e. a common structure.
 */
class Entity{
protected:
	// an incrementer for invincibility after a hit
	unsigned int hitCooldown;

	// an incrementer for triggering change of movement with wander()
	int ticksToUse;

	// entity handles an applied hit (sword) if set true
	bool forcedMove;

	// if set false, entity will be destroyed
	bool alive;

	// if not null, the entity will move towards this one
	Entity *followee;

	// TODO
	float targetx;

public:
	// contains the entity's coordinates, in pixels
	vec2 loc;

	// contains the entity's velocity, in pixels
	vec2 vel;

	// the entity's width, in pixels
	float width;

	// the entity's height, in pixels
	float height;

	// a speed multiplier, applied to velocity
	float speed;

	// when true player may interact, and the entity's name will be drawn
	bool near;

	// when true, the entity can move
	bool canMove;

	// tells direction entity is facing
	bool right, left;

	// set to 1 if entity is on the ground, 0 if in the air
	unsigned char ground;

	// the entity's inventory
	Inventory *inv;

	// the entity's health
	float health;

	// the most health the entity can have
	float maxHealth;

	// the type of the entity
	_TYPE type;

	// the entity's subtype, if applicable
	int	subtype;

	// the entity's name, randomly generated on spawn
	char *name;

	// the entity's gender
	GENDER  gender;

	// a texture handler for the entity
	Texturec *tex;

	// TODO
	Texturec *ntex;

	// draws the entity to the screen
	void draw(void);

	// spawns the entity at the given coordinates
	void spawn(float, float);

	// allows the entity to wander, according to what class is deriving this.
	virtual void wander(int){}

	// allows the entity to interact with the player
	virtual void interact(void){}

	// causes the entity to move to the given x coordinate
	void moveTo(float dest_x);

	// causes the entity to follow the one provided
	void follow(Entity *e);

	// causes the entity to take a player-inflicted hit
	void takeHit(unsigned int _health, unsigned int cooldown);

	// handles hits if they've been taken
	void handleHits(void);

	// insures that the entity is dead
	void die(void);

	// checks if the entity is alive
	bool isAlive(void) const;

	// checks if the entity is hit in some way
	bool isHit(void) const;

	// returns true if this entity is near the one provided
	bool isNear(Entity e);

	// returns true if the coordinate is within the entity
	bool isInside(vec2 coord) const;

	// frees memory taken by the entity
	virtual ~Entity(){}
};

class Player : public Entity{
public:
	QuestHandler qh;

	Player();
	~Player();
	void save(void);
	void sspawn(float x,float y);
};

class Structures : public Entity{
public:
	BUILD_SUB bsubtype;
	World *inWorld;
	std::string inside;
	std::string textureLoc;

	Structures();
	~Structures();

	unsigned int spawn(BUILD_SUB, float, float);
};


class NPC : public Entity {
private:
	// the number of the random dialog to use
	unsigned int randDialog;

	unsigned int dialogCount;

public:
	int dialogIndex;

	NPC();
	~NPC();

	void drawThingy(void) const;

	void addAIFunc(bool preload);

	virtual void interact();
	virtual void wander(int);
};

class Merchant : public NPC{
public:
	std::vector<Trade>trade;
	uint currTrade;

	std::string text[4];
	std::string *toSay;
	//greeting
	//accept
	//deny
	//farewell

	void interact();
	Structures *inside;

	Merchant();
	~Merchant();

	void wander(int);
};

class Mob : public Entity{
public:
	bool aggressive;
	double init_y;
	void (*hey)(Mob *callee);
	std::string heyid;

	Mob(int);
	~Mob();

	void wander(int);
};

class Object : public Entity{
private:
	std::string iname;
public:
	std::string pickupDialog;
	bool questObject = false;

	Object();
	Object(std::string in,std::string pd);
	~Object();

	void reloadTexture(void);

	void interact(void);

	bool operator==(const Object &o) {
		return !strcmp(name, o.name) && (loc == o.loc);
	}
};

/**
 * The light structure, used to store light coordinates and color.
 */

class Light{
public:
	vec2 loc;		/**< Light location */
	Color color;	/**< Light color */
	float radius;   /**< Light radius */

	bool belongsTo;
	Entity *following;

	bool flame;
	float fireFlicker;
	vec2 fireLoc;

	Light(vec2 l, Color c, float r){
		loc = l;
		color = c;
		radius = r;

		belongsTo = false;
		following = nullptr;

		flame = false;
	}

	void makeFlame(void){
		flame = true;
	}

	void follow(Entity *f){
		following=f;
		belongsTo = true;
	}
};

constexpr Object *Objectp(Entity *e) {
	return (Object *)e;
}

constexpr NPC *NPCp(Entity *e) {
	return (NPC *)e;
}

constexpr Structures *Structurep(Entity *e) {
	return (Structures *)e;
}

constexpr Mob *Mobp(Entity *e) {
	return (Mob *)e;
}

#endif // ENTITIES_H

/**
ENTITY TYPES
-1 STRUCTURES
|->1 Village
|->2 Castle
|
0 PLAYERS
|->Player
|
1 NPCS
|->0 Base
|->1 Merchant
|
2 MOBS
|->1 Rabbit
|->2 Bird
**/