#ifndef UNIT_H
#define UNIT_H

/*
* file Unit.h
* Unit
* 
* 27/01/2006
* Copyright Piquier Production
* 
*/

#include <vector>
#include <math.h>
#include "Point2D.h"

// pour les ennemis
#include "EnnemyUnit.h"
#include "UnitEnumeration.h"

#include "PathFinding.h"

#include "Weapon.h"
#include "Mount.h"
#include "FreeMountManager.h" 

#include "Entity.h"
#include "VisibilityArea.h"

#include "MemoryManager/debugNew.h"
// forward declaration
class UnitAction;
class ActionMove;
class ActionHit;
class ActionWait;
class ActionRotate;
class ActionMount;
class EnnemyUnit;
class GroupAI;


/**
* Classe Unit, hérite de Entity
*/
class Unit :
	public Entity, public ground::VisibilityArea
{
private:

	/**
	 * Groupe de l'unite
	 */
	GroupAI* group;

	/**
	* Pile des actions de l'unité (ce sont des actions "bas niveau")
	*/
	std::vector<UnitAction*> stackAction;

	/**
	* Armure de l'unité
	*/
	unitEnumeration::Armor armor;

	/**
	* Arme de l'unité
	*/
	Weapon * weapon;

	/**
	* Position de l'unité
	*/
	//Position position; -> Dans Entity

	/**
	* Vitesse de l'unité
	*/
	//float speed; -> Dans Entity

	/**
	* états
	*/
	unitEnumeration::UnitState state;


	/**
	* Monture de l'unité
	* vaut null si non montée
	*/
	Mount * mount;

	/**
	* nombre de tick à attendre avant le prochain calcul de réflexes
	*/
	int reflexTicks;

	/**
	* Position de la dernière attaque subit (alors que le groupe de l'unité
	* n'était ni en attaque ni en fuite).
	* Le point2D correspond à un couple de int (et non de float). C'est la 
	* case correspondant à la dernière attaque
	*/
	Point2D lastNotifyAttack;


public:

	/**
	* constructeur de la classe Unit (sans monture)
	* 
	* @param
	*/
	Unit(unitEnumeration::Armor a, Weapon *w, Point2D p);

	/**
	* constructeur de la classe Unit avec monture
	* 
	* @param
	*/
	Unit(unitEnumeration::Armor a, Weapon * w, Point2D p, Mount * m);

	/**
	* constructeur de la classe Unit
	*
	* @param
	*/
	Unit(void);

	/**
	* destructeur de la classe Unit
	*
	* @param
	*/
	~Unit(void);

	/**
	* Fait évoluer l'unité à chaque top du moteur 3D selon la pile d'action de l'unité.
	* Ne réévalue pas la stratégie globale de l'unité.
	* Doit réagir à la vision d'un ennemi.
	*/
	void update();

	/**
	* Permet de donner un chemin à suivre à l'unité
	* Ajoute à la pile d'action de l'unité des objets de type ActionMove
	* Remplis la pile de l'unité de chacun des points du chemin
	* Le premier point ne seras rejoinds effectivement que lors
	* de l'appel à la méthode update
	* 
	* @param
	*/
	void goTo(std::vector<Point2D> path);

	/**
	 * permet à l'unité de calculer un chemin en fonction d'un mode de deplacement.
	 */
	void goTo(const Point2D& destination,ground::pathFinding::PathFinderMode mode = ground::pathFinding::NORMAL);

	/**
	* Fais agir l'unité pour suivre l'entité passé en paramêtre
	* Une réévaluation du chemin est faite à chaque franchissement de case.
	* Chaque franchissement de case est effectué par une ActionMove empilé au dessus
	* de l'ActionFollow.
	* L'unité ne chercheras pas à se rapprocher de l'entité si elle est à moins
	* de dist unité de distance de jeu
	* 
	* @param entity : l'entité que l'on veut suivre
	* @param dist : la distance à laquelle on veut suivre l'entité
	*/
	void follow(Entity *entity, bool loop = true);

	/**
	* Fais agir l'unité pour suivre l'entité passé en paramêtre
	* Une réévaluation du chemin est faite à chaque franchissement de case.
	* Chaque franchissement de case est effectué par une ActionMove empilé au dessus
	* de l'ActionFollow.
	* L'unité va chercher à se rapprocher le plus prêt possible de l'entité (selon son radius)
	* 
	* @param entity : l'entité que l'on veut suivre
	* @param dist : la distance à laquelle on veut suivre l'entité
	*/
	void follow(Entity *entity, int dist, bool loop = true);


	/**
	* Permet de faire monter l'unité sur la monture mount
	* Ajoute une action ActionMount à la pile de l'unité
	* L'unité va d'abord rejoindre la monture si nécéssaire
	* 
	* @param m : la monture à prendre
	*/
	void goAndMount(Mount * m);	

	/**
	* Permet de faire monter l'unité sur la monture mount
	* la monture doit être accessible sans déplacement
	* informe le freeMountManager du changement
	* 
	* @param m : la monture à prendre
	*/
	void mountOn(Mount * m);

	/**
	* Permet de faire descendre l'unité de la monture sur laquelle
	* elle est. Sans effet si elle n'est pas sur une monture
	* Ajoute une action ActionDismount à la pile de l'unité
	* L'unité reste ensuite à côté de la monture
	*
	*/
	void dismount();


	/**
	* Efface la pile d'action (on perd tous)
	* On n'executeras plus jamais les actions qui sont en pile 
	* avant l'appel de wait.
	* Empile l'action wait dans le fond de la pile (si rien n'est empilé, on attend)
	*
	*/
	void wait(int nbTop = -1);

	/**
	* Porte une attaque sur l'unité passée en paramêtre
	* Si l'unité ennemie n'est pas à portée, on se rapproche:
	* Complète la pile d'action de l'unité des opérations nécéssaires.
	* (objet de type ActionMove et ActionHit)
	* 
	*/
	virtual void attack(EnnemyUnit & unit);

	/**
	* Permet de signaler à l'unité quelle est attaquée
	*
	* @param Point2D : position de l'attaquant
	*/
	virtual void notifyAttack(Point2D position);

	/**
	* Efface la pile d'action (on perd tous)
	* en général suivit d'un appel à follow, mount, dismount ou attack
	*
	*/
	void eraseAllAction();

	/**
	* Empile l'action passée en paramêtre dans stackAction
	*/
	void pushAction(UnitAction * a) ;

	/**
	* diminue les points de vie de la monture.
	* sans effets si l'unité est non montée.
	*/
	void decreaseMountHealthPoint(int decreasePoint) ;

	/**
	* diminue les points de vie de l'unité
	* test si l'unité meurt, joue l'action et la met dans l'état DEAD
	*/
	void decreaseHealthPoint(int decraesePoint);

	/**
	*
	*/
	void kill();

	/**
	* Retourne le type de l'unité.
	* A spécifier par les classe héritant..
	*
	*/
	virtual unitEnumeration::UnitType getType()=0;


	/**
	* Retourne l'altitude de l'unité
	* (appel au terrain)
	*/
	float getAltitude();

	/**
	*  Retourne la vitesse de l'unité
	* (test si l'unité est montée ou non et rend
	*  soit la vitesse de l'unité soit la vitesse
	*  de la monture selon)
	* 
	*/
	float getSpeed();

	/**
	 * methode utilisée pour recuperer le rayon de collision de l'unité
	 */
	float getCollisionRadius();

	/**
	 * methode permettant de recuperer le rayon de l'unité (ou celui de la monture si il est monté)
	 * @return float : le rayon de l'unité
	 */
	float getRadius();

	/**
	 * returns the GroupAI in which is the unit
	 * @return GroupAI* : pointer to the GroupAI in which is the unit
	 */
	GroupAI* getGroup();

	/**
	 * methode permettant de definir la position de l'unité (et de son cheval si il est monté)
	 * @param p : la nouvelle position de l'unité.
	 */
	void setPosition(Point2D p);

	/**
	* accesseur en écriture à orientation
	*/
	void setOrientation(float o);


	/**
	* Permet d'obtenir différents statuts : charge, mouvement, fuite, combatPosture
	* 
	* @return UnitState : l'état de l'unité
	* @see Unit::UnitState
	*/
	unitEnumeration::UnitState getState();

	/**
	* Permet de mettre à jour les différents statuts : charge, mouvement, fuite, combatPosture
	* 
	* @see Unit::UnitState
	*/
	void setState(unitEnumeration::UnitState s);

	/**
	* Retourne un pointeur sur l'arme de l'unité
	*
	* @return Weapon : un pointeur sur l'arme de l'unité 
	* @see Unit::Weapon
	*/
	Weapon * getWeapon();

	/**
	* Modifie l'arme de l'unité
	*
	* @param Weapon : un pointeur sur l'arme de l'unité 
	* @see Unit::Weapon
	*/
	void setWeapon(Weapon * w);

	/**
	* Indique a quel groupe appartient l'unite
	*
	* @param GroupAI : groupe auquel a ete ajoute l'unite
	*/
	void setGroupAI(GroupAI* g);

	/**
	* Retourne le type d'armure de l'unité
	*
	* @return Armor : le type de l'armure 
	* @see unitEnumeration::Armor
	*/
	unitEnumeration::Armor getArmorType();

	/**
	* Modifie le type d'armure de l'unité
	*
	* @param Armor : le type de l'armure 
	* @see unitEnumeration::Armor
	*/
	void setArmorType(unitEnumeration::Armor a);

	/**
	* Permet de savoir si l'unité est vivante ou morte
	*/
	bool isDead();

	/**
	* Permet d'obtenir le statut de l'unite: en déplacement ou non
	*/
	bool isMoving();

	/**
	* Permet d'obtenir le statut de l'unite: monté ou non
	*/
	bool isMounted();

	/**
	* Permet d'obtenir le statut de l'unite: en charge ou non
	*/
	bool isCharging();

	/**
	* Permet d'obtenir le statut de l'unite: en fuite ou non
	*/
	bool isFleeing();

	/**
	* Permet d'obtenir le statut de l'unite: en position de combat ou non
	*/
	bool isInCombatPosture();
	
	/**
	* Permet d'obtenir le statut de l'unite: en attente ou non
	*/
	bool isWaiting();

	/**
	 * methode permettant de recuperer  la position de l'unitée pour calculer son cone de vision
	 */
	Point2D & getVisibilityPosition();


	/**
	* Permet d'obtenir la monture de l'unité
	*/
	Mount * getMount();


	float getVisibilityRadius();
	float getHeadOffset();
	float getCutOffAngle();
	float getViewAngle();
	virtual void signalCollision();
	void setAnimation(RenderSystem::RenderableEntity::AnimationType nextAnimation, bool mounted = false);

	/**
	 * methode permettant de charger les caracteristiques d'une unitée à partire du fichier de config
	 * @param type : le type de l'unitée à charger
	 */ 
	void load(std::string type);

	/**
	 * method used to notify the end of execution of an order
	 */
	void notifyEndOrder(std::string s = "");

	/**
	 * methode permettant de savoir si l'unité peut traverser la foret ou pas
	 * @return bool true si l'unité peut traverser la foret, false sinon.
	 */
	bool canCrossForest();

};

#include "MemoryManager/debugNewOff.h"


#endif
