package Ship;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.Animation.PlayMode;
import com.badlogic.gdx.math.Rectangle;
import com.jln.ld.GameAnimation;
import com.jln.ld.GameEntity;
import com.jln.ld.GameUtils;
import com.jln.ld.Shared;

import MapItem.MessagePoint;
import MapItem.Powerup;
import enemis.Asteroid;
import menus.GameMenu;
import shoot.BasicShoot;

public abstract class BasicShip implements GameEntity {

	protected float x, targetX;
	protected float y, targetY;
	protected float lastDx = 0f;
	protected float lastDy = 0f;
	protected float width = 48;
	protected float height = 48;
	protected float speed = 4.9f, iaSpeed = 2f, currentIaSpeed = 2f;
	protected float speedFactor = 0f;
	protected float acceleration = 0.05f;

	protected int direction = Shared.DIR_RIGHT;
	protected int xFrame, yFrame;
	protected int cptIaShoot = 0;
	protected Animation[] moveAnimations;
	protected Animation switchAnimation, shieldAnimation;
	protected boolean playSwitchAnimation = false;
	
	protected int speedAnimation;
	protected float statetime = 0f, animStatetime = 0f;
	protected int energy = 200;
	protected int maxEnergy = 200;
	protected int energyPercent = 100;
	protected boolean dead = false;
	protected Rectangle collision;
	protected int cptHealing = 0;
	protected float xLimit = 90;
	protected int shootLevel;
	protected boolean shield = false;

	protected boolean playerOnControl = true;

	public BasicShip(float x, float y, boolean playerOnControl){
		this.x = x;
		this.y = y;
		this.playerOnControl = playerOnControl;
		this.energy = maxEnergy;
		this.initRessources();
		collision = new Rectangle(x-12,y-21,24,42);
		switchAnimation = GameUtils.loadAnimation(Shared.ANIM_SWITCH, 8, 0, 0.09f, PlayMode.NORMAL);
		shieldAnimation = GameUtils.loadAnimation(Shared.SHIP_SHIELD, 3, 0, 0.11f, PlayMode.LOOP);
		
	}

	protected abstract void initRessources();

	/**
	 * ==========================================
	 * == MISE A JOUR DE L'OBJET               ==
	 * ==========================================
	 */
	@Override
	public void update(GameMenu game) {
		if(cptHealing > 0){
			cptHealing--;
		}
		if(cptIaShoot>0){
			cptIaShoot --;
		}
		if(dead && x>-20){
			absoluteMove(-0.8f, 0,game);
		}else{
			if(playerOnControl){
				updateControls(game);
			}else{
				updateIA(game);
			}
		}
		
		if(speedFactor < 0.15 || direction==Shared.DIR_LEFT){
			speedAnimation = 0;
		}else if(speedFactor < 0.85 || direction!=Shared.DIR_RIGHT){
			speedAnimation = 1;
		}else{
			speedAnimation = 2;
		}
	}

	/**
	 * ==========================================
	 * == DESSIN DE L'OBJET                    ==
	 * ==========================================
	 */
	@Override
	public void render(GameMenu game) {
		if(dead){
			Shared.GAME_BATCH.setColor(0.3f, 0.3f, 0.3f, 1f);
		}else if(!isPlayerOnControl()){
			if(game.getShipOnControl()!=3){
				Shared.GAME_BATCH.setColor(0.23f, 0.23f, 0.23f, 1f);
			}else{
				Shared.GAME_BATCH.setColor(0.8f, 0.7f, 0.7f, 1f);
			}

		}
		this.renderShip(game);
		if(shield){
			Shared.GAME_BATCH.draw(shieldAnimation.getKeyFrame(statetime), x-24+Shared.DECAL_X,y-24+Shared.DECAL_Y);
		}
		Shared.GAME_BATCH.setColor(1f, 1f, 1f, 1f);

	
		if(playSwitchAnimation){
			if(switchAnimation.isAnimationFinished(animStatetime)){
				playSwitchAnimation = false;
			}else{
				Shared.GAME_BATCH.draw(switchAnimation.getKeyFrame(animStatetime), x-24+Shared.DECAL_X,y-24+Shared.DECAL_Y);
				animStatetime += Gdx.graphics.getDeltaTime(); 
			}
		}
		statetime += Gdx.graphics.getDeltaTime(); 
	}

	protected abstract void renderShip(GameMenu game);

	protected void updateControls(GameMenu game){
		float dx=0;
		float dy=0;
		int newDir = direction;

		if(Gdx.input.isKeyPressed(Keys.DOWN)){
			dy = -speed;
			newDir = Shared.DIR_DOWN;
		}
		if(Gdx.input.isKeyPressed(Keys.UP)){
			dy = speed;
			newDir = Shared.DIR_UP;
		}
		if(Gdx.input.isKeyPressed(Keys.LEFT)){
			dx = -speed;
			newDir = Shared.DIR_LEFT;
		}
		if(Gdx.input.isKeyPressed(Keys.RIGHT)){
			dx = speed*1.5f;
			newDir = Shared.DIR_RIGHT;
		}
		move(game,dx,dy,newDir);
 
	}

	private void updateIA(GameMenu game){
		float dx=0;
		float dy=0;
		int newDir = direction;
		currentIaSpeed = iaSpeed;
		if(game.getShipOnControl() == 3){
			currentIaSpeed *=0.4;
		}

		if(targetX==0 && targetY==0){
			targetY = searchYWithoutDanger(game);
			targetX = searchX(game);
		}
		if(Math.abs(targetY-y)>10){
			if(targetY>y){
				dy=(float) (iaSpeed*0.6);
			}else{
				dy= (float) -(iaSpeed*0.6);
			}
		}
		if(Math.abs(targetX-x)>10){
			if(targetX>x){
				dx=iaSpeed;
				newDir = Shared.DIR_RIGHT;
			}else{
				dx = -1;
				newDir = Shared.DIR_LEFT;
			}
		}
		
		if(canSeeDanger(game) && cptIaShoot <=0 && game.getShipOnControl() == 3 && (this instanceof SupplySpaceship)==false){
			shoot(game);
		}
		if(dx != 0 || dy != 0){
			move(game,dx,dy,newDir);
		}else{
			targetY = searchYWithoutDanger(game);
			targetX = searchX(game);
		}
	}

	private void move(GameMenu game, float dx, float dy, int newDir){
		if(dx == 0 && dy == 0){
			speedFactor -= acceleration;
		}else {
			if(!GameUtils.isOpositeDirection(newDir, direction)){
				speedFactor += acceleration;
			}else{
				speedFactor = 0.05f;
			}
		}

		if(energy==0){
			speedFactor *=0.3;
		}

		direction = newDir;

		speedFactor = GameUtils.stayInLimit(speedFactor,0,1);

		// facteur de vitesse
		dx *= speedFactor;
		dy *= speedFactor;

		if(dx != 0 && dy != 0){
			dx *=0.75;
			dy *=0.75;
		}
		if((x+dx)<Shared.GAME_WIDTH-(width/2) && (x+dx) > (width/2)){
			absoluteMove(dx,0,game);
		}
		if((y+dy)<Shared.GAME_HEIGHT && (y+dy) > 20){
			absoluteMove(0,dy,game);
		}
	}

	protected void absoluteMove(float dx, float dy, GameMenu game){
		this.x += dx;
		this.y += dy;
		collision.setX(collision.getX()+dx);
		collision.setY(collision.getY()+dy);
		
		if(playerOnControl && dx>2 && Math.random()<0.2){
			this.addMoveAnimation(game);
		}
	}

	protected void shoot(GameMenu game){
		cptIaShoot = 12;
	}

	private void updateAnimation(){
		if(acceleration<0.3){
			yFrame = 0;
		}else if(acceleration<0.9){
			yFrame = 1;
		}else{
			yFrame = 2;
		}
	}


	protected void decreaseEnergy(int value){
		if(energy==0){
			dead = true;		
		}else{
			this.energy -= value;
			if(energy <0){
				energy = 0;
			}
		}

	}

	protected void increaseEnergy(int value){
		this.energy += value;
		cptHealing = 10;
		if(energy>maxEnergy){
			energy = maxEnergy;
		}
	}

	protected float searchYWithoutDanger(GameMenu game){
		float newY = (float)((Math.random()*(Shared.GAME_HEIGHT-60))+30);
		int cpt = 0;
		boolean onDanger = true;
		while(onDanger && cpt<10){
			onDanger = false;
			for(Asteroid a : game.getAsteroids()){
				if(a.isVisible() && a.getY()<newY+24 && a.getY()>newY-24){
					onDanger = true;
					break;
				}
				
			}
			if(onDanger){
				cpt++;
				newY = (float)((Math.random()*(Shared.GAME_HEIGHT-60))+30);
			}else{
				return newY;
			}
		}
		return newY;
	}
	
	protected boolean canSeeDanger(GameMenu game){
		for(Asteroid a : game.getAsteroids()){
			if(a.isVisible() && a.getY()<y && a.getY()>y-24){
				return true;
			}
		}
		return false;
	}
	
	protected float searchX(GameMenu game){
		float newX = (float)((Math.random()*300)+120);
		return newX;
	}
	
	public boolean isDead() {
		return dead;
	}

	public float getEnergyPercent(){
		return ((float)energy )/(float)maxEnergy;
	}

	public boolean isPlayerOnControl() {
		return playerOnControl;
	}

	public void setPlayerOnControl(boolean playerOnControl) {
		this.playerOnControl = playerOnControl;
	}

	public int getEnergy() {
		return energy;
	}
	public boolean onEnergyContact(GameMenu game, BasicShoot s){
		if(!dead){
			if((this instanceof SupplySpaceship)==false){
				if(collision.contains(s.getX(), s.getY())){
					increaseEnergy(1);
					return true;
				}
			}
		}
		return false;
	}
	public boolean onShootContact(GameMenu game, BasicShoot s){
		if(!dead &&(playerOnControl || game.getShipOnControl()==3)){
			if(collision.contains(s.getX(), s.getY())){
				Shared.SOUND_EXPLOSE_2.play();
				
				if(shield){
					shield = false;
				}else{
					if(this instanceof SupplySpaceship){
						decreaseEnergy(1);
					}else{
						decreaseEnergy(35);
					}
				}
				this.addHitAnimation(game);
				return true;
			}
		}
		return false;
	}

	public boolean onAsteroidContact(GameMenu game, Asteroid a){
		if(!dead &&(playerOnControl || game.getShipOnControl()==3)){
			if(a.getCollision().overlaps(this.collision)){
				if(shield){
					shield = false;
				}else{
					this.decreaseEnergy((this instanceof SupplySpaceship)?1:50);
					Shared.SOUND_EXPLOSE_2.play();
				}
				this.addHitAnimation(game);
				return true;
			}
		}
		return false;
	}
	
	public boolean onItemContact(GameMenu game, Powerup p){
		if(!dead &&(playerOnControl || game.getShipOnControl()==3)){
			if(this.collision.contains(p.getX(), p.getY())){
				Shared.SOUND_PICKUP.play();
				if(p.getType() == Powerup.POWERUP_INCREASESHOOT){
					if(shootLevel<2 || ((this instanceof SupplySpaceship)==false && shootLevel<3)){
						shootLevel++;
						game.addMessage(x, y, "UPGRADE SHOOT", MessagePoint.TYPE_POWERUPS);
					}else{
						game.addMessage(x, y+16, "MAX SHOOT UPGRADE", MessagePoint.TYPE_INFORMATION);
						game.incPointsWithMessage(50,x, y);
					}
				}else if(p.getType() == Powerup.POWERUP_SHIELD){
					if(isShield()){
						game.addMessage(x, y+16, "YOU ALREADY HAVE A SHIELD", MessagePoint.TYPE_INFORMATION);
						game.incPointsWithMessage(50,x, y);
					}else{
						game.addMessage(x, y+16, "SHIELD !", MessagePoint.TYPE_POWERUPS);
						shield = true;
					}
				}else if(p.getType() == Powerup.POWERUP_50){
					game.incPointsWithMessage(50,x, y);
				}else if(p.getType() == Powerup.POWERUP_100){
					game.incPointsWithMessage(100,x, y);
				}
				return true;
			}
		}
		return false;
	}

	public void giveControl(GameMenu game){
		this.xLimit = (float)(80+ (Math.random()*70));
		this.iaSpeed = (float)(1f + Math.random()*2);
		this.playerOnControl = false;
	}

	public void takeControl(GameMenu game){
		Shared.SOUND_SWITCH.play();
		this.playerOnControl = true;
		animStatetime = 0f;
		playSwitchAnimation = true;
	}

	protected void addMoveAnimation(GameMenu game){
		
	}
	
	private void addHitAnimation(GameMenu game){
		game.getAnimations().add(new GameAnimation(GameAnimation.ANIM_EXPLOSION, 
				(float)(x-8+(Math.random()*16))+Shared.DECAL_X, (float)(y-8+(Math.random()*12))+Shared.DECAL_Y));
		game.getAnimations().add(new GameAnimation(GameAnimation.ANIM_EXPLOSION, 
				(float)(x-8+(Math.random()*16))+Shared.DECAL_X, (float)(y-8+(Math.random()*12))+Shared.DECAL_Y));
		game.getAnimations().add(new GameAnimation(GameAnimation.ANIM_EXPLOSION, 
				(float)(x-8+(Math.random()*16))+Shared.DECAL_X, (float)(y-8+(Math.random()*12))+Shared.DECAL_Y));
		Shared.DECAL_Y = 4;
		Shared.CPT_DECAL = 3;
		Shared.CPT_DECALBIS = 2;

		if(dead){
			game.getAnimations().add(new GameAnimation(GameAnimation.ANIM_EXPLOSION, 
					(float)(x-8+(Math.random()*16))+Shared.DECAL_X, (float)(y-8+(Math.random()*12))+Shared.DECAL_Y));
			game.getAnimations().add(new GameAnimation(GameAnimation.ANIM_EXPLOSION, 
					(float)(x-8+(Math.random()*16))+Shared.DECAL_X, (float)(y-8+(Math.random()*12))+Shared.DECAL_Y));
			game.getAnimations().add(new GameAnimation(GameAnimation.ANIM_EXPLOSION, 
					(float)(x-8+(Math.random()*16))+Shared.DECAL_X, (float)(y-8+(Math.random()*12))+Shared.DECAL_Y));
			game.getAnimations().add(new GameAnimation(GameAnimation.ANIM_EXPLOSION, 
					(float)(x-8+(Math.random()*16))+Shared.DECAL_X, (float)(y-8+(Math.random()*12))+Shared.DECAL_Y));
			Shared.DECAL_Y = 5;
			Shared.CPT_DECAL = 3;
			Shared.CPT_DECALBIS = 4;

		}
	}

	public boolean isShield(){
		return shield;
	}
	
	public void giveShield(){
		this.shield = true;
	}
	
	public int getShootLevel(){
		return shootLevel;
	}

}
