package zero1hd.rhythmbullet.entity;

import java.util.HashMap;

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.scenes.scene2d.Actor;
import com.badlogic.gdx.utils.Pool.Poolable;

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

public class Entity extends Actor implements Poolable {
	private Coordinator coordinator;
	private EntityFrame<?> ef;
	
	protected AssetManager assets;
	protected Preferences prefs;
	protected EntityManager ec;
	
	protected boolean enemy;
	protected boolean simple = true;
	protected boolean nonStnrd = false;
	protected boolean move = true;
	
	protected boolean dead;
	protected Rectangle hitbox;
	protected Sprite sprite;
	protected Vector2 rotRatios;
	protected Vector2 center;
	public float angle;
	public float speed;

	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();
		center = 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();
	}
	
	/**
	 * used by the game stage to pass parameters for different types of entities.
	 * @param params a hashmap containing parameters necessary for different entities.
	 */
	public void init(HashMap<String, Float> params) {
	}
	
	/**
	 * 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;
	}
	
	@Override
	public void act(float delta) {
		if (!nonStnrd) {
			if (coordinator != null) {
				coordinator.coordinate(delta);
			}
			
			if (move) {
				move(delta, true);
			}
			if (dead) {
				ef.recycleEntity(this);
			}
		}
		
		if (angle >= 360f) {
			angle -= 360f;
		}
		
		if (getX() > RhythmBullet.GAME_AREA_WIDTH || getY() > RhythmBullet.GAME_AREA_HEIGHT || getX() < 0-getWidth() || getY() < 0-getHeight()) {
			dead = true;
		}
		super.act(delta);
	}
	
	@Override
	public void draw(Batch batch, float parentAlpha) {
		if (!nonStnrd) {
			sprite.draw(batch);
		}
		batch.setColor(Color.WHITE);
		super.draw(batch, parentAlpha);
	}
	
	public boolean playCollidePFX() {
		return true;
	}
	
	public boolean playCollideSFX() {
		return true;
	}
	
	public void move(float delta, boolean update) {
		rotRatios.set(MathUtils.cosDeg(angle), MathUtils.sinDeg(angle));
		moveBy(rotRatios.x*speed*delta, rotRatios.y*speed*delta);
		center.set(getX() + getWidth()/2f, getY() + getHeight()/2f);
		
		if (update) {
			updatePositionData();
		}
	}
	
	public void updatePositionData() {
		if (simple) {
			sprite.setPosition(getX(), getY());
			hitbox.setPosition(getX(), getY());
			sprite.setSize(getWidth(), getHeight());
			hitbox.setSize(getWidth(), getHeight());
		} else {
			sprite.setCenter(center.x, center.y);
			hitbox.setCenter(center);
			sprite.setOriginCenter();
			sprite.setRotation(angle);
		}
	}
	
	@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);
		setPosition(0, 0);
		center.set(0, 0);
		angle = 0;
		speed = 0;
		points = 0;
		dead = false;
	}
	
	public Vector2 getCenter() {
		return center;
	}
	
	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);
	}
}
