package com.brackeen.javagamebook.ai.pattern;

import java.util.*;
import com.brackeen.javagamebook.math3D.Vector3D;
import com.brackeen.javagamebook.path.PathFinder;
import com.brackeen.javagamebook.game.GameObject;
import com.brackeen.javagamebook.bsp2D.BSPTree;

/**
    Prosta abstrakcyjna klasa implementująca interfejs PathFinder,
    w której metoda find(Vector3D, Vector3D) zwraca wartość null.
    Nie zaimplementowano: AttackPatternSneak and DodgePatternHide
*/
public abstract class AIPattern implements PathFinder {


    protected BSPTree bspTree;

    /**
        Drzewo BSP jest wykorzystywane do otrzymywania właściwych
        wartości y dla reprezentowanego świata.
    */
    public AIPattern(BSPTree bspTree) {
        this.bspTree = bspTree;
    }

    public void setBSPTree(BSPTree bspTree) {
        this.bspTree = bspTree;
    }

    /**
        Ta metoda nie jest zaimplementowana.
    */
    public Iterator find(Vector3D start, Vector3D goal) {
        return null;
    }

    public abstract Iterator find(GameObject bot,
        GameObject player);


    /**
        Oblicza wysokość podłogi dla określonego położenia. Jeśli
        nie można obliczyć wysokości, wykorzystywana jest wartość 
        domyślna.
    */
    protected void calcFloorHeight(Vector3D v, float defaultY) {
       BSPTree.Leaf leaf = bspTree.getLeaf(v.x, v.z);
       if (leaf == null || leaf.floorHeight == Float.MIN_VALUE) {
           v.y = defaultY;
       }
       else {
           v.y = leaf.floorHeight;
       }
    }


    /**
        Zwraca położenie takiego punktu znajdującego się na
        prostej łączącej bota z graczem, który znajduje się 
        w określonej odległości od gracza.
    */
    protected Vector3D getLocationFromPlayer(GameObject bot, GameObject player, float desiredDistSq)
    {
        // oblicza odległość (podniesioną do kwadratu)
        float distSq =  bot.getLocation().getDistanceSq(player.getLocation());

        // jeśli w promieniu pięciu jednostek od gracza,
        // bot jest wystarczająco blisko
        if (Math.abs(desiredDistSq - distSq) < 25) {
            return new Vector3D(bot.getLocation());
        }

        // oblicza wektor od bota do gracza
        Vector3D goal = new Vector3D(bot.getLocation());
        goal.subtract(player.getLocation());

        // oblicza docelową odległość od gracza
        goal.multiply((float)Math.sqrt(desiredDistSq / distSq));

        goal.add(player.getLocation());
        calcFloorHeight(goal, bot.getFloorHeight());

        return goal;
    }

    public String toString() {
        // zwróć nazwę klasy (bez nazwy pakietu)
        String fullName = getClass().getName();
        int index = fullName.lastIndexOf('.');
        return fullName.substring(index+1);
    }

}
