//Copyright (C) 2007 SiegeLord
//See ReadMe.txt and License.txt for copying information

#include "trails.h"

STrail* CreateTrail(SObject* parent, SObject* target_object, SBitmap* bmp, zColor color, float dec_rate)
{
	STrail* trail = new STrail;
	InitObject(trail, parent);

	trail->bmp = bmp;
	trail->color = color;
	trail->dec_rate = dec_rate;
	trail->target_object = target_object;

	return trail;
}

int STrail::Handle()
{
//	bool reform_last = false;


	//prune the end
	while(entries.size() != 0 && entries.back().factor < 0)
	{
		entries.pop_back();
	}

	int size = entries.size();
	FOR1(size)
	{
		STrailEntry* entry = &entries[ii];
		entry->factor -= g_fDelta * dec_rate;
		if(entry->factor >= 0)
		{
			//entry->tcoords1[0] -= t_decrease_u;
			//entry->tcoords2[0] -= t_decrease_v;

			zColor color2 = BlendColors(0x00000000, entry->orig_color, entry->factor);
			entry->color1 = color2;
			entry->color2 = color2;
		}
	}

	if(target_object == 0)
	{
		if(entries.size() == 0)
			dead = true;
		return 0;
	}

	vector2d pos = target_object->GetGlobalPosition();
	if(pos == g_vecZero)
		return 0;

	if(size == 0)
	{
		STrailEntry ent;
		ent.color1 = color;
		ent.color2 = color;
		ent.factor = 1.0f;
		ent.position = pos;
		ent.orig_color = color;
		ent.verts1[0] = pos.x;
		ent.verts1[1] = pos.y;
		ent.verts1[2] = -10;

		ent.verts2[0] = pos.x;
		ent.verts2[1] = pos.y;
		ent.verts2[2] = -10;

		entries.push_front(ent);
	}
	else
	{
		//STrailEntry* entry = &(entries.front());
		vector2d dir = pos - entries.front().position;
//		VecAssign(&dir, pos);
		//VecSubtract(&dir, &entries.front().pos);

		vector2d normal = dir;
		//VecAssign(&normal, &dir);
		//VecMakeNormal(&normal);
		normal.MakeNormal();
		//VecNormalize(&normal);
		normal.Normalize();
		normal = normal * -bmp->h / 2.0f;
		//VecMultiply(&normal, bmp->h / 2.0f);

		if(dir.GetLengthSQ() > 50.0f)
		{
			STrailEntry ent;
			ent.color1 = color;
			ent.color2 = color;
			ent.factor = 1.0f;
			ent.position = pos;
			ent.orig_color = color;

			ent.verts1[0] = ent.position.x + normal.x;
			ent.verts1[1] = ent.position.y + normal.y;
			ent.verts1[2] = -10;

			ent.verts2[0] = ent.position.x - normal.x;
			ent.verts2[1] = ent.position.y - normal.y;
			ent.verts2[2] = -10;

			if(size == 2)//fix the first entry
			{
				STrailEntry* last = &entries[0];

				dir = ent.position - last->position;

				normal.Set(dir.y, -dir.x);
				//VecAssignCoords(&normal, dir.y, -dir.x);
				//VecNormalize(&normal);
				normal = normal * bmp->h / 2.0f;
				//VecMultiply(&normal, bmp->h / 2.0f);

				last->verts1[0] = last->position.x + normal.x;
				last->verts1[1] = last->position.y + normal.y;
				last->verts1[2] = -10;

				last->verts2[0] = last->position.x - normal.x;
				last->verts2[1] = last->position.y - normal.y;
				last->verts2[2] = -10;

				last->tcoords1[0] = 0;
				last->tcoords1[1] = 0;
				last->tcoords2[0] = 0;
				last->tcoords2[1] = 1;
			}

			float t;

			STrailEntry* last = &entries.front();

			//math::vector2d vec = dir;

			//vec.Set(last->verts1[0] - ent.verts1[0], last->verts1[1] - ent.verts1[1]);

			t = dir.GetLength() / bmp->w + last->tcoords1[0];

			//vec.Set(last->verts2[0] - ent.verts2[0], last->verts2[1] - ent.verts2[1]);
			//t2 = t1;//vec.GetLength() / bmp->w + last->tcoords2[0];

			ent.tcoords1[0] = t;
			ent.tcoords1[1] = 0;
			ent.tcoords2[0] = t;
			ent.tcoords2[1] = 1;

			entries.push_front(ent);

			if(entries.size() > 2)//we can alter the previous node too, whee!
			{
				//now we do the cool thing
				//first we get the needed poss
				STrailEntry* entry = &entries[1];

				vector2d cur_prev = entries[2].position - entry->position;
				//VecSubtract(&cur_prev, &entry->pos);

				vector2d cur_next = entries[0].position - entry->position ;
				//VecSubtract(&cur_next, &entry->pos);

				//VecNormalize(&cur_next);
				//VecNormalize(&cur_prev);
				cur_next.Normalize();
				cur_prev.Normalize();

				vector2d bisector = cur_prev + cur_next;//the angle bisector between the two above vectors

				vector2d perp; //we use this to determine the proper direction of the bisector
				perp.x = -cur_next.y;
				perp.y = cur_next.x;

				if(bisector == g_vecZero)//if it is a zero vector, the two vectors are parallel = take the perp
											//vector
					bisector = perp;

				bisector.Normalize();
				//cur_next.Normalize();

				float sn = bisector.DotProduct(cur_next);//get the sine of the angle between the two vectors

				sn = sqrt(1 - sn);

				if(sn < 0.1)//uh oh
				{
					//we are screwed anyway, just make sn some small number
					sn = -0.1f;
				}

				float d = bmp->h / 2 / sn;

				if(perp.DotProduct(bisector) < 0)
					bisector = -bisector;

				bisector *= d;

				entry->verts1[0] = entry->position.x - bisector.x;
				entry->verts1[1] = entry->position.y - bisector.y;
				entry->verts1[2] = -10;

				entry->verts2[0] = entry->position.x + bisector.x;
				entry->verts2[1] = entry->position.y + bisector.y;
				entry->verts2[2] = -10;

				entry->tcoords1[0] = 1;
				entry->tcoords1[1] = 0;
				entry->tcoords2[0] = 1;
				entry->tcoords2[1] = 1;
			}
		}//the check for closeness
		else if(entries.size() > 1)
		{
			//we have failed to add a new entry, move the previous location closer
			float t;

			STrailEntry* last = &entries[1];

			t = dir.GetLength() / bmp->w + last->tcoords1[0];

			STrailEntry* entry = &entries.front();

			entry->verts1[0] = pos.x + normal.x;
			entry->verts1[1] = pos.y + normal.y;
			entry->verts1[2] = -10;

			entry->verts2[0] = pos.x - normal.x;
			entry->verts2[1] = pos.y - normal.y;
			entry->verts2[2] = -10;

			entry->tcoords1[0] = t;
			entry->tcoords1[1] = 0;
			entry->tcoords2[0] = t;
			entry->tcoords2[1] = 1;
		}
	}

	return 0;
}

void STrail::Draw()
{
	DrawModeAdd();
	if(entries.size() > 2)
		DrawQuadStripInterleaved(bmp, entries.size(),
			&entries[0], sizeof(STrailEntry) / 2);
	DrawModeSolid();
}
