#include "clientballsystem.h"
#include "../common/particletypes.h"
#include <list>

extern void DrawBeamHead(const beam &head, vec3_t vecStart, vec3_t vecDir);
extern void DrawFlareTrail(const std::list <vec3_t> &points, vec3_t end, float width, int sprite, int frame, float beamlength);
const int BEAMPART_SIZE[] = {5,50,100,150,300};

ClientBallSystem::ClientBallSystem(int iEnt,int iType,Vector vecOrigin,Vector vecEnd,int iSpeed,int iFlareA,int iFlareB,int iWidth,int iLength,int iTrail,int iBend):FXSystem(iEnt,iType)
{
	m_iId = iEnt;
	
	m_flStartTime = gEngfuncs.GetClientTime();
	m_vecPos = vecOrigin;
	m_vecStart = vecOrigin;
	m_vecEnd = vecEnd;
	m_iSpeed = iSpeed;
	m_flare.maxlength=iLength;
	m_flare.points.push_front(vecOrigin);
	m_flare.trailframe = 0;
	m_flare.width = iWidth;
	m_flare.head.width = iWidth;
	m_flare.head.flarea = iFlareA;
	m_flare.head.flareb = iFlareB;
	m_flare.trail=iTrail;
	int i=0;
	for(i=0;i<9;i++)
	{
		m_flare.head.flareframe[i] = 0;
	}
	m_flare.head.width = iWidth;

	float flStartAngle = gEngfuncs.pfnRandomFloat(10,20);
	flStartAngle = 2.0*M_PI*flStartAngle/360.0;

	float flSideSpeed = sin(flStartAngle)*iSpeed;	

	
	cl_entity_t *pClient = gEngfuncs.GetEntityByIndex( iEnt );
	vec3_t vecForward,vecRight,vecUp;
	if (pClient)
	{	
		AngleVectors(pClient->angles,vecForward,vecRight,vecUp);
	}
	
	/*
	vec3_t vecForward = m_vecEnd-m_vecStart;
	VectorNormalize(vecForward);
	vec3_t vecRight;
	vecRight.x = vecForward.y*vecForward.z;
	vecRight.y = -0.5 * vecForward.x * vecForward.z;
	vecRight.z = -0.5 * vecForward.x * vecForward.y;
	VectorNormalize(vecRight);		
	vec3_t vecUp = CrossProduct(vecForward,vecRight);
	VectorNormalize(vecUp);
	*/	
	if(iBend == BEND_RIGHT)
	{
		m_vecSideVelocity = vecUp*gEngfuncs.pfnRandomFloat(-1,1)+vecRight*gEngfuncs.pfnRandomFloat(0,1);
		m_vecSideVelocity = m_vecSideVelocity.Normalize() * flSideSpeed;
		//calculate acceleration
		float flHalfDuration = 0.5*(m_vecStart-m_vecEnd).Length()/iSpeed;
		m_vecAcceleration = (1.0/flHalfDuration) * m_vecSideVelocity;
	}
	else if(iBend == BEND_LEFT)
	{
		m_vecSideVelocity = vecUp*gEngfuncs.pfnRandomFloat(-1,1)+vecRight*gEngfuncs.pfnRandomFloat(0,-1);
		m_vecSideVelocity = m_vecSideVelocity.Normalize() * flSideSpeed;
		//calculate acceleration
		float flHalfDuration = 0.5*(m_vecStart-m_vecEnd).Length()/iSpeed;
		m_vecAcceleration = (1.0/flHalfDuration) * m_vecSideVelocity;
	}
	else
	{
		m_vecSideVelocity = vec3_t(0,0,0);
		m_vecAcceleration = vec3_t(0,0,0);		
	}
	
}

void ClientBallSystem::draw()
{
	Vector vecDir = (m_vecEnd-m_vecStart).Normalize();
	DrawBeamHead(m_flare.head, m_vecPos, vecDir);
	
	//TODO: animate head & trail
	/*
	if(fAnimate)
	{	AnimateFlare(iter->head);
		iter->trailframe=getTrailFrame(iter->trail,iter->trailframe);			
	}
	*/
	
	//get traillength
	m_flare.traillength = gHUD.m_Trail.LimitTrailLength(m_flare.points, m_flare.maxlength, m_vecPos);
	float flDist=0;
	if(m_flare.points.begin()!=m_flare.points.end())
	{
		flDist = Length(m_vecPos-*m_flare.points.begin());
	}
	
	int iQuality=gHUD.m_Trail.GetBeamQuality();
	if(flDist>BEAMPART_SIZE[iQuality]*0.1)
	{	m_flare.traillength += flDist;
		m_flare.points.push_front(m_vecPos);						
	}	

	DrawFlareTrail(m_flare.points, m_vecPos, m_flare.width*0.75, m_flare.trail, m_flare.trailframe, m_flare.traillength);

}

void ClientBallSystem::think(float time)
{
	float flTimeDiff = time-m_flStartTime;
	Vector vecDir = flTimeDiff*m_iSpeed*(m_vecEnd-m_vecStart).Normalize();
	if(vecDir.Length() > (m_vecEnd-m_vecStart).Length())
	{
		m_fRemove = true;
	}
	else
	{
		m_vecPos = m_vecStart + vecDir + m_vecSideVelocity * flTimeDiff - 0.5*m_vecAcceleration * flTimeDiff * flTimeDiff;
	}
}