/*
 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 */
package pacman;

import javafx.animation.*;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.shape.Circle;
import javafx.scene.transform.Rotate;
import javafx.util.Duration;
import static pacman.Pacman.*;



/**
 *
 * @author akouznet
 */
public class Enemy extends Creature {
    public static final Duration ENEMY_DEAD_TIME = Duration.seconds(5);
    public static final int PALEVO_TIME = 30000;
    private static final double PALEVO_PROBABILITY = 0.05;
    
    private RotateTransition rotate;

    public static enum State { NORMAL, FRIGHTENED, DEAD };
    private State state = State.NORMAL;
    private Image normalImage;
    private Image frightenedImage;
    private ImageView imageView;
    
    public Enemy(double speed, String filenameNormal, String filenameFrightened) {
        super(speed);
        
        normalImage = new Image(Enemy.class.getResource("images/" + filenameNormal).toExternalForm());
        frightenedImage = new Image(Enemy.class.getResource("images/" + filenameFrightened).toExternalForm());
        
        imageView = new ImageView(normalImage);
        imageView.setFitWidth(CELL_WIDTH);
        imageView.setFitHeight(CELL_WIDTH);
        imageView.setPreserveRatio(true);
        
        imageView.setClip(new Circle(CELL_WIDTH / 2, CELL_WIDTH / 2, CELL_WIDTH / 2));
        
        getChildren().add(imageView);
        
        
        rotate = new RotateTransition(Duration.seconds(1.5), this);
        rotate.setByAngle(360);
        rotate.setAxis(Rotate.Z_AXIS);
        rotate.setCycleCount(Timeline.INDEFINITE);
        rotate.setInterpolator(Interpolator.LINEAR);
//        rotate.play();         
    }

    public void chooseRandomDirection() {
        int direction = (int) (Math.random() * 4);
        switch(direction) {
            case 0:
                moveUp();
                break;
            case 1:
                moveDown();
                break;
            case 2:
                moveLeft();
                break;
            case 3:
                moveRight();
                break;
        }
    }
    
    private boolean walkaround = false;
    private static long lastPalevoTime = System.currentTimeMillis();
    
    public static void resetPalevo() {
        lastPalevoTime = System.currentTimeMillis();
    }
    

    public void chooseBestDirection() {
        Mikhalych mikhalych = Pacman.getGame().getMikhalych();
        double dx = mikhalych.getTranslateX() - getTranslateX();
        double dy = mikhalych.getTranslateY() - getTranslateY();
        
        int sx = (int) Math.round(Math.signum(dx));
        int sy = (int) Math.round(Math.signum(dy));
        if (getState() == State.FRIGHTENED) {
            sx = -sx;
            sy = -sy;
        }
        if (Math.abs(dx) > Math.abs(dy)) {
            if (sx != 0 && Pacman.getGame().getField().isFree(getCellX() + sx, getCellY())) {
                move(sx, 0);
            } else if (sy != 0 && Pacman.getGame().getField().isFree(getCellX(), getCellY() + sy)) {
                move(0, sy);
            } else {
                walkaround = true;
                super.stepFinished();
            }
        } else {
            if (sy != 0 && Pacman.getGame().getField().isFree(getCellX(), getCellY() + sy)) {
                move(0, sy);
            } else if (sx != 0 && Pacman.getGame().getField().isFree(getCellX() + sx, getCellY())) {
                move(sx, 0);
            } else {
                walkaround = true;
                super.stepFinished();
            }
        }
    }

    @Override
    public void movementStarted() {
        super.movementStarted();
        rotate.play();
    }

    @Override
    public void stop() {
        super.stop();
//        rotate.pause();
        chooseRandomDirection();
    }

    @Override
    public void stepFinished() {
        walkUpToCrossing();
    }

    public void walkUpToCrossing() {
        int x = getCellX();
        int y = getCellY();
        
        int ways = 0;
        if (getGame().getField().isFree(x - 1, y)) {
            ways++;
        }
        if (getGame().getField().isFree(x + 1, y)) {
            ways++;
        }
        if (getGame().getField().isFree(x, y - 1)) {
            ways++;
        }
        if (getGame().getField().isFree(x, y + 1)) {
            ways++;
        }
        
        if (ways >= 3) {
            walkaround = false;
            chooseRandomDirection();
        } else {
            super.stepFinished();
        }
    }
    
    public double getDistance() {
        Mikhalych mikhalych = Pacman.getGame().getMikhalych();
        double dx = mikhalych.getTranslateX() - getTranslateX();
        double dy = mikhalych.getTranslateY() - getTranslateY();
        return Math.hypot(dx, dy) / Pacman.CELL_WIDTH;
    }
    
    public boolean isMikhalychAlive() {
        Mikhalych mikhalych = Pacman.getGame().getMikhalych();
        return mikhalych.getState() == Mikhalych.State.ALIVE;
    }    
    
    public void enemyMovement(int distance) {
        if (!walkaround && isMikhalychAlive() && getDistance() <= distance) {
            chooseBestDirection();
        } else {
            walkUpToCrossing();
        }
    }  
    
    public void maybeDropPalevo() {
        if (System.currentTimeMillis() - lastPalevoTime >= PALEVO_TIME 
                && Math.random() < PALEVO_PROBABILITY) {
            getGame().dropPalevo(new Palevo(), getCellX(), getCellY());
            lastPalevoTime = System.currentTimeMillis();
        }
    }
    
    public void becomeFrightened() {
        if (state == State.NORMAL) {
            state = State.FRIGHTENED;
            imageView.setImage(frightenedImage);
        }
    }
    
    public void becomeNormal() {
        if (state == State.FRIGHTENED) {
            state = State.NORMAL;
            imageView.setImage(normalImage);
        }
    }

    public State getState() {
        return state;
    }
    
    void die() {
        if (state == State.FRIGHTENED) {
            state = State.DEAD;
            if (getMove() != null) {
                getMove().pause();
            }
            playDeathAnimation();
        }
    }
    
    private void playDeathAnimation() {
        final double currentX = getTranslateX();
        final double currentY = getTranslateY();
        final AnimationTimer animationTimer = new AnimationTimer() {
            
            @Override
            public void handle(long l) {
                setTranslateX(currentX + Math.random() * 10 - 5);
                setTranslateY(currentY + Math.random() * 10 - 5);
            }
        };
        animationTimer.start();
        PauseTransitionBuilder.create()
                .duration(ENEMY_DEAD_TIME)
                .onFinished(new EventHandler<ActionEvent>() {

                    @Override
                    public void handle(ActionEvent t) {
                        animationTimer.stop();
                        setTranslateX(currentX);
                        setTranslateY(currentY);
                        state = State.NORMAL;
                        imageView.setImage(normalImage);
                        if (getMove() != null) {
                            getMove().play();
                        }
                    }
                })
                .build().play();
    }

    int getRequestAmount() {
        return 10;
    }
}
