/* 
 * 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
 *
 * OrderAttack.cpp
 *
 * ...
 * Date 22/03/06
 *
 */
#include "OrderFlee.h"
#include "GroupPathFinder.h"
#include "GroundMap.h"
#include "Point2D.h"
#include "GroupAI.h"
#include <vector>

OrderFlee::OrderFlee() {}

OrderFlee::OrderFlee(GroupAI* g) : Order(g)
{}

void OrderFlee::execute()
{
	DebugAI::trace('o', "Executing OrderFlee");

	Order::execute();
	ground::GroupPathFinder* pathFinder = new ground::GroupPathFinder(); // used to manage the group of unit with the pathfinder
	ground::GroundMap &map = ground::GroundMap::getInstance(); // used to move the group to specific place
	Point2D placeToFlee, positEnnemies, directionToFlee;
	std::vector<GroupEnnemy*> ennemyGroups;
	float distanceToFlee;

	myGroup->resetActions();

	for (std::vector<Unit*>::iterator it = myGroup->getUnits()->begin(); it != myGroup->getUnits()->end();++it)
	{
		(*it)->notifyEndOrder("OrderFlee");
		pathFinder->addUnit(*it);
	}

	ennemyGroups = myGroup->getEnnemyManager()->getCloseGroups(myGroup->getPosition(), 10);

	/*
	 * Calculating the average position of close ennemy units
	 */
	int nbEnnemies = 0;
	positEnnemies = Point2D(0.f, 0.f);
	placeToFlee = Point2D();

	for (std::vector<GroupEnnemy*>::iterator it = ennemyGroups.begin(); it != ennemyGroups.end(); ++it) {
		for (std::vector<EnnemyUnit*>::iterator jt = (*it)->getUnits().begin();
			jt != (*it)->getUnits().end(); ++jt)
		{
			nbEnnemies ++;
			positEnnemies += (*jt)->getPosition();
		}
	}
	if (nbEnnemies > 0) { // the case nbEnnemies = 0 should not happen.
		positEnnemies *= 1.0f / nbEnnemies;

		/*
		 * Position of Ennemy is B
		 * Our position is A
		 *
		 * Distance to flee is a fixed value
		 * Direction to flee is the normalized vector BA
		 * Position to flee to is A + (direction * distance)
		 */
		distanceToFlee = 10.0f;

		directionToFlee = (myGroup->getPosition()- positEnnemies);
		directionToFlee.normalise();

		placeToFlee = myGroup->getPosition();
		placeToFlee += (directionToFlee * distanceToFlee);

		float angle = myGroup->getPosition().getAngle(placeToFlee);
		float maxX = map.getWidth();
		float maxY = map.getHeight();

		while (placeToFlee.getX() < 0.f || placeToFlee.getX() > maxX
			 ||placeToFlee.getY() < 0.f || placeToFlee.getY() > maxY)
		{
			angle += 20.f;
			directionToFlee.setX(cos(angle));
			directionToFlee.setY(sin(angle));
			placeToFlee = myGroup->getPosition();
			placeToFlee += (directionToFlee * distanceToFlee);
		}


		map.moveGroupTo(*pathFinder, placeToFlee);
	}

	DebugAI::trace('o', "OrderFlee Executed");
}

OrderFlee::~OrderFlee() {}

FuzzyValueName OrderFlee::getType()
{
	return ORDER_FLEE;
}