package zero1hd.rhythmbullet.entity;

import java.security.InvalidParameterException;

import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Pool.Poolable;

import zero1hd.rhythmbullet.RhythmBullet;
import zero1hd.rhythmbullet.entity.coordinator.Coordinator;

public class Entity implements Poolable {
	private Coordinator coordinator;
	private EntityFrame<?> ef;
	
	protected AssetManager assets;
	protected Preferences prefs;
	protected EntityManager ec;
	
	protected boolean enemy;
	protected boolean move = true;
	
	protected boolean dead;
	protected Rectangle hitbox;
	protected Sprite sprite;
	protected Vector2 rotRatios;
	public float angle;
	public float speed;
	protected float hitBoxScale;
	
	protected int points;
	
	/**
	 * called by the entity frame and only once (when this object is created).
	 * Used by the frame to setup variables for simple calling later.
	 * Anything that needs to be setup for the entity on first call should not override this.
	 * (Unless you call the super of this and then the rest which is fine too).
	 * This will then call preInit() which is the method you should override.
	 */
	protected void setup(EntityManager ec, EntityFrame<?> ef) {
		this.ec = ec;
		this.ef = ef;
		assets = ec.getAssets();
		prefs = ec.getPrefs();
		rotRatios = new Vector2();
		hitbox = new Rectangle();
		
		preInit();
	}
	
	/**
	 * Method to override should any setup need to be done once (on entity first creation).
	 */
	public void preInit() {
		if (sprite.getTexture() == null) throw new NullPointerException("what, your not going to have a texture for your entity?");
		sprite.setOriginCenter();
	}
	
	public void init(float deg, float speed, int hp) {
		rotRatios.set(MathUtils.cosDeg(angle), MathUtils.sinDeg(angle));
		sprite.setSize(sprite.getTexture().getWidth()/RhythmBullet.pixels_per_unit, sprite.getTexture().getHeight()/RhythmBullet.pixels_per_unit);
		float r = RhythmBullet.SPAWN_CIRCLE_RADIUS - sprite.getWidth();
		if (r < RhythmBullet.SPAWN_CIRCLE_RADIUS -1) {
			throw new InvalidParameterException("Entity is too big! Calculated final distance from center: " + r);
		}
		sprite.setPosition(r*rotRatios.x, r*rotRatios.y);
		updatePosition();
	}
	
	/**
	 * Called whenever a collision is detected
	 * @param entity is the entity that hit this one.
	 */
	public void collided(Entity entity) {
	}
	
	/**
	 * gets the box that represents the hit box to calculate whether there is a collision or not
	 * @return the object that represents the hit box
	 */
	public Rectangle getHitZone() {
		return hitbox;
	}
	
	public boolean isDead() {
		return dead;
	}
	
	public void calculate(float delta) {
		if (coordinator != null) {
			coordinator.coordinate(delta);
		}
		
		if (dead) {
			ef.recycleEntity(this);
		}
		
		if (angle >= 360f) {
			angle -= 360f;
		}
		
		if (sprite.getX() > RhythmBullet.WORLD_WIDTH || sprite.getY() > RhythmBullet.WORLD_HEIGHT || sprite.getX() < 0-sprite.getWidth() || sprite.getX() < 0-sprite.getWidth()) {
			dead = true;
		}
		
		updatePosition();
	}
	
	public void draw(Batch batch) {
		sprite.draw(batch);
		batch.setColor(Color.WHITE);
	}
	
	public void moveBy(float x, float y) {
		sprite.setCenter(sprite.getX() + x, sprite.getY() + y);
	}
	
	public void updatePosition() {
		rotRatios.set(MathUtils.cosDeg(angle), MathUtils.sinDeg(angle));
		sprite.setOriginCenter();
		sprite.setRotation(angle);
		hitbox.setCenter(sprite.getOriginX(), sprite.getOriginY());
	}
	
	@Override
	public void reset() {
		if (coordinator != null) {
			coordinator.clean();
			coordinator = null;
		}
		rotRatios.set(0, 0);
		sprite.setPosition(0, 0);
		hitbox.set(0, 0, 0, 0);
		sprite.setRotation(0);
		sprite.setColor(Color.WHITE);
		angle = 0;
		speed = 0;
		points = 0;
		dead = false;
	}
	
	public float getAngle() {
		return angle;
	}
	
	public void setSpeed(float speed) {
		this.speed = speed;
	}
	
	public float getSpeed() {
		return speed;
	}
	
	public void setCoordinator(Coordinator coordinator) {
		this.coordinator = coordinator;
		coordinator.setEntity(this);
	}
	
	public void kill() {
		dead = true;
	}
	
	public int getPoints() {
		return points + (coordinator != null ? coordinator.getScoreBonus() : 0);
	}
	
	public float getX() {
		return sprite.getX();
	}
	
	public float getY() {
		return sprite.getY();
	}
	
	public void setPosition(float x, float y) {
		sprite.setPosition(x, y);
		updatePosition();
	}
	
	public float getWidth() {
		return sprite.getWidth();
	}
	
	public float getHeight() {
		return sprite.getHeight();
	}

	public void setSize(float width, float height) {
		sprite.setSize(width, height);
	}
	
	public void setHitboxScale(float scale) {
		hitbox.setSize(sprite.getWidth()*scale, sprite.getHeight()*scale);
	}
}
