#ifndef GROUNDARMYINFO_H
#define GROUNDARMYINFO_H

#include <map>
#include <vector>

#include "Unit.h"
#include "Point2D.h"
#include "DangerGenerator.h"
#include "VisibilityChecker.h"

#include "MemoryManager/debugNew.h"

namespace ground{
	/**
	 * classe gerant l'ensemble des informations liée au terrain necessaires à la gestion d'une armée.
	 */
	class GroundArmyInfo
	{
	public:
		/**
		 * structure permettant de retourner les information necessaires pour connaitre la
		 * moyenne de temps d'une zone
		 */
		struct VisibilityAreaInfo{
			/**
			 * la moyenne du temps ecoulé depuis la derniere vision d'une zone
			 */
			float average;
			/**
			 * le nombre de cases non visibles
			 */
			int caseCount;
		};
	private:
		/**
		 * compteur servant à stocker le nombre d'appels à la methode update effectué.
		 */
		int updateCounter;
		/**
		 * la largeur de la carte
		 */
		int mapWidth;
		/**
		 * la hauteur de la carte
		 */
		int mapHeight;
		/**
		 * la matrice de visibilitée de la carte. une case a true est une case visible.
		 */
		bool** visibilityMatrix;
		/**
		 * la matrice de danger dynamique
		 */
		float** dynamicDanger;
		/** 
		 * la matrice stockant la date de la derniere fois ou chaque case a été vue.
		 */
		int ** lastUpdateTime;
		/**
		 * vecteur stockant l'ensemble des generateurs de visibilitée (les unités)
		 */
		std::vector<VisibilityArea*> visibilityArea;
		/**
		 * vecteur stockant l'ensemble de generateur de danger (les ennemies)
		 */
		std::map<void*,DangerGenerator*> dangerGenerators;
		/**
		 * le verificateur de visibilitée.
		 */
		VisibilityChecker visibilityChecker;
		/**
		 * methode servant à calculer la matrice de danger dynamique
		 */
		void computeDynamicDanger();
		/**
		 * matrice servant à mettre à jour la matrice de datation des cases
		 */
		void updateTimeMatrix();
	public:
		/**
		 * constructeur par defaut.
		 */
		GroundArmyInfo(void);
		/**
		 * destructeur par defaut.
		 */
		virtual ~GroundArmyInfo(void);
		/**
		 * methode utilisée pour ajouter une unitée de l'armée possedant le GroundArmyInfo
		 * @param unit : l'unité à ajouter.
		 */
		void addUnit(Unit* unit);
		/**
		 * methode utilisée pour supprimer une unité de l'armée possedant le GroundArmyInfo
		 * @param unit : l'unité à supprimer.
		 */
		void removeUnit(Unit* unit);
		/**
		 * methode permettant de tester si une unité est gerée par le GroundArmyInfo.
		 * @param unit : l'unité dont on souhaite tester l'existance.
		 * @return bool : true si l'unité existe dans le GroundArmyInfo, false sinon.
		 */
		bool containUnit(Unit* unit);
		/**
		 * methode utilisée pour supprimer toutes les unités du GroundArmyInfo.
		 */
		void removeAllUnits();
		/**
		 * methode utilisé pour ajouter un generateur de danger au GroundArmyInfo.
		 * @param ennemy : le generateur de danger.
		 */
		void addDangerGenerator(DangerGenerator* ennemy);
		/**
		 * methode utilisée pour enlever un generateur de danger du GroundArmyInfo
		 * @param ennemy : le generateur de danger à supprimer
		 */
		void removeDangerGenerator(DangerGenerator* ennemy);
		/**
		 * methode utilisée pour savoir si le GroundArmyInfo contient un generateur de danger.
		 * @param ennemy : le generateur de danger dont on souhaite tester l'existance
		 * @return bool : true si le generateur de danger est present dans le GroundArmyInfo, false sinon.
		 */
		bool containDangerGenerator(DangerGenerator* ennemy);
		/**
		 * methode utilisée pour enlever tout les generateurs de danger de GroundArmyInfo.
		 */
		void removeAllDangerGenerator();
		/**
		 * methode appelée pour mettre a jour le GroundArmyInfo.
		 * 
		 * Cette methode met a jour toutes les matrices du GroundArmyInfo.
		 */ 
		void update();
		/**
		 * methode servant à configurer le GroundArmyInfo. A appeler au moins une fois avant de faire appel à 
		 * la methode update et au methode get sur les matrices.
		 *
		 * C'est cette methode qui crée les matrices gerée par le GroundArmyInfo et parametre le gestionaire de
		 * visibilité.
		 */
		void setupMapInfo(int width, int height);
		/**
		 * methode permettant de recuperer la matrice de visibilité.
		 * <B>Attention :</B> toute modification sur cette matrice peut entrainer des probleme.
		 * @return bool** : la matrice de visibilité de l'armée
		 */
		bool** getVisibilityMatrix();
		/**
		 * methode permettant de recuperer la largeur de la carte gerée par le GroundArmyInfo.
		 * @return int : la largeur de la carte gerée.
		 */
		int getMapWidth();
		/**
		 * methode permettant de recuperer la hauteur de la carte gerée par le GroundArmyInfo
		 * @return int : la hauteur de la carte gerée.
		 */
		int getMapHeight();
		/**
		 * methode permettant de recuperer la matrice de danger dynamique du GroundArmyInfo.
		 * @return float** : la matrice de danger dynamique
		 */
		float** getDynamicDanger();
		/**
		 * methode permettant de recuperer la matrice de datation des cases
		 * @return int** : la matrice de datation des cases.
		 */
		int** getLastUpdateTime();
		/**
		 * methode permettant de recuperer la moyenne de temps ecoulé pour les cases non visibles
		 * @param center : la position du centre du carré sur lequel est effectué le calcul
		 * @param radius : le "rayon" (en nombre de cases) du carré sur lequel est effectué le calcul
		 * @return GroundArmyInfo::VisibilityAreaInfo : structure stockant les information du calcul effectué.
		 */ 
		GroundArmyInfo::VisibilityAreaInfo getTimeAverage(Point2D center,int radius);

		/**
		 * methode permettant de recuperer la position de la case la plus anciennement vue dans un carré donné
		 * @param center : le centre du carré sur lequel s'effectue la recherche
		 * @param radius : le "rayon" du carré sur lequel s'effectue la recherche
		 * @return Point2D : la position de la cases la plus anciennement vue.
		 */
		Point2D getOldestCase(Point2D center, int radius);

		/**
		 * methode permettant de savoir si une cases est visible ou pas.
		 * @param pos : la position de la case à tester
		 * @return bool : true si la case est visible, false sinon.
		 */
		bool isVisible(const Point2D& pos);

		/**
		 * methode permettant de savoir si une cases est visible ou pas.
		 * @param x : la position x de la case à tester
		 * @param y : la position y de la case à tester
		 * @return bool : true si la case est visible, false sinon.
		 */
		bool isVisible(int x, int y);
		/**
		 * methode permettant de savoir si une cases est visible ou pas.
		 * @param pos : la position de la case à tester
		 * @return bool : true si la case est visible, false sinon.
		 */
		float getDynamicDanger(const Point2D& pos);

		/**
		 * methode permettant de savoir si une cases est visible ou pas.
		 * @param x : la position x de la case à tester
		 * @param y : la position y de la case à tester
		 * @return bool : true si la case est visible, false sinon.
		 */
		float getDynamicDanger(int x, int y);
	};

};// namespace ground;

#include "MemoryManager/debugNewOff.h"

#endif
