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

import graph.*;
import game.Constants;
import game.Game;
import game.actor.Ghost;
import game.actor.Pacman;
import game.actor.Actor;
import game.actor.MovementDirection;

import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Iterator;

/**
 * This class represents the ghosts, which are controlled by the program.
 */
public class AIPlayer extends Player implements Constants {

 List<Ghost> ghosts = new ArrayList<Ghost>();
 Timer timer = new Timer(false);
 Random rand = new Random();
   
 int calculationInterval = 500; // new path calculation interval

 public AIPlayer(Game game, game.map.PacmanMap map) {
  super(game);
 
  //initialize ghosts
  ghosts.add(new Ghost("blinky", 100,100,0, new Point2D.Double(12*CELL, 11*CELL), blinkyImageNames));
  ghosts.add(new Ghost("pinky", 60,110,1, new Point2D.Double(13*CELL, 11*CELL), pinkyImageNames));
  ghosts.add(new Ghost("inky", 70,120,2, new Point2D.Double(14*CELL, 11*CELL), inkyImageNames));
  ghosts.add(new Ghost("clyde", 85,115, 3,new Point2D.Double(15*CELL, 11*CELL), clydeImageNames));
  timer.scheduleAtFixedRate(new MoveGhostTask(), calculationInterval, calculationInterval);
 }

 public void move(double dt) {
  for (Ghost g : ghosts) {
   g.move(dt);
  }
 }

 public List<Ghost> getActorList() {
  return ghosts;
 }

 public boolean compare(Node n, Point2D p){
  return n.getX()==p.getX()&&n.getY()==p.getY();
 }
 
 class MoveGhostTask extends TimerTask {

  public void run() {
   moveSmartGhosts();
  }
  
  /**
   * for each ghost, use dijkstra's alg to calculate the shortest path to
   * pacman, run from him if they are vulnerable 
   *
   */
  protected void moveSmartGhosts(){
   MapGraph map=(game.getMap().getGraph());
   for(Ghost g:ghosts){
    Pacman pacman=game.localPlayer.getPacman();
    Point2D p1=g.getCurrentCellPoint();
    Point2D p2=pacman.getCurrentCellPoint();
   if(g.isActive()){
   if(p1.distance(game.getMap().getCorralCellPoint())<3){
     escapeCorral(g,p1);
   }
else{
  Path p=map.shortestPath(map.getNodeByCoord((int)p1.getX(), (int)p1.getY()),
      map.getNodeByCoord((int)p2.getX(), (int)p2.getY()));
  follow(p,g);}}
   if(g.isVulnerable()||g.isRecovering()||g.isPoisoned()){
    run(g,pacman);
  }
   }
  }
  
  /**
   * Since the method suggested in the assignment of moving 
   * in the opposite direction of the shortest path
   * fails to produce ghost which actually run away from pacman
   * this method find pacmans relative position and moves them away.
   * Adds one new move each calc interval
   * @param g
   * @param pacman
   */
  protected void run(Actor g, Actor pacman){
   Point2D pg=g.getCurrentCellPoint();
   MovementDirection mdx=MovementDirection.getOpposite(getD(g.getCurrentCellPoint(),pacman.getCurrentCellPoint(),"x"));
   MovementDirection mdy=MovementDirection.getOpposite(getD(g.getCurrentCellPoint(),pacman.getCurrentCellPoint(),"y"));
   boolean north =game.getMap().canMoveDirection((int)pg.getX(),(int)pg.getY(),MovementDirection.NORTH, true);
   boolean south =game.getMap().canMoveDirection((int)pg.getX(),(int)pg.getY(), MovementDirection.SOUTH, true);
   boolean east =game.getMap().canMoveDirection((int)pg.getX(),(int)pg.getY(), MovementDirection.EAST, true);
   boolean west =game.getMap().canMoveDirection((int)pg.getX(),(int)pg.getY(), MovementDirection.WEST, true);
   boolean running=false;
   int i=0;
   while(!running&&i<2){
    i++;
   switch (mdy){
   case NORTH:
    if(north){
     g.addDirection(MovementDirection.NORTH);
     running=true;
     }
     break;
    
   case SOUTH:
    if(south){
     g.addDirection(MovementDirection.SOUTH);
     running=true;
     }
     break;
   default:
    ;
   }
   switch (mdx){
    case WEST:
     if(west){
      g.addDirection(MovementDirection.WEST);
      running=true;}
     break;
     
    case EAST:
     if(east){
      g.addDirection(MovementDirection.EAST);
      running=true;}
     break;
     
    default:
     ;
     
    }
   if(mdy.equals(MovementDirection.NONE)){
    if(south)mdy=MovementDirection.SOUTH;
    if(north)mdy=MovementDirection.NORTH;
   }
   if(mdx.equals(MovementDirection.NONE)){
    if(east)mdx=MovementDirection.EAST;
    if(west)mdx=MovementDirection.WEST;
   }
   }
   
   
   
  }
  /**
  *Brute force to get the ghosts out of the corral. they had trouble
  *without this method.
  */
  protected void escapeCorral(Ghost g,Point2D pg){
   while(game.getMap().canMoveDirection((int)pg.getX(),(int)pg.getY(),MovementDirection.NORTH, true)){
   g.addDirection(MovementDirection.NORTH);
   pg=g.getCurrentCellPoint();
   }
   g.addDirection(MovementDirection.WEST);
   g.addDirection(MovementDirection.NORTH);
  }
  /**
   * code to assign the shortest path moves to a ghost
   * @param p
   * @param g
   */
  protected void follow(Path p, Ghost g){
   Iterator<Node> it=p.iterator();
   Node n1, n2;
    n1=it.next();
   
   while(it.hasNext()){
    n2=it.next();
    g.addDirection(getD(n1,n2));
    n1=n2;
//    do not add any more directions until a ghost has arrived at it destination
    if(!(g.getCurrentCellPoint().distance(n2.getCoordinates())<3)){
     break;
    }
   }
   
 }
  
  private MovementDirection getD(Node n1,Node n2){
   
   if(n2.getX()-n1.getX()>0) return MovementDirection.EAST;
   if(n2.getX()-n1.getX()<0) return MovementDirection.WEST;
   if(n2.getY()-n1.getY()>0) return MovementDirection.SOUTH;
   else return MovementDirection.NORTH;
  }
  private MovementDirection getD(Point2D p1,Point2D p2,String axis){
   if(axis.equals("x")){
   if(p2.getX()-p1.getX()>0) return MovementDirection.EAST;
   if(p2.getX()-p1.getX()<0) return MovementDirection.WEST;
   return MovementDirection.NONE;}
   else{ 
    if(p2.getY()-p1.getY()>0) return MovementDirection.SOUTH;
    if(p2.getY()-p1.getY()<0) return MovementDirection.NORTH;
    return MovementDirection.NONE;}
   }
    
   
 
 }
}
