package mobs;

import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;

import _texture.loader.Textures;
import engine.Game;
import engine.Handler;
import hud.Clock;
import hud.Clock.TIME;
import interfaces.Mob;
import player.Player;
import utils.Animation;
import utils.Point2f;
import utils.Utils;

/**  ------------- Nihilne ------------
    *** @author Mitch Weaver - 2016 ***
      ~~~~ All Rights Reserved ~~~~ */

public class Rabbit extends Mob {
/**********************************************************************************************************************************************************/
		/**** NOTE: THIS WAS THE FIRST MOB I CREATED FOR THIS GAME
		 * 	  IT IS THE ONLY MOB WRITTEN PURELY IN JAVA, WHERE AS
		 * 	  THE OTHERS ARE SCRIPTED WITH PYTHON / JYTHON.
		 * 	  THIS IS TO BE USED AS A REFERENCE FOR THOSE
		 * 	  OTHER MOBS TO BE SCRIPTED */
/***********************************************************************************************************************************************************/
	
	public Rabbit(final float x, final float y) {
		super(Mob.MOB_ID.RABBIT, new Point2f(x, y), RABBIT_WIDTH, RABBIT_HEIGHT, RABBIT_HOME_RADIUS, randomizeNum(RABBIT_AGGRO_RADIUS), false, -1, RABBIT_COMBAT_LEVEL, 0, RABBIT_TOTAL_HEALTH); 
		currentAnimation = ANIMATION.idleWalk;
		destroyingTimer = DEATH_ANIMATION_SPEED * death.length;
		walkingSpeed = RABBIT_WALKING_SPEED; runningSpeed = RABBIT_RUNNING_SPEED;
		idleMove(walkingSpeed);
	}
	
	private int idleAnimationTimer = Utils.rand.nextInt(250);
	public void tick() {

		// DISCOVER
		getDiscoveredStatus();
		
		// AFTER DEATH
		if(!alive()) { whileDead(); return; }
		
		// NORMALIZE HEALTH
		normalizeHealth();

		// COLLISION / COMBAT / POSITION
		collision(); combat(); if(!collided) updatePosition();
		
		// SLEEPING
		if(!collided && !playerAggroCollided && Clock.clock == TIME.DAWN || Clock.clock == TIME.NIGHT) sleeping = true; else sleeping = false;
		
		// RUN ANIMATIONS
		runAnimations();
		
		// SLEEPING
		if(sleeping && !playerAggroCollided){ velX = velY = 0; currentAnimation = ANIMATION.sleep; }
		
		// RUN AWAY
		if(playerAggroCollided){ currentAnimation = ANIMATION.runAway; runAway(runningSpeed, Player.center); }
		
		// STOP RUNNING AWAY
		if(runningAway && !collided) {
			if(--howFarToRunAwayTimer <= 0) { 
				velX = velY = 0; runningAway = false;
				if(Utils.rand.nextBoolean()) currentAnimation = ANIMATION.idle1; 
				else if(runningAway){ currentAnimation = ANIMATION.idleWalk; idleMove(walkingSpeed);}
			}
		}
		
		// IDLE ANIMATION ALGORITHMS ~~~ ONLY START IF NOT SLEEPING AND NOT RUNNING AWAY
		if(!collided && !runningAway && !sleeping){
			
			// IF NOT WALKING AROUND, MUST BE EATING GROUND
			if(currentAnimation != ANIMATION.idleWalk) idleAnimationTimer--;
		
			// IF FINISHED IDLE WALKING, CHANGE ANIMATION
			if(distanceToMove <= 0 && currentAnimation == ANIMATION.idleWalk) {
				if(Utils.rand.nextInt(4) == 0) idleMove(walkingSpeed); /* 1 in 4 chance of keeping on walking */
				else { idleAnimationTimer = Utils.rand.nextInt(200) + 100; velX = velY = 0;
					   currentAnimation = ANIMATION.idle1;
				}
			}
		
			// IF WAS IDLING, AND TIMER IS UP, START WALKING
			if(currentAnimation != ANIMATION.idleWalk && idleAnimationTimer <= 0){
				currentAnimation = ANIMATION.idleWalk;
				idleMove(walkingSpeed);
			}
		
			// IF WALKING, SUBSTRACT FROM WALK DISTANCE
			if(currentAnimation == ANIMATION.idleWalk) distanceToMove -= Utils.pythagoras(velX, velY);
		
			// IF HAS STEPPED OUTSIDE ITS TERRITORY, GO HOME
			if(!home.contains(center) && !collided) { 
				if(home.center.distance(center) < 1500){
					goHome(walkingSpeed); 
					currentAnimation = ANIMATION.idleWalk; 
				} else {
					goHome(runningSpeed); 
					currentAnimation = ANIMATION.runAway; 
				}
			}
			
			// FIX BUGGY WALKING AROUND
			fixBuggyMovement(walkingSpeed);
		}
		// FIX BUGGY COLLISION --- (they get stuck occasionally) -- just start
		// the idiots moving again until they find a good direction.
		if(justCollided){ idleMove(walkingSpeed); justCollided = collided = false; }
		
		
		getHitClock(); // sub hit timer
	}
	
	public void whileDead() {
		if(alive() || destroyingTimer <= 0) return;
		
		try { if(--destroyingTimer <= 0) destroy();
			
		for(final Animation i : death) if(i.currentFrame != 2) i.runAnimation(); /* != 2 means it won't restart the animation */
		
		} catch (NullPointerException npe) {} // npe is to catch if the handler is slow and ticks again after mob gets removed
	}
	
	private Graphics2D copy; private AffineTransform transform = new AffineTransform();
	public void render(Graphics2D g2d) {
		if(!discovered) return;
		copy = (Graphics2D) g2d.create(); transform.setToRotation(-Utils._45 * (Game.rotation - 1), center.x, center.y); copy.transform(transform);
		if(alive() && GET_HIT_TIMER <= 0) {
				switch(currentAnimation){
					case idleWalk: idleWalks[facing - 1].drawAnimation(copy, center.x, center.y); break;
					case idle1:    idle1[facing - 1].drawAnimation(copy, center.x, center.y); break;
					case runAway:  runAway[facing - 1].drawAnimation(copy, center.x, center.y); break;
					case sleep:    sleep[facing - 1].drawAnimation(copy, center.x, center.y); break;
					default: break;
				}
			drawCollisionBounds(copy); 
		} else if (alive()) copy.drawImage(GET_HITS[facing - 1], (int)center.x, (int)center.y, null);  // THIS IS IF THE GET_HIT TIMER IS ABOVE ZERO, MEANING WE NEED TO RENDER THE GET_HIT ANIMATION
		  else try { death[facing - 1].drawAnimation(copy,  pos.x - width/2, pos.y - height/2); } catch (NullPointerException npe) { /* means he finished dying and got removed */ }
		
		// NOTE: will stop rendering when it gets removed from the mobs list after destroy()
		
		copy.dispose(); copy = null;
	}

	public void combat() {
		if(Player.attacking && Utils.intersects(Player.attackBounds, center, radius)){
			health-= Player.currentDamage;
			HIT_BY_PLAYER();
		}
	}
	
	public void destroy() {
		DROP_TABLES.dropItem(id, center);
		
//		/* implicitly null everything because I'm paranoid */
		for(int i = 0; i < idleWalks.length; i++) idleWalks[i] = null;
		for(int i = 0; i < idle1.length; i++) idle1[i] = null;
		for(int i = 0; i < runAway.length; i++) runAway[i] = null;
		for(int i = 0; i < sleep.length; i++) sleep[i] = null;
		for(int i = 0; i < death.length; i++) death[i] = null;
		idleWalks = idle1 = runAway = sleep = death = null;
		copy = null; transform = null;
		
		Handler.mobs.remove(this);
	}

	
	
	
	
/********************************************************* ANIMATION DECLARATIONS --- IGNORE ******************************************************************/
	private static final int IDLE_WALK_ANIMATION_SPEED = 18, IDLE_EAT_GROUND_ANIMATION_SPEED = 18, RUN_AWAY_ANIMATION_SPEED = 5, SLEEP_ANIMATION_SPEED = 25, DEATH_ANIMATION_SPEED = 10;

	public void runAnimations() {
		switch(currentAnimation){
			case idleWalk: idleWalks[facing - 1].runAnimation(); break;
			case idle1: idle1[facing - 1].runAnimation(); break;
			case runAway: runAway[facing - 1].runAnimation(); break;
			case sleep: sleep[facing -1].runAnimation(); break;
			default: break;
		}
	}

	private static BufferedImage[] GET_HITS = {
			Textures.rabbitSheet[136],
			Textures.rabbitSheet[137],
			Textures.rabbitSheet[138],
			Textures.rabbitSheet[139],
			Textures.rabbitSheet[140],
			Textures.rabbitSheet[141],
			Textures.rabbitSheet[142],
			Textures.rabbitSheet[143]
	};
	
	private Animation[] idleWalks = {
			new Animation(IDLE_WALK_ANIMATION_SPEED, Textures.rabbitSheet[0], Textures.rabbitSheet[1], Textures.rabbitSheet[2], Textures.rabbitSheet[3]), // SOUTH -- FACING = 5
			new Animation(IDLE_WALK_ANIMATION_SPEED, Textures.rabbitSheet[20], Textures.rabbitSheet[21], Textures.rabbitSheet[22], Textures.rabbitSheet[23]), // NE -- FACING = 2
			new Animation(IDLE_WALK_ANIMATION_SPEED, Textures.rabbitSheet[12], Textures.rabbitSheet[13], Textures.rabbitSheet[14], Textures.rabbitSheet[15]), // EAST -- FACING = 3
			new Animation(IDLE_WALK_ANIMATION_SPEED, Textures.rabbitSheet[28], Textures.rabbitSheet[29], Textures.rabbitSheet[30], Textures.rabbitSheet[31]), // SE -- FACING = 4
			new Animation(IDLE_WALK_ANIMATION_SPEED, Textures.rabbitSheet[4], Textures.rabbitSheet[5], Textures.rabbitSheet[6], Textures.rabbitSheet[7]), // NORTH -- FACING = 1
			new Animation(IDLE_WALK_ANIMATION_SPEED, Textures.rabbitSheet[24], Textures.rabbitSheet[25], Textures.rabbitSheet[26], Textures.rabbitSheet[27]), // SW -- FACING = 6
			new Animation(IDLE_WALK_ANIMATION_SPEED, Textures.rabbitSheet[8], Textures.rabbitSheet[9], Textures.rabbitSheet[10], Textures.rabbitSheet[11]), // WEST -- FACING = 7
			new Animation(IDLE_WALK_ANIMATION_SPEED, Textures.rabbitSheet[16], Textures.rabbitSheet[17], Textures.rabbitSheet[18], Textures.rabbitSheet[19]) // NW -- FACING = 8
	};
	
	private Animation[] idle1 = {
			new Animation(IDLE_EAT_GROUND_ANIMATION_SPEED, Textures.rabbitSheet[32], Textures.rabbitSheet[33], Textures.rabbitSheet[34], Textures.rabbitSheet[35]), // SOUTH -- FACING = 5
			new Animation(IDLE_EAT_GROUND_ANIMATION_SPEED, Textures.rabbitSheet[52], Textures.rabbitSheet[53], Textures.rabbitSheet[54], Textures.rabbitSheet[55]), // NE -- FACING = 2
			new Animation(IDLE_EAT_GROUND_ANIMATION_SPEED, Textures.rabbitSheet[44], Textures.rabbitSheet[45], Textures.rabbitSheet[46], Textures.rabbitSheet[47]), // EAST -- FACING = 3
			new Animation(IDLE_EAT_GROUND_ANIMATION_SPEED, Textures.rabbitSheet[60], Textures.rabbitSheet[61], Textures.rabbitSheet[62], Textures.rabbitSheet[63]), // SE -- FACING = 4
			new Animation(IDLE_EAT_GROUND_ANIMATION_SPEED, Textures.rabbitSheet[36], Textures.rabbitSheet[37], Textures.rabbitSheet[38], Textures.rabbitSheet[39]), // NORTH -- FACING = 1
			new Animation(IDLE_EAT_GROUND_ANIMATION_SPEED, Textures.rabbitSheet[56], Textures.rabbitSheet[57], Textures.rabbitSheet[58], Textures.rabbitSheet[59]), // SW -- FACING = 6
			new Animation(IDLE_EAT_GROUND_ANIMATION_SPEED, Textures.rabbitSheet[40], Textures.rabbitSheet[41], Textures.rabbitSheet[42], Textures.rabbitSheet[43]), // WEST -- FACING = 7
			new Animation(IDLE_EAT_GROUND_ANIMATION_SPEED, Textures.rabbitSheet[48], Textures.rabbitSheet[49], Textures.rabbitSheet[50], Textures.rabbitSheet[51]) // NW -- FACING = 8
	};
	
	private Animation[] runAway = {
			new Animation(RUN_AWAY_ANIMATION_SPEED, Textures.rabbitSheet[64], Textures.rabbitSheet[65], Textures.rabbitSheet[66], Textures.rabbitSheet[67]), //SOUTH -- FACING = 5
			new Animation(RUN_AWAY_ANIMATION_SPEED, Textures.rabbitSheet[84], Textures.rabbitSheet[85], Textures.rabbitSheet[86], Textures.rabbitSheet[87]), //NE -- FACING = 2
			new Animation(RUN_AWAY_ANIMATION_SPEED, Textures.rabbitSheet[76], Textures.rabbitSheet[77], Textures.rabbitSheet[78], Textures.rabbitSheet[79]), //EAST -- FACING = 3
			new Animation(RUN_AWAY_ANIMATION_SPEED, Textures.rabbitSheet[92], Textures.rabbitSheet[93], Textures.rabbitSheet[94], Textures.rabbitSheet[95]), //SE -- FACING = 4
			new Animation(RUN_AWAY_ANIMATION_SPEED, Textures.rabbitSheet[68], Textures.rabbitSheet[69], Textures.rabbitSheet[70], Textures.rabbitSheet[71]), //NORTH -- FACING = 1
			new Animation(RUN_AWAY_ANIMATION_SPEED, Textures.rabbitSheet[88], Textures.rabbitSheet[89], Textures.rabbitSheet[90], Textures.rabbitSheet[91]), //SW -- FACING = 6
			new Animation(RUN_AWAY_ANIMATION_SPEED, Textures.rabbitSheet[72], Textures.rabbitSheet[73], Textures.rabbitSheet[74], Textures.rabbitSheet[75]), //WEST -- FACING = 7
			new Animation(RUN_AWAY_ANIMATION_SPEED, Textures.rabbitSheet[80], Textures.rabbitSheet[81], Textures.rabbitSheet[82], Textures.rabbitSheet[83])  //NW -- FACING = 8
	};
	
	private Animation[] sleep = {
			new Animation(SLEEP_ANIMATION_SPEED, Textures.rabbitSheet[96], Textures.rabbitSheet[97]), // SOUTH -- FACING = 5
			new Animation(SLEEP_ANIMATION_SPEED, Textures.rabbitSheet[106], Textures.rabbitSheet[107]), //NE -- FACING = 2
			new Animation(SLEEP_ANIMATION_SPEED, Textures.rabbitSheet[102], Textures.rabbitSheet[103]), // EAST -- FACING = 3
			new Animation(SLEEP_ANIMATION_SPEED, Textures.rabbitSheet[110], Textures.rabbitSheet[111]), // SE -- FACING = 4
			new Animation(SLEEP_ANIMATION_SPEED, Textures.rabbitSheet[98], Textures.rabbitSheet[99]), // NORTH -- FACING = 1
			new Animation(SLEEP_ANIMATION_SPEED, Textures.rabbitSheet[108], Textures.rabbitSheet[109]), //SW -- FACING = 6
			new Animation(SLEEP_ANIMATION_SPEED, Textures.rabbitSheet[100], Textures.rabbitSheet[101]), // WEST -- FACING = 7
			new Animation(SLEEP_ANIMATION_SPEED, Textures.rabbitSheet[104], Textures.rabbitSheet[105])  //NW -- FACING = 8
	};
	
	
	private Animation[] death = {
			new Animation(DEATH_ANIMATION_SPEED, Textures.rabbitSheet[112], Textures.rabbitSheet[113], Textures.rabbitSheet[114]), 
			new Animation(DEATH_ANIMATION_SPEED, Textures.rabbitSheet[124], Textures.rabbitSheet[125], Textures.rabbitSheet[126]), 
			new Animation(DEATH_ANIMATION_SPEED, Textures.rabbitSheet[121], Textures.rabbitSheet[122], Textures.rabbitSheet[123]),
			new Animation(DEATH_ANIMATION_SPEED, Textures.rabbitSheet[133], Textures.rabbitSheet[134], Textures.rabbitSheet[135]),
			new Animation(DEATH_ANIMATION_SPEED, Textures.rabbitSheet[115], Textures.rabbitSheet[116], Textures.rabbitSheet[117]), 
			new Animation(DEATH_ANIMATION_SPEED, Textures.rabbitSheet[130], Textures.rabbitSheet[131], Textures.rabbitSheet[132]),
			new Animation(DEATH_ANIMATION_SPEED, Textures.rabbitSheet[118], Textures.rabbitSheet[119], Textures.rabbitSheet[120]), 
			new Animation(DEATH_ANIMATION_SPEED, Textures.rabbitSheet[127], Textures.rabbitSheet[128], Textures.rabbitSheet[129])
	};
/******************************************************************************************************************************************************************************/

}
