#ifndef ZONE_MANAGER
#define ZONE_MANAGER

#include "stdlib.h"
#include <cmath>
#include <map>

#include "GroundMap.h"
#include "Case.h"
#include "ZoneDanger.h"
#include "ZoneStrong.h"
#include "AxeNatural.h"
#include "ZoneForest.h"
#include "MatrixPathFinder.h"

#include "MemoryManager/debugNew.h"


namespace ground{
	#define ARCHER_TIR_DISTANCE				6.0f	//la distance de tir des archer : TODO : utilisé autre valeur plus tard!!!!


	/**
	 *	La classe permettant de calculer puis d'avoir accès au différente zone du terrain : les zone de danger,
	 * les place forte et axe naturel de déplacement.
	 *	Cette classe implémente un pattern SINGLETON.
	 */
	class ZoneManager
	{
	private:

		/**
		 * L'unique instance du ZoneManager dans le jeu
		 */
		static ZoneManager* zoneManager;

		/**
		 * Le constructeur par défaut privé
		 */
		ZoneManager();

		/**
		 * destructeur privé
		 */
		~ZoneManager();

		/**
		 *	La map contenant les zones fortes.
		 * Les données sont stockées ainsi : map<id_de_la_zone,address_de_la_zone>.
		 */
		std::map<int,ZoneStrong*> strongZone;

		/**
		 *	La map contenant les axes naturels.
		 * Les données sont stockées ainsi : map<id_de_l'axe,address_de_l'axe>.
		 */
		std::map<int,AxeNatural*> naturalAxe;

		/**
		 *	La map contenant les forêts.
		 * Les données sont stockées ainsi : map<id_de_l'axe,address_de_la_foret>.
		 */
		std::map<int,ZoneForest*> forestZone;

		/**
		 * Indique si des zone on déjà été calculer(pour effacer la mémoire en cas de nouveau calcul de zone)
		 */
		bool zoneHaveBeenComputed;

		/**
		 * Permet de rendre la mémoire utilisé par les zones
		 */
		void unloadComputedZone();

		/**
		 *	Permet d'ajouter une contribution d'axe naturel au case voisine d'une certain case de coordonée (i,j) sur
		 * une certaine distance avec atténuation.
		 *
		 * @param i : coordonnée x de la case géneratrice
		 * @param j : coordonnée y de la case géneratrice
		 * @param k : rayon d'influence
		 * @param contrib : contribution maximum
		 */
		void addNaturalAxeContribution(int i, int j, int k, float contrib);

		/**
		 *	Permet d'attribuer un numéro de zone forte au case adjacente appartenant a la même zone forte.
		 * Cette fonction est récursive et ajoute les case avec un algorithme en 4-connexité.
		 *
		 * @pre : les case non franchissable ne doive pas avoir de valeur de zoneForte sinon des cases non franchissable
		 * se retrouverons dans la zone.
		 * @post : z->cases = z->cases@pre + c;
		 *
		 * @param c : la case de départ de construction de la zone forte
		 * @param z : la zone auquel on ajoute les cases
		 */
		void rec_computeStrongZoneFromACase(Case*c, ZoneStrong*z);

		/**
		 *	Permet d'attribuer un numéro d'axe naturel aux cases adjacentes appartenant au même axe naturel.
		 * Cette fonction est récursive et ajoute les case avec un algorithme en 4-connexité.
		 *
		 * @pre : les case non franchissable ne doive pas avoir de valeur d'axe naturel sinon des cases non franchissable
		 * se retrouverons dans l'axe.
		 * @post : z->cases = z->cases@pre + c;
		 *
		 * @param c : la case de départ de construction de l'axe naturel
		 * @param z : l'axe auquel on ajoute les cases
		 */
		void rec_computeNaturalAxeFromACase(Case*c, AxeNatural*z);


		/**
		 *	Permet d'attribuer un numéro de foret aux cases adjacentes appartenant a la meme foret.
		 * Cette fonction est récursive et ajoute les cases avec un algorithme en 4-connexité.
		 *
		 * @post : z->cases = z->cases@pre + c;
		 *
		 * @param c : la case de départ de construction de la foret
		 * @param f : la foret auquel on ajoute les cases
		 */
		void rec_computeForestZoneFromACase(Case*c, ZoneForest*f);

	protected:

		/**
		 *	La map sur lequel les zone ont été calculé
		 */
		GroundMap* map;

		/**
		 * Permet de savoir le nombre de case adjacente de type forêt près de cette case(celleci y comprit)
		 *
		 * @param i : coordonnée i de la case
		 * @param j : coordonnée j de la case
		 * @return le nombre de cases.
		 */
		int getNextWoodCount(int i, int j);

	public:

		/**
		 * Permet d'avoir accès à l'unique instance du ZoneManager
		 *
		 * @return l'unique ZoneManager
		 */
		static ZoneManager& getInstance();

		/**
		 *	Permet de détruire l'unique instance du ZoneManager
		 *
		 * @return l'unique ZoneManager
		 */
		static void destroy();

		/**
		 * Permet de calculer les zone et axe pour la carte suivante :
		 *	- zone de danger
		 *	- zone forte(avantageuse)
		 *	- axe naturel de déplacement
		 * Les données des cases du terrain concernant ces zones&axes sont mis a jour.
		 *
		 * @param ground : le terrain dont on doit calculer les zone et axes.
		 */
		void computeZoneAxe(GroundMap& ground);

		/**
		 * Permet de récupérer la map des zone forte.
		 * Les données sont stocké ainsi : map<id_de_la_zone,address_de_la_zone>.
		 *
		 * @return la map de zone forte.
		 */
		const std::map<int,ZoneStrong*>& getZoneStrong();

		/**
		 * Permet de récupérer la map des axe naturel.
		 * Les données sont stocké ainsi : map<id_de_l'axe,address_de_l'axe>.
		 *
		 * @return la map d'axe naturel.
		 */
		const std::map<int,AxeNatural*>& getAxeNatural();

		/**
		 * Permet de récupérer la map les forets.
		 * Les données sont stocké ainsi : map<id_de_la_foret,address_de_la_foret>.
		 *
		 * @return la map de foret.
		 */
		const std::map<int,ZoneForest*>& getZoneForest();

		/**
		 * essaye de charger les information de la map depuis un fichier. si la methode ne trouve pas
		 * le fichier sur le disque, elle calcule les zones.
		 * @param ground : le terrain sur lequel est effectué le chargement
		 * @param file : le chemin du fichier a partir du quel sera effectué le chargement. (Attention,
		 * la methode ajoute l'extention .info au nom du fichier.)
		 */
		void loadZoneAxe(GroundMap& ground, std::string file);
	};

};

#include "MemoryManager/debugNewOff.h"


#endif
