//////////////////////////////////////////////////////////////////////
// Flock.cpp: implementation of the Flock class.
//   A flock contains a list of boids
// Joel Gompert
//////////////////////////////////////////////////////////////////////

#include <fstream> // for outputting energy data

#include "Flock.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

Flock::Flock(Vector2D goal)
{
	team_goals[0] = goal;
	// set up some example goal positions
	//team_goals[0] = Vector2D(35,35);
	//team_goals[1] = Vector2D(50,50);
}

Flock::~Flock()
{

}

// calls Update() on all members of the flock
void Flock::Update(float elapsed_time) 
{
	list<Boid *>::iterator i;
	for(i = members.begin(); i != members.end(); i++)
	{
		(*i)->Update(elapsed_time);
	}
}

// adds a boid to the flock
void Flock::AddTo(Boid* boid) 
{
	// there are two steps to this because the flock
	// and the boid must point to each other
	members.push_back(boid); // let the flock know about the boid
	boid->parentFlock = this; // let the boid know which flock it is in
}

// here's a helper function to release the memory of all the boids in the flock
void Flock::cleanup()
{
	while(!members.empty())
	{
		Boid *pBoid = members.front();
		members.pop_front();
		delete pBoid;
	}
}

// removes a boid from the flock and releases the boid's memory
void Flock::RemoveFrom(Boid* boid)
{
	// first we have to find this boid in the list
	list<Boid *>::iterator i;
	for(i = members.begin(); i != members.end(); i++)
	{
		Boid *pBoid = *i;

		if(pBoid == boid)
		{
			// here it is, remove it and delete it
			members.erase(i);
			delete pBoid;
			return;
		}
	}
	return;
}

// gives the average 2D position of the flock
Vector2D Flock::ave2Pos(int team)
{
	Vector2D ave(0,0);
	int count = 0;

	list<Boid *>::iterator i;
	for(i = members.begin(); i != members.end(); i++)
	{
		Boid *pBoid = *i;
		if(team == pBoid->team)
		{
			ave += pBoid->getPos();
			count++;
		}
	}

	return (ave / (float)count);
}

// returns the average 3D position of the flock
D3DXVECTOR3 Flock::ave3Pos(int team)
{
	D3DXVECTOR3 ave(0,0,0);
	int count = 0;

	list<Boid *>::iterator i;
	for(i = members.begin(); i != members.end(); i++)
	{
		Boid *pBoid = *i;
		if(team == pBoid->team)
		{
			Vector2D p = pBoid->getPos();
			ave += D3DXVECTOR3(p.x, p.y, pBoid->terrain->GetHeight(p.x, p.y));
			count++;
		}
	}

	return (ave / (float)count);
}

// gives the average 2D velocity of the flock
Vector2D Flock::aveVel(int team)
{
	Vector2D ave(0,0);
	int count = 0;

	list<Boid *>::iterator i;
	for(i = members.begin(); i != members.end(); i++)
	{
		Boid *pBoid = *i;
		if(team == pBoid->team)
		{
			ave += pBoid->getVel();
			count++;
		}
	}

	return (ave / (float)count);
}

float Flock::aveYaw(int team)
{
	float ave = 0;
	int count = 0;

	list<Boid *>::iterator i;
	for(i = members.begin(); i != members.end(); i++)
	{
		Boid *pBoid = *i;
		if(team == pBoid->team)
		{
			ave += pBoid->getYaw();
			count++;
		}
	}

	return (ave / (float)count);
}

float Flock::avePitch(int team)
{
	float ave = 0;
	int count = 0;

	list<Boid *>::iterator i;
	for(i = members.begin(); i != members.end(); i++)
	{
		Boid *pBoid = *i;
		if(team == pBoid->team)
		{
			ave += pBoid->getPitch();
			count++;
		}
	}

	return (ave / (float)count);
}

///////////////////////////////////////////////////////
// functions required for PhysicalEntity
unsigned int Flock::GetAction(float TimeStep, Msg** SentMsgs)
{
	const float some_error_constant = 10.0f;

	// here we can check if the flock has reached its goal.
	// if the average position of the flock is within some error constant distance from the goal
	//if(aveEnergy() > 350 || (ave2Pos(0) - team_goals[0]).squared_magnitude() < some_error_constant)
	//{
	//	// output the current average energy expended
	//	ofstream fout;
	//	fout.open("energy.dat", ios_base::app);
	//	fout << aveEnergy() << '\t';
	//	

	//	Boid *pBoid = (Boid *)members.front();
	//	
	//	pBoid->terrain->Initialize(40, 40);
	//	pBoid->terrain->NewRandomSmoothTerrain();
	//	pBoid->terrain->NormalizeHeight();

	//	float df = pBoid->TERRAIN_DRAG_FACTOR;
	//	df += 12.5f;
	//	if(df > 75.0f)
	//	{
	//		fout << endl;
	//		df = 0;
	//	}

	//	fout.close();

	//	list<Boid *>::iterator i;
	//	for(i = members.begin(); i != members.end(); i++)
	//	{
	//		pBoid = *i;
	//		pBoid->reset();
	//		pBoid->TERRAIN_DRAG_FACTOR = df;
	//	}
	//}

	return 0;
}
unsigned int Flock::SendMsg(Msg* RecievedMsg, Msg** SentMsgs)
{
	return 0;
}
///////////////////////////////////////////////////////

////////////////////////////////////////////////////////
// Temporary addition for calculating energy expediture
float Flock::aveEnergy()
{
	float ave = 0;
	int count = 0;

	list<Boid *>::iterator i;
	for(i = members.begin(); i != members.end(); i++)
	{
		Boid *pBoid = *i;
		if(0 == pBoid->team)
		{
			ave += pBoid->energy;
			count++;
		}
	}

	return (ave / (float)count);
}
////////////////////////////////////////////////////////