/* 
 * Tactic is the legal property of its developers, whose names are too numerous 
 * to list here.  Please refer to the COPYRIGHT file distributed with this 
 * source distribution. 
 * 
 * This library is free software; you can redistribute it and/or 
 * modify it under the terms of the GNU Lesser General Public 
 * License as published by the Free Software Foundation; either 
 * version 2.1 of the License, or (at your option) any later version. 
 * 
 * This library is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 * Lesser General Public License for more details. 
 * 
 * You should have received a copy of the GNU Lesser General Public 
 * License along with this library; if not, write to the Free Software 
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
 *
 * See README for more informations
 *
 * GroupAI.h
 *
 * This class is used to manage group of units
 *
 * Date 15/02/06
 *
 */

#ifndef GROUPAI_H
#define GROUPAI_H

//Debug
#include "DebugAI.h"

#include <vector>
#include "Point2D.h"
#include "InferenceEngine.h"
#include "GroundArmyInfo.h"
#include "EnnemyManager.h"

// FuzzyNumbers
#include "FNIsNotRegrouping.h"
#include "FuzzyNumber.h"
#include "AllyHealthPoint.h"
#include "Distance.h"
#include "EnnemyHealthPoint.h"
#include "Force.h"
#include "Fresh.h"
#include "NbEnnemis.h"
#include "NbVisibleUnit.h"
#include "Support.h"

// FuzzyValues
#include "FVIsNotRegrouping.h"

#include "FuzzyValue.h"

#include "HPHigh.h"
#include "HPMiddle.h"
#include "HPLow.h"

#include "ClosedZone.h"
#include "FarZone.h"

#include "ForceHigh.h"
#include "ForceMiddle.h"
#include "ForceLow.h"

#include "FreshZone.h"
#include "OutDatedZone.h"

#include "NbEnnemyUnitHigh.h"
#include "NbEnnemyUnitMiddle.h"
#include "NbEnnemyUnitLow.h"

#include "NbVisibleUnitHigh.h"
#include "NbVisibleUnitMiddle.h"
#include "NbVisibleUnitLow.h"
#include "NbEnnemyIsNotZero.h"

#include "GoodSupport.h"
#include "BadSupport.h"

//Result FuzzyValues
#include "FvReconnaissance.h"
#include "FvAttack.h"
#include "FvFlee.h"
#include "FvEvaluation.h"
#include "FvRegroup.h"

// FuzzyRules
#include "FuzzyRule.h"
#include "And.h"
#include "Or.h"
#include "Implication.h"

// Order
#include "Order.h"
#include "OrderReconnaissance.h"
#include "OrderAttack.h"
#include "OrderFlee.h"
#include "OrderEvaluation.h"
#include "OrderRegroup.h"

// State
#include "State.h"
#include "Evaluation.h"
#include "Fight.h"
#include "Flee.h"
#include "Move.h"
#include "Obey.h"
#include "ErrorState.h"

class GroupAI {

private :

	Order* myOrder;						// This order is the current order
	State* myState;						// This state is the current state
	InferenceEngine* myIe;				// An inferenceEngine to evaluate the situation.
	ground::GroundArmyInfo* infoGround;	// The current state of the map
	GroupEnnemy* ennemyGroup;			// Represent the closest group ennemy 
	GroupEnnemy emptyEnnemyGroup;		// Give it when you don't have ennemy group
	EnnemyManager* ennemyManager;
	GroupAI* ally;						// The group which can support us
	std::vector<Unit*> units;

	// FuzzyNumbers
	AllyHealthPoint allyHP;	
	Distance distance;
	EnnemyHealthPoint ennemyHP;
	Force force;
	Fresh fresh;
	NbEnnemis nbEnnemis;
	NbVisibleUnit nbVisibleUnit;
	Support support;
	FNIsNotRegrouping fnIsNotRegrouping;


	// FuzzyValues
	HPHigh allyHPHigh;
	HPMiddle allyHPMiddle;
	HPLow allyHPLow;

	FarZone farZone;
	ClosedZone closedZone;

	HPHigh ennemyHPHigh;
	HPMiddle ennemyHPMiddle;
	HPLow ennemyHPLow;

	ForceHigh forceHigh;
	ForceMiddle forceMiddle;
	ForceLow forceLow;

	FreshZone freshZone;
	OutDatedZone outDatedZone;

	NbEnnemyUnitHigh nbEnnemisUnitHigh;
	NbEnnemyUnitMiddle nbEnnemisUnitMiddle;
	NbEnnemyUnitLow nbEnnemisUnitLow;
	NbEnnemyIsNotZero nbEnnemyIsNotZero;

	NbVisibleUnitHigh nbVisibleUnitHigh;
	NbVisibleUnitMiddle nbVisibleUnitMiddle;
	NbVisibleUnitLow nbVisibleUnitLow;

	GoodSupport goodSupport;
	BadSupport badSupport;

	FVIsNotRegrouping fvIsNotRegrouping;

	// FuzzyRules
	And andOp;
	Or orOp;
	Implication implicationOp;
	FvReconnaissance fvReconnaissance;
	FvAttack fvAttack;
	FvFlee fvFlee;
	FvRegroup fvRegroup;
	FuzzyRule	frReconnaissance01, frReconnaissance02,
				frAttack01, frAttack02, frAttack03, frAttack04,
				frFlee01, frFlee02, frFlee03, frFlee04, frFlee05,
				frRegroup01, frRegroup02, frRegroup03, frRegroup04, frRegroup05;

	// FuzzyRules Vectors
	std::vector<FuzzyRule> evaluationRules, fightRules, fleeRules, moveRules, obeyRules, errorRules;

	// Orders
	OrderEvaluation* orderEvaluation;
	OrderReconnaissance* orderReconnaissance;
	OrderFlee* orderFlee;
	OrderAttack* orderAttack;
	OrderRegroup* orderRegroup;

	// Automate
	Fight* fightState;
	Evaluation* evaluationState;
	Flee* fleeState;
	Move* moveState;
	Obey* obeyState;
	ErrorState* errorState;
	bool obey;

	// Information used by the AI engine

	int numberOfUnits;					// The number of unit in the group
	int hp;								// The current sum of all the units's HP
	int maxHP;							// The sum of the maximum HP for all units
	Point2D pt2d;						// Current position of the group
	Point2D pt2dZone;					// Point you want consider
	std::vector<FuzzyNumber*> vectFN;	// Contains all FuzzyNumbers

public:

	/**
	 * Constructor used for tests
	 * 
	 * @param void
	 *
	 */
	GroupAI(void);

	/**
	 * Constructor
	 * 
	 * @param ie : A pointer associated to the global InferenceEngine
	 *
	 */
	GroupAI(InferenceEngine* ie, EnnemyManager* ennemyManager);
	
	/**
	 * Constructor
	 * 
	 * @param ie : A pointer associated to the global InferenceEngine
	 * @param state : A type of State
	 * @param Order : A type of Order
	 *
	 */
	//GroupAI(InferenceEngine* ie, std::string state, FuzzyValueName order);

	/**
	 * Destructor
	 */
	~GroupAI(void);

	/**
	 * update : change the state and update data and order
	 * 
	 * The next state is returned by the InferenceEngine
	 * 
	 * @return void
	 */
	void update();

	/**
	 * toString : Give the representation of the GroupAI.
	 * 
	 * @param void
	 * 
	 * @return String : The representation of the GroupAI.
	 *  
	 */
	std::string toString();

private :

	/**
	 * updateData : updates the data.
	 * 
	 * Takes all the fuzzyValues of the current state and update them.
	 * 
	 * @return void
	 */
	void updateData();

	/**
	 * updateOrder : updates the order.
	 * 
	 * Updates the current state by calling the inference engine with the
	 * set of FuzzyValues of the current state.
	 * 
	 * @return void
	 */
	void updateOrder();

public :

	/**
	 * setOrder : sets order according to fuzzy value name
	 *
	 * Sets the order according to the fuzzy value name
	 *
	 * @param order : FuzzyValueName corresponding to new order
	 */
	void setOrder(FuzzyValueName order);

	/**
	 * setState : Set the state of the group
	 * 
	 * @param state
	 *
	 * @return void
	 *  
	 */
	void setState(StateName state);

	/**
	 * return a visible free mount in range
	 * 
	 * @param point : the point 
	 */
	Mount* getVisibleFreeMountInRange(Point2D point, float range);

	/**
	 * getState : Get the current state of the group
	 * 
	 * @param void
	 *  
	 */
	State* getState();

	/**
	 * getNumber : Return the number of unit in the Group
	 * 
	 * @param void
	 *
	 * @return int : Return the number of unit in the Group which is in attribute
	 *  
	 */
	int getNumber(void);

	/**
	 * getHP : Return the current sum of all units's HP
	 * 
	 * @param void
	 *
	 * @return int : Return the current sum of all units's HP
	 *  
	 */
	int getHP(void);

	/**
	 * getHP : Return the sum of the maximum HP for all units
	 * 
	 * @param void
	 *
	 * @return int : Return the sum of the maximum HP for all units
	 *  
	 */
	int getHPMax(void);

	/**
	 * setPosition : Get the position of the group
	 * 
	 * @param void
	 *
	 * @return Point2D : the position of the group
	 *  
	 */
	Point2D getPosition(void);

	/**
	 * getForce : Get the sum of all units of the group
	 * 
	 * @param void
	 *
	 * @return int : the sum of all units of the group
	 *  
	 */
	int getForce(void);



	/**
	 * isRegrouped : return true if the group has recently been regrouped
	 *
	 * @return bool : true if the group has recently been regrouped, false otherwise
	 */
	bool isRegrouped();

	/**
	 * setInfoGround : Set the InfoGround
	 * 
	 * @param infoG : The InfoGround for the GroupAI
	 *
	 * @return void
	 *  
	 */
	void setInfoGround(ground::GroundArmyInfo* infoG);

	/**
	 * getZone : Get the zone considered by the group
	 * 
	 * @param void
	 *
	 * @return Point2D
	 *  
	 */
	Point2D getZone(void);

	/**
	 * getOrderType : Get the type of the current Order of the group
	 * 
	 * @param void
	 *
	 * @return FuzzyValueName
	 *  
	 */
	FuzzyValueName getOrderType(void);

	/**
	 * setEnnemyGroup : Set the closest GroupEnnemy
	 * 
	 * @param ennemy : The closest GroupEnnemy
	 *
	 * @return void
	 *  
	 */
	void setGroupEnnemy(GroupEnnemy* ennemy);

	/**
	 * setAlly : Set the group which can support us
	 * 
	 * @param ally
	 *
	 * @return void
	 */
	void setAlly(GroupAI* ally);

	/**
	 * getUnits : get the vecor of units
	 *
	 * @return std::vector<Unit*>* : the vector of units of the group
	 */
	std::vector<Unit*>* getUnits();

	/**
	 * getGroundArmyInfo : get groundArmyInfo of the group's army
	 *
	 * @return ground::GroundArmyInfo* : groundarmyinfo of the army's group
	 */
	ground::GroundArmyInfo* getGroundArmyInfo();

	/**
	 * getEnnemyManager : get the ennemy manager of the army's group
	 *
	 * @return EnnemyManager* : ennemyManager of the army's group
	 */
	EnnemyManager* getEnnemyManager();

	/**
	 * getGroupToAttack : returns pointer to group to attack
	 *
	 * @return GroupEnnemy* : group to attack
	 */
	GroupEnnemy* getGroupToAttack();

	void addUnit(Unit* unit);
	void removeUnit(Unit* unit);
	void removeDeadUnits();
	bool containUnit(Unit* unit);
	void removeAllUnit();

	/**
	 * resetActions : empties the stack of actions of each unit of the group
	 */
	void resetActions();

	/**
	 * notifyEndOrder : 
	 *
	 * @param Unit* : pointer to the unit notifying it has finished its current order
	 */
	void notifyEndOrder(Unit* u);

	/**
	 * sets the group to obey to the army or not
	 *
	 * @param bool : do the group obey? or not...
	 */
	void setObey(bool b);

	/**
	 * obeys : accessor to the obey value
	 *
	 * @return bool : is the group obeying?
	 */
	bool isObeying();
};

#endif
