package com.brackeen.javagamebook.bsp2D;


import java.util.*;
import com.brackeen.javagamebook.math3D.Vector3D;
import com.brackeen.javagamebook.path.AStarNode;

/**
    Klasa Portal reprezentuje rozdzielnik pomiędzy dwoma
    liśćmi drzewa BSP (np. przejścia pomiędzy pomieszczeniami).
    Klasa Portal jest rozszerzeniem klasy AStarNode, zatem
    boty wyposażone w system sztucznej inteligencji będą mogły
    wykorzystywać algorytm A* do znajdowania drogi w drzewie
    BSP.
*/
public class Portal extends AStarNode {

    private BSPLine divider;
    private BSPTree.Leaf front;
    private BSPTree.Leaf back;
    private ArrayList neighbors;
    private Vector3D midPoint;

    /**
        Tworzy nowy obiekt klasy Portal z danym rozdzielnikiem i
        liśćmi dla przodu i tyłu.
    */
    public Portal(BSPLine divider, BSPTree.Leaf front,
        BSPTree.Leaf back)
    {
        this.divider = divider;
        this.front = front;
        this.back = back;
        midPoint = new Vector3D(
            (divider.x1 + divider.x2) / 2,
            Math.max(front.floorHeight, back.floorHeight),
            (divider.y1 + divider.y2) / 2);
    }


    /**
        Zwraca punkt środkowy z rozdzielnika przejścia.
    */
    public Vector3D getMidPoint() {
        return midPoint;
    }


    /**
        Buduje listę sąsiadów dla reprezentacji AStarNode.
        Sąsiadami są przejścia znajdującie się w przednich
        i tylnych liściach, wyłączając to przejście.
    */
    public void buildNeighborList() {
        neighbors = new ArrayList();
        if (front != null) {
            neighbors.addAll(front.portals);
        }
        if (back != null) {
            neighbors.addAll(back.portals);
        }

        // dostosuj rozmiar, po czym usuń odwołania do tego węzła.
        // (zapewnia dodatkową przestrzeń na wywołania metogy addNeighbor()
        // bez zwiększania przestrzeni w tablicy)
        neighbors.trimToSize();
        while (neighbors.remove(this));
    }


    /**
        Dodaje węzeł sąsiadujący do listy sąsiadów.
    */
    public void addNeighbor(AStarNode node) {
        if (neighbors == null) {
            buildNeighborList();
        }
        neighbors.add(node);
    }


    /**
        Usuwa węzeł sąsiadujący z listy sąsiadów.
    */
    public void removeNeighbor(AStarNode node) {
        if (neighbors == null) {
            buildNeighborList();
        }
        neighbors.remove(node);
    }

    // metody z klasy AStarNode

    public float getCost(AStarNode node) {
        return getEstimatedCost(node);
    }


    public float getEstimatedCost(AStarNode node) {
        if (node instanceof Portal) {
            Portal other = (Portal)node;
            float dx = midPoint.x - other.midPoint.x;
            float dz = midPoint.z - other.midPoint.z;
            return (float)Math.sqrt(dx * dx + dz * dz);
        }
        else {
            return node.getEstimatedCost(this);
        }
    }


    public List getNeighbors() {
        if (neighbors == null) {
            buildNeighborList();
        }
        return neighbors;
    }

}