/**
 * An Object that moves following physical rules
 * @author vanitas
 *
 */
public class MovingObject
{
	//Attributes
	protected float	velocity, 			//whats the velocity of the object? 0 or 1
	x, 					//x position of the object
	y, 					//y position of the object
	speedX, 			//x component of the speedvector
	speedY,				//y component (eg. x=2,y=2 => object is flying to the right corner with a speed of 2.7
	maxSpeed,			//Maximal speed of the object
	rotation,			//totation of the object (0° <=> object points towards the top of the screen)
	thrust;				//Power of acceleration
	protected int team;					//Which team is the object in? 0 = nature
	protected Shape shape;				//Contains the vertices for the shape

	//Constructors (Lol there are none)

	/**
	 * moves the Object one frame
	 * @param delta
	 * @param keepOnScreen
	 */
	public void move(float delta, boolean keepOnScreen)
	{
		//Set new x and y locations calculated from old location and
		//Speedvector
		this.setX(this.getX()+this.getSpeedX()*delta*0.2f);
		this.setY(this.getY()+this.getSpeedY()*delta*0.2f);
		//Eventually keep the object on the screen if it leaves at the borders
		if(keepOnScreen) this.keepOnScreen();
	}
	/**
	 * Rotates the Object to the right
	 * @param delta
	 */
	public void turnRight(int delta)
	{
		this.setRotation(this.getRotation() + 0.35f * delta);
	}
	/**
	 * Rotates the Object to the left
	 * @param delta
	 */
	public void turnLeft(int delta)
	{
		this.setRotation(this.getRotation() - 0.35f * delta);
	}
	/**
	 * Let this Object follow another Object
	 * @param x
	 */
	public void follow(MovingObject x) //TODO Test this
	{
		float xOther = x.getX();
		float yOther = x.getY();
		float hypot = (float) Math.hypot(Math.abs(this.x-xOther), Math.abs(this.y-yOther));
		//Set Rotation
		float rot;
		if(this.x<xOther) rot = (float) -(Math.toDegrees((Math.PI/2)-Math.asin((yOther-this.getY())/hypot)));
		else rot = (float) (Math.toDegrees((Math.PI/2)-Math.asin((yOther-this.getY())/hypot)));
		//Catch NaN (if rot is Infinity)
		if(!Float.isNaN(rot)) this.setRotation(rot);
		else this.setRotation(0);
		this.setVelocity(1);
	}
	/**
	 * Calculate the SpeedVector for the Object.
	 */
	public void accelerate()
	{
		this.speedX = (float) (Math.sin(Math.toRadians(this.getRotation()))*this.getThrust()*this.getVelocity()+this.getSpeedX());
		this.speedY = (float) (Math.cos(Math.toRadians(this.getRotation()))*this.getThrust()*this.getVelocity()+this.getSpeedY());

		double actualSpeed = Math.sqrt(Math.pow(this.getSpeedX(),2)+Math.pow(this.getSpeedY(),2));
		if(actualSpeed>this.getMaxSpeed())
		{
			double fac = actualSpeed/this.getMaxSpeed();
			this.speedX = (float) (this.speedX/fac);
			this.speedY = (float) (this.speedY/fac);
		}
	}
	/**
	 * Keep the Object on the screen if it leaves to the borders
	 */
	public void keepOnScreen()
	{
		this.x = this.x%SpaceSpiel.frameSizeX;
		this.y = this.y%SpaceSpiel.frameSizeY;
		if(this.x<0) this.x = SpaceSpiel.frameSizeX+this.x;
		if(this.y<0) this.y = SpaceSpiel.frameSizeY+this.y;
	}
	/**
	 * This Method fires (In this class its only there, to be overwritten)
	 * @param delta
	 */
	public void fire(float delta)
	{
		//Let me empty
	}
	
	/**
	 * Checks, if this Object collides with another TODO: This is not accurate, maybe there's a fix for this
	 * @param otherObject The Object, this Object should check for collision with
	 * @return the Object if collided, else null
	 * @author lil, Oooh, vanitas
	 */
	public MovingObject intersect(MovingObject otherObject)
	{
		//Extract the shapes of the objects
		Shape one = this.getShape();
		Shape other = otherObject.getShape();
		//Go through all the edges of the shape of THIS object
		for(int i = 0; i<one.getLength(); i++)
		{
			int iinc = (i+1)%one.getLength();
			//Go through all the edges of otherObject's shape
			for(int j = 0; j< other.getLength(); j++)
			{
				int jinc = (j+1)%other.getLength();
				//Calculate all the start and end-points of the edges 
				//(1-2=>current edge of THIS shape, 3-4 => current edge of otherObject's shape)
				double x1 = this.getX()+MathShit.rotateX(Math.toRadians(this.getRotation()), one.getX(i), one.getY(i))*one.getSize();
				double x2 = this.getX()+MathShit.rotateX(Math.toRadians(this.getRotation()), one.getX(iinc), one.getY(iinc))*one.getSize();
				double x3 = otherObject.getX()+MathShit.rotateX(Math.toRadians(otherObject.getRotation()), other.getX(j), other.getY(j))*other.getSize();
				double x4 = otherObject.getX()+MathShit.rotateX(Math.toRadians(otherObject.getRotation()), other.getX(jinc), other.getY(jinc))*other.getSize();
				double y1 = this.getY()+MathShit.rotateY(Math.toRadians(this.getRotation()), one.getX(i), one.getY(i))*one.getSize();
				double y2 = this.getY()+MathShit.rotateY(Math.toRadians(this.getRotation()), one.getX(iinc), one.getY(iinc))*one.getSize();
				double y3 = otherObject.getY()+MathShit.rotateY(Math.toRadians(otherObject.getRotation()), other.getX(j), other.getY(j))*other.getSize();
				double y4 = otherObject.getY()+MathShit.rotateY(Math.toRadians(otherObject.getRotation()), other.getX(jinc), other.getY(jinc))*other.getSize();
				// Zaehler
				double zx = (x1 * y2 - y1 * x2)*(x3-x4) - (x1 - x2) * (x3 * y4 - y3 * x4);
				double zy = (x1 * y2 - y1 * x2)*(y3-y4) - (y1 - y2) * (x3 * y4 - y3 * x4);

				// Nenner
				double n = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);

				// Koordinaten des Schnittpunktes
				double x = zx/n;
				double y = zy/n;

				// Vielleicht ist bei der Division durch n etwas schief gelaufen
				if (Double.isNaN(x)& Double.isNaN(y))
				{
					System.out.println("NaN");
				}
				// Test ob der Schnittpunkt auf den angebenen Strecken liegt oder außerhalb.
				if (Math.abs((x - x1) / (x2 - x1)) > 1 || Math.abs((x - x3) / (x4 - x3)) > 1 || Math.abs((y - y1) / (y2 - y1)) > 1 || Math.abs((y - y3) / (y4 - y3)) > 1 )
				{
					//System.out.println("Alles ok");
				}
				else return otherObject;
			}
		}
		return null;
	}
	
	/**
	 * Placeholder for children. Children should overwrite this method to handle the case of a collision
	 * @param o The Object THIS collided with
	 */
	public void processCollision(MovingObject o)
	{
		
	}

	//Getters and setters 
	public float getVelocity()
	{
		return this.velocity;
	}
	public void setVelocity(float v)
	{
		this.velocity = v;
	}
	public float getX()
	{
		return this.x;
	}
	public void setX(float x)
	{
		this.x = x;
	}
	public float getY()
	{
		return y;
	}
	public void setY(float y)
	{
		this.y = y;
	}
	public float getSpeedX()
	{
		return speedX;
	}
	public void setSpeedX(float speedX)
	{
		this.speedX = speedX;
	}
	public float getSpeedY()
	{
		return speedY;
	}
	public void setSpeedY(float speedY)
	{
		this.speedY = speedY;
	}
	public float getMaxSpeed()
	{
		return maxSpeed;
	}
	public void setMaxSpeed(float maxSpeed)
	{
		this.maxSpeed = maxSpeed;
	}
	public float getRotation()
	{
		return rotation;
	}
	public void setRotation(float rotation)
	{
		this.rotation = rotation%360;
	}
	public float getThrust()
	{
		return thrust;
	}
	public void setThrust(float thrust)
	{
		this.thrust = thrust;
	}
	public int getTeam()
	{
		return team;
	}
	public void setTeam(int team)
	{
		this.team = team;
	}
	public Shape getShape()
	{
		return shape;
	}
	public void setShape(Shape shape)
	{
		this.shape = shape;
	}
}
