/**
 * Diese Klasse implementiert den Medium Ki Spieler.
 * @author Florian und Florian
 * */
import java.util.ArrayList;
import java.util.List;

public class SpecificAiPlayerMedium extends AiPlayer{
    /**
     * Liste an Punkten die beschossen werden sollen. (Mögliche weitere Segmente vom schiff)
     */
 	private List<Point> hitsQueue = new ArrayList<>();

    public SpecificAiPlayerMedium() {
        super();
        this.setName("AI Player Medium");
    }

    /**
     * Ki Methode um zu schießen.
     */
    @Override
    public void aiShoot() {
        Point nextShot = ComputeNextShot();
        // Shoot at the enemy and receive the hit response
        enemy.receiveShoot(nextShot);
    }
    
    @Override
    public synchronized void receiveHit(HitResponse hitResponse) {
        super.receiveHit(hitResponse);
        // If it's a hit or sunk, add adjacent cells to the hitsQueue
        if (hitResponse.getHitResponse() == HitResponseType.HIT) {
            addAdjacentPoints(hitResponse.getPoint());
        }
    }

    /**
     * Die Methode bestimmt welche Position als nächstes beschossen werden soll.
     * @return
     */
    public Point ComputeNextShot() {
        Point nextShot;

        // Prioritize shots from the hitsQueue
        while (!hitsQueue.isEmpty()) {
            nextShot = hitsQueue.remove(0);
            if (!alreadyShot(nextShot)) {
                return nextShot;
            }
        }

        // If hitsQueue is empty, pick a random point that hasn't been shot
        do {
            nextShot = RandomPoint();
        } while (alreadyShot(nextShot));

        return nextShot;
    }

    /**
     * Diese Methode erweitert die hitsQueue um die umliegenden Punkte die Schiffe seien könnten.
     * @param point
     */
    private void addAdjacentPoints(Point point) {
        int x = point.getX();
        int y = point.getY();

        // Possible adjacent positions (up, down, left, right)
        Point[] adjacentPoints = {
            new Point(x, y - 1),
            new Point(x, y + 1),
            new Point(x - 1, y),
            new Point(x + 1, y)
        };

        for (Point p : adjacentPoints) {
            if (isValidPoint(p) && !alreadyShot(p) && !hitsQueue.contains(p)) {
                hitsQueue.add(p);
            }
        }
    }

    /**
     * Diese Methode gibt zurück, ob eine Position schon beschossen wurde. (Boolean)
     * @param p Punkt der geprüft werden soll
     * @return wurde schon beschossen oder nicht.
     */
    private boolean alreadyShot(Point p) {
        
        return this.enemy.board.getHitResponseOnPoint(p) != null;
        
    }

    /**
     * Die Methode gibt zurück, ob eine Position auf dem Board ist. (Boolean)
     * @param point Punkt der geprüft werden soll
     * @return Ist auf dem Board oder nicht.
     */
    private boolean isValidPoint(Point point) {
        return point.getX() >= 0 && point.getX() < board.getSize() &&
               point.getY() >= 0 && point.getY() < board.getSize();
    }
}