/**********************************
 * Assignment 5: Pacman
 * Date: 5/5/2006
 *
 * Jenna Holloway: jh382, 563324
 * Benji Shultz: bas67, 1786511
 **********************************/
package game.actor;

import game.Constants;

import java.awt.geom.Point2D;
import java.util.EnumSet;
import java.util.Timer;
import java.util.TimerTask;

enum GhostState { ACTIVE, SEND_TO_CORRAL, CORRAL, VULNERABLE, RECOVERING,POOED };
/**
 * Class to represent a Ghost in the Pacman Game
 * Ghosts add the ability to become vulnerable and to 'fly' back to the corral
 * @author Alec Berntson
 *
 */
public class Ghost extends Actor {

 // the possible states and current state of the ghost
 static final EnumSet<GhostState> MOVING = EnumSet.of(GhostState.ACTIVE,GhostState.POOED, GhostState.VULNERABLE, GhostState.RECOVERING);
 public GhostState ghostState = GhostState.ACTIVE;
 
 // how near the ghost corral does it need to be to stop flying
 public static double NEAR_THRESHOLD = 10;
 // how long should a ghost be stuck in the corral
 public static long CORRAL_TIMEOUT = 10000;
 //score value for killing this ghost
 int scoreval=0; double initialSpeed;
 // timer to free the ghost
 private Timer corralTimer = new Timer(false);

 // images used
 private Images vulnerableGhostImages = new Images(Constants.vulnerableGhostImageNames);
 private Images vulnerableKoopaImages = new Images(Constants.mVulnerableGhostImagesNames);
 private Images recoveringKoopaImages = new Images(Constants.RecoveringKoopaImageNames);
 private Images poisonedGhostImages= new Images(Constants.poisonedGhostImageNames);
 private Images recoveringGhostImages = new Images(Constants.recoveringGhostImageNames);
 public final int timerIndex; //timer index
 /**
  * create a new ghost
  * @param unitID
  * @param speed in pixels per secound
  * @param initialLocation
  * @param imagePaths
  */
 public Ghost(String unitID, double speed, int scoreval,int timerIndex,Point2D initialLocation, String[][] imagePaths) {
  super(unitID, speed, initialLocation, imagePaths);
  initialSpeed=speed;
  this.scoreval=scoreval;
  this.timerIndex=timerIndex;
 }

 
 /*Methods used to set up the appropriate images and mode of ghosts*/
 
 public void setPsych(int i){
	 switch (i){
	 case 0:
		 currentImages=standardImages=new Images(pPinkyImageNames);
		 break;
 	case 1:
	 currentImages=standardImages=new Images(pBlinkyImageNames);
	 break;
 	case 2:
 		 currentImages=standardImages=new Images(pInkyImageNames);
 		 break;
 	case 3:
 		 currentImages=standardImages=new Images(pClydeImageNames);
 		 break;
 		
 }
 }
 
 public void setNorm(int i){
	 switch (i){
	 case 0:
		 currentImages=standardImages=new Images(pinkyImageNames);
		 break;
 	case 1:
	 currentImages=standardImages=new Images(blinkyImageNames);
	 break;
 	case 2:
 		 currentImages=standardImages=new Images(inkyImageNames);
 		 break;
 	case 3:
 		 currentImages=standardImages=new Images(clydeImageNames);
 		 break;
 		
 }
 }
 
 public void setKoopa(int i){
	 switch (i){
	 case 0:
		 currentImages=standardImages=new Images(redKoopaImageNames);
		 break;
 	case 1:
	 currentImages=standardImages=new Images(greenKoopaImageNames);
	 break;
 	case 2:
 		 currentImages=standardImages=new Images(brownKoopaImageNames);
 		 break;
 	case 3:
 		 currentImages=standardImages=new Images(greenKoopaImageNames);
 		 break;
 		
 }
 }
 //how many points do pacman get for eating this ghost
 public int getScore(){
  return scoreval;
 }
 
 //is the ghost in corral?
 public boolean inCorral(){
	  return ghostState==GhostState.CORRAL;
	 }
 
 /**
  * makes the Ghost vulnerable to being eaten by pacman
  * swaps images with the blue ghost
  *
  */

 public void makeVulnerable() {
  if(ghostState == GhostState.ACTIVE ){
   ghostState = GhostState.VULNERABLE;
   if(game.isMario())
	   currentImages=vulnerableKoopaImages;
   else
	   currentImages = vulnerableGhostImages;
   speed=60;
  }
 }
 /**
  * put the ghost into flashing, recovery mode
  *
  */
 public void makeRecovering() {
  if(ghostState == GhostState.VULNERABLE||ghostState==GhostState.POOED){
   ghostState = GhostState.RECOVERING;
   if(game.isMario())
	   currentImages=recoveringKoopaImages;
   else
	   currentImages = recoveringGhostImages;
  }	
 }
 
 
 /**
  * 
  * puts the ghost into green, vulnerable mode
  *
  */
 public void makePoisoned(){
  if(ghostState==GhostState.ACTIVE){
   ghostState=GhostState.POOED;
   currentImages=poisonedGhostImages;
   speed=50;
  }
 }
 
 public boolean isPoisoned(){
  return ghostState==GhostState.POOED;
 }
 /**
  * makes the ghost appear normally
  *
  */
 public void makeActive() {
  if(ghostState == GhostState.RECOVERING || ghostState == GhostState.CORRAL ){
   speed=initialSpeed;
   ghostState = GhostState.ACTIVE;
   currentImages = standardImages;
  }
 }

 public boolean isVulnerable() {
  return ghostState == GhostState.VULNERABLE;
 }

 public boolean isRecovering() {
  return ghostState == GhostState.RECOVERING;
 }

 public boolean isActive() {
  return ghostState == GhostState.ACTIVE;
 }

 class FreeGhostTask extends TimerTask {
  public void run() {
   ghostState = GhostState.ACTIVE;
  }
 }
 /**
  * forces the ghost to fly to the Corral, purges any timers
  * and sets the timer to free the ghost from the Corral
  *
  */
 public void sendToCorral() {
  ghostState = GhostState.SEND_TO_CORRAL;
  corralTimer.purge();
  corralTimer.schedule(new FreeGhostTask(), CORRAL_TIMEOUT);
  currentImages = standardImages;
 }

 /**
  * Adds a direction for the ghost to travel in in accordance to the
  * way 'pacman works'. 
  * @param newDirection
  */
 public void addDirection(MovementDirection newDirection) {

  // if we are not moving now, set both directions to be newDirection
  if (currentDirection == MovementDirection.NONE) {
   currentDirection = newDirection;
   nextDirection = currentDirection;
   lastInterection = new Point2D.Double(-1, -1);
  }
  // if newDirection is the same as our current direction, cancel the change
  // (set nextDirection = current)
  else if (newDirection == currentDirection) {
   nextDirection = newDirection;
  }
  // if we are turning around, set both
  else if (MovementDirection.isOpposite(currentDirection, newDirection)) {
   currentDirection = newDirection;
   nextDirection = currentDirection;
   lastInterection = new Point2D.Double(-1, -1);

  }
  // otherwise register to turn 90 deg at the next intersection
  else { // newDirection must be perpendicular
   nextDirection = newDirection;
  }
 }
 
 /**
  * move the ghost along is chosen path, OR fly to the Corral depending on the state
  * @param dt the delta time that has passed since the last drawing
  */
 public void move(double dt) {
  if (MOVING.contains(ghostState)) {
   super.move(dt);
  } else {
   Point2D corral = game.map.getCorralLocation();
   if (!isNear(currentPosition, corral)) {
    Point2D dest = corral;
    double dx = dest.getX() - this.currentPosition.getX();
    double dy = dest.getY() - this.currentPosition.getY();
    Point2D vec = normalize(new Point2D.Double(dx, dy));
    currentPosition.setLocation(currentPosition.getX() + (vec.getX() * speed / 5), currentPosition.getY() + (vec.getY() * speed / 5));
   } else {
    currentPosition.setLocation(corral);
    ghostState = GhostState.CORRAL;
    currentImages = standardImages;
   }
  }
 }
 /**
  * Normaizes Point2D to a length of 1
  * @param vec
  * @return
  */
 public Point2D normalize(Point2D vec) {
  double x = vec.getX();
  double y = vec.getY();
  double d_2 = x * x + y * y;
  double d_root = Math.sqrt(d_2);
  return new Point2D.Double(x / d_root, y / d_root);
 }
 /**
  * returns true if pt1 is within NEAR_THRESHOLD of pt2 
  * @param pt1
  * @param pt2
  * @return
  */
 public boolean isNear(Point2D pt1, Point2D pt2) {
  return pt1.distance(pt2) < NEAR_THRESHOLD;
 }
}
