package de.swagner.paxbritannica;

import java.util.ArrayList;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;

import de.swagner.paxbritannica.factory.FactoryProduction;

public class Ship extends Sprite {

	protected float amount = 1.0f;

	protected float turnSpeed = 1.0f;
	protected float accel = 0.0f;
	protected float hitPoints = 0;

	protected float maxHitPoints = 0;

	private float delta = 0.0f;

	public float aliveTime = 0.0f;

	public Vector2 position = new Vector2();
	public Vector2 velocity = new Vector2();
	public Vector2 facing = new Vector2();
	
	public Vector2 collisionCenter = new Vector2();
	public Array<Vector2> collisionPoints = new Array<Vector2>();

	public boolean alive = true;

	private float deathCounter = 50f;
	private float nextExplosion = 10f;
	private float opacity = 5.0f;

	public int id = 0;

	public Ship(int id, Vector2 position, Vector2 facing) {
		super();

		this.id = id;

		this.position.set(position);
		this.facing.set(facing);
		
		collisionPoints.clear();
		collisionPoints.add(new Vector2());
		collisionPoints.add(new Vector2());
		collisionPoints.add(new Vector2());
		collisionPoints.add(new Vector2());

		this.setOrigin(this.getWidth() / 2.f, this.getHeight() / 2.f);
	}

	@Override
	public void draw(Batch batch) {
		delta = Math.min(0.06f, Gdx.graphics.getDeltaTime());
		
		aliveTime += delta;
		collisionPoints.get(0).set( this.getVertices()[0], this.getVertices()[1]);
		collisionPoints.get(1).set( this.getVertices()[5], this.getVertices()[6]);
		collisionPoints.get(2).set( this.getVertices()[10], this.getVertices()[11]);
		collisionPoints.get(3).set( this.getVertices()[15], this.getVertices()[16]);
		
		collisionCenter.set(collisionPoints.get(0)).add(collisionPoints.get(2)).scl(0.5f);

		velocity.scl( (float) Math.pow(0.97f, delta * 30.f));
		position.add(velocity.x * delta, velocity.y * delta);
		
		this.setRotation(facing.angle());
		this.setPosition(position.x, position.y);

		if (!(this instanceof Bullet) && hitPoints <= 0)
			destruct();
		if (MathUtils.random() < velocity.len() / 900.f) {
			GameInstance.getInstance().bubbleParticles.addParticle(randomPointOnShip());
		}
		super.draw(batch);
	}

	public void turn(float direction) {
		delta = Math.min(0.06f, Gdx.graphics.getDeltaTime());
		
		facing.rotate(direction * turnSpeed * delta).nor();
	}

	public void thrust() {
		delta = Math.min(0.06f, Gdx.graphics.getDeltaTime());
		
		velocity.add(facing.x * accel * delta, facing.y * accel * delta);
	}
	
	public void thrust(float amount) {
		delta = Math.min(0.06f, Gdx.graphics.getDeltaTime());
		
		velocity.add(facing.x * accel * delta, facing.y * accel * amount * delta);
	}

	public Vector2 randomPointOnShip() {
		return new Vector2(collisionCenter.x + MathUtils.random(-this.getWidth() / 2, this.getWidth() / 2), collisionCenter.y
				+ MathUtils.random(-this.getHeight() / 2, this.getHeight() / 2));
	}

	/*
	 * Scratch space for computing a target's direction. This is safe (as a static) because
	 * its only used in goTowardsOrAway which is only called on the render thread (via update).
	 */
	private static final Vector2 target_direction = new Vector2(); 

	public void goTowardsOrAway(Vector2 targetPos, boolean forceThrust, boolean isAway) {
		target_direction.set(targetPos).sub(collisionCenter);
		if (isAway) {
			target_direction.scl(-1);
		}

		if (facing.crs(target_direction) > 0) {
			turn(1);
		} else {
			turn(-1);
		}

		if (forceThrust || facing.dot(target_direction) > 0) {
			thrust();
		}
	}

	public float healthPercentage() {
		return Math.max(hitPoints / maxHitPoints, 0);
	}

	public void damage(float amount) {
		hitPoints = Math.max(hitPoints - amount, 0);
	}

	public void destruct() {
		if (this instanceof FactoryProduction) {
			factoryDestruct();
		} else {
			GameInstance.getInstance().explode(this);
			alive = false;
			for (Ship factory : GameInstance.getInstance().factorys) {
				if(factory instanceof FactoryProduction && factory.id == this.id) ((FactoryProduction) factory).ownShips--;
			}
		}
	}

	public void factoryDestruct() {
		delta = Math.min(0.06f, Gdx.graphics.getDeltaTime());

		if (deathCounter > 0) {
			((FactoryProduction) this).production.halt_production = true;
			this.setColor(1, 1, 1, Math.min(1, opacity));
			opacity -= 1 * delta;
			if (Math.floor(deathCounter) % nextExplosion == 0) {
				GameInstance.getInstance().explode(this, randomPointOnShip());
				nextExplosion = MathUtils.random(2, 6);
			}
			deathCounter -= 10 * delta;
		} else {
			for (int i = 1; i <= 10; ++i) {
				GameInstance.getInstance().explode(this, randomPointOnShip());
			}
			alive = false;
		}
	}

	// automatically thrusts and turns according to the target
	public void goTowards(Vector2 targetPos, boolean forceThrust) {
		goTowardsOrAway(targetPos, forceThrust, false);
	}

	public void goAway(Vector2 targetPos, boolean forceThrust) {
		goTowardsOrAway(targetPos, forceThrust, true);
	}

}
