#include "framedata.h"




MovingObject::MovingObject(Type t):
	hasSpeed(false),type(t),velocity(0.0)
{

}

MovingObject::~MovingObject()
{
}

void MovingObject::addVelocitySample(const QPointF &sample)
{
	velocitySamples << sample;
	if(velocitySamples.size() > 1)
	{
		if(velocitySamples.size() > Options::SpeedSamples)
		{
			velocitySamples.removeFirst();
			
		}
		QPointF v(0.0, 0.0);
		for(int i = 0; i < velocitySamples.size(); i++)
		{
			v += velocitySamples[i];
		}
		v = v / double(velocitySamples.size());
		velocity = sqrt(v.x() * v.x() + v.y() * v.y());
		if(velocity  > 0.0)
		{
				vVec = v / velocity;
		}
		hasSpeed = true;

	}
	else
	{
		hasSpeed = false;
	}
}

void MovingObject::copySamples(const MovingObject &other)
{
	velocitySamples = other.velocitySamples;
}

Target::Target(Type tp):
	MovingObject(tp),size(Unknown),targeded(false),lives(1),inRange(false),selectionValue(0.0),ignoreTimeout(0)
{
}


Target::Target(Size sz, Type tp):
	MovingObject(tp),size(sz),ignoreTimeout(0),miss(false)
{
}

Target::~Target()
{
}

void Target::forget(int shots)
{
	// Bis zum erwarteten Treffer unsichbar schalten (mit Sicherheitsabstand)
	lives --;
	shots--;
	if(!lives || !shots)
	{
		ignoreTimeout = int(timeToKill) + 0;
		targeded = false;
		lives = 1;
	}
}

ShipData::ShipData():
	MovingObject(MovingObject::Ship),last(0),visible(false)
{
}

ShipData::~ShipData()
{
}

void ShipData::clear()
{
	last = 0;
	visible = false;
}

bool ShipData::match(ShipData *l)
{
	last = l;
	if(!last->visible)
	{
		last = 0;
		return false;
	}
	QPointF dist = position - last->position;
	if(abs(dist.x()) < 8 && abs(dist.y()) < 8)
	{
		copySamples(*last);
		return true;
	}
	else
	{
		last = 0;
		return false;
	}
}

SaucerData::SaucerData():
	Target(MovingObject::Saucer),last(0),present(false)
{
}

SaucerData::~SaucerData()
{
}

void SaucerData::clear()
{
	present = false;
	last = 0;
	hasSpeed = false;
	targeded = false;
	lives = 1;
	miss = false;
}

bool SaucerData::match(SaucerData *l)
{
	last = l;
	if(!last->present)
	{
		last = 0;
		return false;
	}
	QPointF dist = position - last->position;
	if(		(abs(dist.x()) < 5.0 && abs(dist.y()) < 5.0) || 
			(abs(dist.x()) > 1018) ||	// 1023.0 - 5.0
			(abs(dist.y()) > 762)		//  767.0 - 5.0
	   )
	{
		copySamples(*last);
		targeded = last->targeded;
		lives = last->lives;
		ignoreTimeout = last->ignoreTimeout;
		if(ignoreTimeout)
		{
			ignoreTimeout--;
		}
		return true;
	}
	else
	{
		last = 0;
		return false;
	}
	
}




ShotData::ShotData(const QPointF &ps):
	MovingObject(MovingObject::Shot),last(0),owner(Unknown)
{
	position = ps;
	eval = 2.0;
}

ShotData::~ShotData()
{
}

bool ShotData::match(ShotData *l)
{
	last = l;
	owner = last->owner;
	copySamples(*last);
	return true;
}

double ShotData::tryMatch(ShotData *l)
{
	last = l;
	if(last->hasSpeed)
	{
		QPointF posEstimate = last->position + last->velocity * last->vVec;
		QPointF vDist = position - posEstimate;
		last = 0;
		eval = sqrt(vDist.x() * vDist.x() + vDist.y() * vDist.y()) / 2.0; // 2 Pixel Abweichung
		return eval;//sqrt(vDist.x() * vDist.x() + vDist.y() * vDist.y()) / 3.0;
	}
	else
	{
		QPointF vDist = position - last->position;
		last = 0;
		eval = abs((sqrt(vDist.x() * vDist.x() + vDist.y() * vDist.y()) -8.0) / 5.0); //5 Pixel Abweichung 
		return eval;//abs((sqrt(vDist.x() * vDist.x() + vDist.y() * vDist.y()) -8.0) / 4.0);
	}
}


void ShotData::print()
{
	qDebug() << "Tracked: " << hasSpeed << "Speed: " << velocity;
	if(last)
	{
		qDebug() << "last: " << last << "Position: " << last->position;
	}
	qDebug() << "this: " << this << "Position: " << position;
	qDebug() << "Eval: " << eval;

}


AsteroidData::AsteroidData(const QPointF &ps, int lk, Target::Size sz):
	Target(sz, MovingObject::Asteroid),look(lk),last(0),willCollide(false)
{
	position = ps;
	color = QColor(Qt::white);
	switch(size)
	{
		case Target::Big:
			lives = 4;
			break;
		case Target::Medium:
			lives = 3;
			break;	
		case Target::Small:
		default:
			lives = 1;
			break;
	}
}

AsteroidData::~AsteroidData()
{
}

bool AsteroidData::match(AsteroidData *l)
{
	
	static double maxSpeed  = 0;
	// Passen die Asteroiden zusammen (Typ und Größe)?
	last = l;
	if(look == last->look && size == last->size)
	{
		QPointF dist = position - last->position;
		if((abs(dist.x()) < 5.0 && abs(dist.y()) < 5.0) || 
				(abs(dist.x()) > 1018) ||	// 1023.0 - 5.0
				(abs(dist.y()) > 762)		//  767.0 - 5.0
			)
		{
			copySamples(*last);
			targeded = last->targeded;
			lives = last->lives;
			//color = last->color;
			ignoreTimeout = last->ignoreTimeout;
			if(ignoreTimeout)
			{
				ignoreTimeout--;
				color = QColor(64, 64, 64);
				miss = last->miss;
				if(miss)
				{
					color = QColor(255, 255 , 0);
				}
			}
			else
			{
				color = QColor(255 , 255, 255);
			}
			return true;
		}
		else
		{
			last = 0;
			return false;
		}
	}
	else
	{
		last = 0;
		return false;
	}
}




FrameData::FrameData():
	deadlyFire(false)
{
}

FrameData::~FrameData()
{
	clear();
}

void FrameData::clear()
{
	shipData.clear();
	saucerData.clear();

	threadList.clear();
	targetList.clear();
	movingObjectList.clear();
	

	for(int i = 0; i < shotDataList.size(); i++)
	{
		delete shotDataList[i];
	}
	shotDataList.clear();

	for(int i = 0; i < asteroidDataList.size(); i++)
	{
		delete asteroidDataList[i];
	}
	asteroidDataList.clear();

	deadlyFire = false;
}


void FrameData::asteroidFound(int x, int y, int lk, int scale)
{
	/*static int minX = 10000.0;
	if(x < minX)
	{
		minX = x;
		qDebug()<<minX;
	}*/
	addAsteroid(new AsteroidData(QPointF((double)x, (double)y), lk, (Target::Size)scale));
}

void FrameData::saucerFound(int x, int y, int scale)
{
	saucerData.position = QPointF((double)x, (double)y);
	saucerData.size = (Target::Size)scale;
	saucerData.present = true;
	targetList << &saucerData;
	movingObjectList << &saucerData;
}

void FrameData::shipFound(int x, int y, int dX, int dY)
{
	shipData.position = QPoint((double)x, (double)y);
	shipData.visible = true;
	double length = sqrt((double)(dX * dX + dY * dY));

	shipData.heading = QPointF((double)dX / length, (double)dY / length);

	shipData.angle = (180.0 / PI) * acos(shipData.heading.x());
	if(shipData.heading.y() < 0.0)
	{
		shipData.angle = 360.0 - shipData.angle; 
	}
	movingObjectList << &shipData;
}

void FrameData::shotFound(int x, int y)
{
	ShotData *sData = new ShotData(QPointF((double)x, (double)y));
	shotDataList << sData;
	movingObjectList << sData;

}

void FrameData::addAsteroid(AsteroidData *as)
{
	asteroidDataList << as;
	targetList << as;
	movingObjectList << as;
}
