/////////////////////////////////////////////////////////////////////
// Boid.h: interface for the Boid class.
//   A Boid object represents one animal in the simulation
// Joel Gompert
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_BOID_H__4A9416A7_C323_4E53_87BB_A1E6DD0D0123__INCLUDED_)
#define AFX_BOID_H__4A9416A7_C323_4E53_87BB_A1E6DD0D0123__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "Vector2D.h"
#include "Entity.h"
#include "Mesh.h"
#include "Terrain.h"
#include "Flock.h"

class Flock;

class Boid : public PhysicalEntity
{
public:

	// Constructor #1
	// creates an individual boid with randomized position,
	// velocity, and orientation.
	Boid(LPDIRECT3DDEVICE9 CreationDevice, Flock* f, Terrain* t);

	// Constructor #2
	// creates an individual boid with specific position and velocity.
	Boid(LPDIRECT3DDEVICE9 CreationDevice, Flock* f, Terrain* t, 
		  const Vector2D& startpos, const Vector2D& startvel);

	///////////////////////////////////////////////////////
	// functions required for PhysicalEntity
	D3DXVECTOR3 GetGroundContactPoint();
	void GetMeshes(Mesh** MeshArray);
	int GetMeshCount();
	unsigned int GetAction(float TimeStep, Msg** SentMsgs);
	unsigned int SendMsg(Msg* RecievedMsg, Msg** SentMsgs);
	///////////////////////////////////////////////////////

	// Destructor
	virtual ~Boid() {}

	// Update_Behaviors needs to be called frequently.  This is where the animal
	// makes decisions and updates its behavior and current acceleration
	void Update_Behaviors();

	// Update needs to be called every frame.  This is where the animal's position
	// is updated and animated
	void Update(float elapsed_time);

	// helper stuff for controlling the rate at which Update_Behaviors() is called
	int behavior_update_delay; // number of frames between behavior updates
	int last_behavior_update;  // number of frames since last behavior update

	// accessor function
	// retrieves the current 2D position of the animal
	Vector2D getPos() const;
	// retrieves the current 2D velocity of the animal
	Vector2D getVel() const;
	float getYaw();
	float getPitch();

	// for some experiments I want the boids in the flock
	// in different groups, we'll call the groups 'teams'
	int			team;

	// a pointer to the terrain object
	Terrain*	terrain;

	///////////////////////////////////
	// Temporary addition for calculating energy expenditure
	D3DXVECTOR3 lastPos;
	float energy;
	void reset();
	float TERRAIN_DRAG_FACTOR;
	float DOWNHILL_TERRAIN_DRAG_FACTOR;
	//////////////////////////////////////////////////////

	// this lets the animal know which flock it is a member of
	Flock* parentFlock;

private:

	// this is the 3D model that appears in the animation for this animal
	Mesh*		m_mesh;
	
	// current 2D acceleration, velocity and position of the animal
	Vector2D	m_2acceleration;
	Vector2D	m_2velocity;
	Vector2D	m_2position;

    float m_yaw;
    float m_pitch;

	// this is scratch space used by each boid
	static list<Boid *> neighborList;
	
	// finds all animals in parentFlock which are to be considered
	// neigbors of this animal and stores this list of animals in neighborList
	void computeNeighbors(); 

	// computes new acceleration for the boid each frame
	// it is called by Update_Behaviors()
	Vector2D navigator(); 

	// These functions provide all of the basis behaviors that are
	// combined to create the overall behavior of the animal
	Vector2D keepDistance();	// keeps comfort space between animals
	Vector2D matchHeading();	// adjusts velocity to match neighbors
	Vector2D steerToCenter();	// maintains flock cohesion
	Vector2D avoidObstacles();	// steer arounds trees
	Vector2D gotoGoal();		// steers animal towards the goal
	//Vector2D avoidCircularObstacle(Vector2D pos, float radius);
	
	// this is the function that combines the basis behaviors
	// it combines valueToAdd with the running total contained in accumulator
	// and returns the magnitude of the resulting value of accumulator
	float accumulate(Vector2D& accumulator, const Vector2D& valueToAdd);
};

#endif // !defined(AFX_BOID_H__4A9416A7_C323_4E53_87BB_A1E6DD0D0123__INCLUDED_)
