#include "g_local.h"


#define Z_RADUISLISTSIZE	2000


void ai_run_melee(edict_t *self);
qboolean FindTarget (edict_t *self);
qboolean SV_StepDirection (edict_t *ent, float yaw, float dist);
void SV_NewChaseDir (edict_t *actor, vec3_t eOrigin, float dist);
#if 0
void z_aiMoveTo(edict_t *self, float dist)
{
	// sanity check
	if (!(self->monsterinfo.scriptState & MSS_AIMOVETO))
		return;
#if 0
	if (!SV_StepDirection (self, self->ideal_yaw, dist))
	{
		SV_NewChaseDir (self, self->monsterinfo.aiMoveTo, dist);
	}
#endif
}
#endif


/*
=============
zSchoolAllVisiable

Creates a list of all entities in the raduis of Z_RADUISLISTSIZE
==============
*/
void zCreateRaduisList (edict_t *self)
{
	edict_t *head, *list;
	vec3_t vec;

	if(self->zRaduisList)
	{ // already created for this think, don't bother doing it again...
		return;
	}

	head = NULL;
	list = self;

	while(1)
	{
		head = findradius(head, self->s.origin, Z_RADUISLISTSIZE);
		if(head == NULL)
		break;

		if(head != self)
		{
			list->zRaduisList = head;
			VectorSubtract(self->s.origin, head->s.origin, vec);
			head->zDistance = VectorLength(vec);
			list = head;
		}
	}

	list->zRaduisList = NULL;
};



/*
=============
zSchoolAllVisiable

Create list of monsters of the same schooling type that are ahead of you. 
==============
*/
int zSchoolAllVisiable (edict_t *self)
{
	int max;
	edict_t *head, *list;

	max = 0;

	zCreateRaduisList(self);
	head = self->zRaduisList;
	list = self;

	while (head)
	{
		if (strcmp(head->classname, self->classname) == 0
			&& (self->monsterinfo.aiflags2 & AI2_SCHOOLING) && (head->health > 0)
			&& (head->zDistance <= self->monsterinfo.zSchoolSightRadius)
			&& (visible(self, head)) && (infront(self, head)) )
		{
			list->zSchoolChain = head;
			list = head;
			max++;
		}
		head = head->zRaduisList;
	}

	list->zSchoolChain = NULL;

	return max;
}




/*
=============
zFindRoamYaw

Check direction moving in does not hit a wall... if it does change direction.
==============
*/
int zFindRoamYaw (edict_t *self, float distcheck)
{
	vec3_t	forward, end, angles;
	trace_t	tr;
	float current = anglemod(self->s.angles[YAW]);

	if (current <= self->ideal_yaw - 1 || current > self->ideal_yaw + 1)
	{
		if(fabs(current - self->ideal_yaw) <= 359.0)
		{
			return 0;
		}
	}

	AngleVectors (self->s.angles, forward, NULL, NULL);
	VectorMA (self->s.origin, distcheck, forward, end);

	tr = gi.trace (self->s.origin, self->mins, self->maxs, end, self, MASK_SOLID);

	if (tr.fraction < 1.0)
	{
		if (random() > 0.75)
		{
			self->ideal_yaw = vectoyaw(forward);
			self->ideal_yaw = self->ideal_yaw + 180;
		}
		else
		{
			float dir = random() > 0.5 ? -45 : 45;
			float maxtrys = 100;

			VectorCopy(self->s.angles, angles);

			while (tr.fraction < 1.0 && maxtrys)
			{
				// blocked, change ideal yaw...
				self->ideal_yaw = vectoyaw(forward);
				self->ideal_yaw = self->ideal_yaw + (random() * dir);
				//   	self->ideal_yaw = self->ideal_yaw + (-45 +  (random() * 90));

				angles[YAW] = anglemod (self->ideal_yaw);
				AngleVectors (angles, forward, NULL, NULL);
				VectorMA (self->s.origin, distcheck, forward, end);

				tr = gi.trace (self->s.origin, self->mins, self->maxs, end, self, MASK_SOLID);
				maxtrys--;
			}
		}

		return 1;
	}

	return 0;
};



/*
=============
zSchoolMonsters

Roaming schooling ai. 
==============
*/
int zSchoolMonsters (edict_t *self, float dist, int runStyle, float *currentSpeed)
{
	int maxInsight;
	int newRunStyle;

	maxInsight = zSchoolAllVisiable(self);

	// If you're not out in front
	if (maxInsight > 0)
	{
		float totalSpeed;
		float totalBearing;
		float distanceToNearest, distanceToLeader, dist;
		edict_t *nearestEntity, *list;
		vec3_t vec;

		totalSpeed = 0;
		totalBearing = 0;
		distanceToNearest = 10000;
		distanceToLeader = 0;
		list = self->zSchoolChain;

		while (list)
		{
			// Gather data on those you see
			totalSpeed += list->speed;
			totalBearing += anglemod(list->s.angles[YAW]);

			VectorSubtract(self->s.origin, list->s.origin, vec);
			dist = VectorLength(vec);

			if (dist < distanceToNearest)
			{
				distanceToNearest = dist;
				nearestEntity = list;
			}

			if (dist > distanceToLeader)
			{
				distanceToLeader = dist;
			}

			list = list->zSchoolChain;
		}

		// Rule 1) Match average speed of those in the list
		self->speed = (totalSpeed / maxInsight) * 1.5;

		// Rule 2) Move towards the perceived center of gravity of the herd
		self->ideal_yaw = totalBearing / maxInsight;

		// check if hitting something
		if (!zFindRoamYaw(self, 10))
		{
			// Rule 3) Maintain a minimum distance from those around you
			if (distanceToNearest <= self->monsterinfo.zSchoolMinimumDistance)
			{
				self->ideal_yaw = nearestEntity->s.angles[YAW];
				self->speed = nearestEntity->speed;
			}
		}

	}
	else
	{	//You are in front, so slow down a bit
		edict_t *head;

		self->speed = (self->speed * self->monsterinfo.zSchoolDecayRate);

		// check direction
		zFindRoamYaw(self, 100);

		// change directions of the monsters following you...
		zCreateRaduisList(self);
		head = self->zRaduisList;

		while (head)
		{
			if (strcmp(head->classname, self->classname) == 0 && (head->health > 0) && 
			(head->zDistance <= self->monsterinfo.zSchoolSightRadius) && (visible(self, head)))

			{
				head->ideal_yaw = self->ideal_yaw + (-20 +  (random() * 40));
			}
			head = head->zRaduisList;
		}
	}

	//  if(self.rm_schoolFlags & 1)
	//  { // check to see is I keep away from "other" entities...
	//    zSchoolCheckForOtherEntities(checkOtherRaduis);
	//  }

	if (self->speed > self->monsterinfo.zSchoolMaxSpeed)
	{
		self->speed = self->monsterinfo.zSchoolMaxSpeed;
	}

	if (self->speed < self->monsterinfo.zSchoolMinSpeed)
	{
		self->speed = self->monsterinfo.zSchoolMinSpeed;
	}

	if (self->speed <= self->monsterinfo.zSpeedStandMax)
	{
		newRunStyle = 0;

		if(newRunStyle != runStyle)
		{
			*currentSpeed = 1;
		}
		else
		{
			*currentSpeed = (self->speed - self->monsterinfo.zSchoolMinSpeed) + 1;
		}
	}
	else if (self->speed <= self->monsterinfo.zSpeedWalkMax)
	{
		newRunStyle = 1;

		if (newRunStyle  != runStyle)
		{
			*currentSpeed = 1;
		}
		else
		{
			*currentSpeed = (self->speed - self->monsterinfo.zSpeedStandMax) + 1;
		}
	}
	else 
	{
		newRunStyle = 2;

		if(newRunStyle  != runStyle)
		{
			*currentSpeed = 1;
		}
		else
		{
			*currentSpeed = (self->speed - self->monsterinfo.zSpeedWalkMax) + 1;
		}
	}

	return newRunStyle;
}



/*
=============
ai_schoolStand

Used for standing around and looking for players / schooling monsters of the same type.
Distance is for slight position adjustments needed by the animations
==============
*/
void ai_schoolStand (edict_t *self, float dist)
{
	float speed;

	if (!(self->monsterinfo.aiflags2 & AI2_SCHOOLING))
	{
		ai_stand(self, dist);
		return;
	}

	// init school var's for this frame
	self->zRaduisList = NULL;

	if (self->enemy || FindTarget(self))
	{
		ai_stand(self, dist);
		return;
	}
	else
	{
		// run schooling routines
		switch (zSchoolMonsters(self, dist, 0, &speed))
		{
		case 1:
			self->monsterinfo.walk (self);
			break;
		case 2:
			self->monsterinfo.run (self);
			break;
		}
	}

	// do the normal stand stuff
	if (dist)
		M_walkmove (self, self->ideal_yaw, dist);
	//	M_walkmove (self, self->ideal_yaw, dist * speed);
}





/*
=============
ai_schoolRun

The monster has an enemy it is trying to kill
=============
*/
void ai_schoolRun (edict_t *self, float dist)
{
	float speed;

	if (!(self->monsterinfo.aiflags2 & AI2_SCHOOLING))
	{
		ai_run(self, dist);
		return;
	}

	// init school var's for this frame
	self->zRaduisList = NULL;

	if (self->enemy || FindTarget(self))
	{
		ai_run(self, dist);
		return;
	}
	else
	{
		// run schooling routines
		switch (zSchoolMonsters(self, dist, 2, &speed))
		{
		case 0:
			self->monsterinfo.stand (self);
			break;
		case 1:
			self->monsterinfo.walk (self);
			break;
		}
	}

	// do the normal run stuff
	SV_StepDirection (self, self->ideal_yaw, dist);
//  SV_StepDirection (self, self->ideal_yaw, dist * speed);
}



/*
=============
ai_schoolWalk

The monster is walking it's beat
=============
*/
void ai_schoolWalk (edict_t *self, float dist)
{
	float speed;

	if (!(self->monsterinfo.aiflags2 & AI2_SCHOOLING))
	{
		ai_walk(self, dist);
		return;
	}

	// init school var's for this frame
	self->zRaduisList = NULL;

	if (self->enemy || FindTarget(self))
	{
		ai_walk(self, dist);
		return;
	}
	else
	{
		// run schooling routines
		switch (zSchoolMonsters(self, dist, 1, &speed))
		{
		case 0:
			self->monsterinfo.stand (self);
			break;
		case 2:
			self->monsterinfo.run (self);
			break;
		}
	}

	// do the normal walk stuff
	SV_StepDirection (self, self->ideal_yaw, dist);
//  SV_StepDirection (self, self->ideal_yaw, dist * speed);
}
  


/*
=============
ai_schoolCharge

Turns towards target and advances
Use this call with a distnace of 0 to replace ai_face
==============
*/
void ai_schoolCharge (edict_t *self, float dist)
{
	/*
	if(!(self->monsterinfo.aiflags & AI_SCHOOLING))
	{
		ai_charge(self, dist);
		return;
	}
	*/
	ai_charge(self, dist);
}