// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.npc.navigation;

import java.util.Arrays;
import javax.annotation.Nullable;
import javax.annotation.Nonnull;
import com.hypixel.hytale.math.vector.Vector3d;

public class AStarNode implements IWaypoint
{
    public static final AStarNode ENTRY_NODE_TAG;
    @Nonnull
    protected final Vector3d position;
    protected float travelCost;
    protected float estimateToGoal;
    protected float totalCost;
    @Nullable
    protected AStarNode predecessor;
    protected int predecessorDirection;
    @Nonnull
    protected final AStarNode[] successors;
    @Nonnull
    protected final float[] stepCost;
    protected AStarNode nextPathNode;
    protected int length;
    protected long positionIndex;
    protected boolean open;
    
    public AStarNode(final int numDirections) {
        this.position = new Vector3d();
        this.predecessor = null;
        this.predecessorDirection = -1;
        this.successors = new AStarNode[numDirections];
        this.stepCost = new float[numDirections];
    }
    
    public long getPositionIndex() {
        return this.positionIndex;
    }
    
    @Nonnull
    public AStarNode[] getSuccessors() {
        return this.successors;
    }
    
    public AStarNode getSuccessor(final int index) {
        return this.successors[index];
    }
    
    public void setSuccessor(final int directionIndex, @Nonnull final AStarNode node, final int inverseDirectionIndex, final float cost) {
        this.successors[directionIndex] = node;
        this.stepCost[directionIndex] = cost;
        node.successors[inverseDirectionIndex] = AStarNode.ENTRY_NODE_TAG;
    }
    
    @Nullable
    public AStarNode getPredecessor() {
        return this.predecessor;
    }
    
    public AStarNode getNextPathNode() {
        return this.nextPathNode;
    }
    
    public void setNextNode(final AStarNode next, final int length) {
        this.nextPathNode = next;
        this.length = length;
    }
    
    public float getTravelCost() {
        return this.travelCost;
    }
    
    public float getEstimateToGoal() {
        return this.estimateToGoal;
    }
    
    public float getTotalCost() {
        return this.totalCost;
    }
    
    public int getPredecessorDirection() {
        return this.predecessorDirection;
    }
    
    public void close() {
        this.open = false;
    }
    
    public boolean isOpen() {
        return this.open;
    }
    
    public boolean isInvalid() {
        return this.length < 0;
    }
    
    @Override
    public int getLength() {
        return this.length;
    }
    
    @Override
    public AStarNode next() {
        return this.nextPathNode;
    }
    
    @Nonnull
    @Override
    public Vector3d getPosition() {
        return this.position;
    }
    
    @Nullable
    @Override
    public AStarNode advance(int skip) {
        AStarNode node;
        for (node = this; skip-- > 0 && node != null; node = node.nextPathNode) {}
        return node;
    }
    
    @Nonnull
    public AStarNode initAsStartNode(@Nonnull final Vector3d position, final long positionIndex, final float cost, final float estimateCost) {
        this.position.assign(position);
        this.positionIndex = positionIndex;
        this.open = true;
        this.estimateToGoal = estimateCost;
        this.travelCost = cost;
        this.totalCost = this.travelCost + this.estimateToGoal;
        this.predecessor = null;
        this.predecessorDirection = -1;
        Arrays.fill(this.successors, null);
        Arrays.fill(this.stepCost, 0.0f);
        this.length = 1;
        return this;
    }
    
    @Nonnull
    public AStarNode initWithPredecessor(@Nonnull final AStarNode predecessor, final int directionIndex, @Nonnull final Vector3d position, final long positionIndex, final int inverseDirectionIndex, final float travelCost, final float estimateCost) {
        this.position.assign(position);
        this.positionIndex = positionIndex;
        this.open = true;
        this.estimateToGoal = estimateCost;
        this.travelCost = travelCost;
        this.totalCost = this.travelCost + this.estimateToGoal;
        this.length = predecessor.length + 1;
        Arrays.fill(this.successors, null);
        Arrays.fill(this.stepCost, 0.0f);
        predecessor.setSuccessor(directionIndex, this, inverseDirectionIndex, travelCost - predecessor.travelCost);
        this.predecessor = predecessor;
        this.predecessorDirection = directionIndex;
        return this;
    }
    
    @Nonnull
    public AStarNode initAsInvalid(@Nonnull final Vector3d position, final long positionIndex) {
        this.position.assign(position);
        this.positionIndex = positionIndex;
        this.open = false;
        this.estimateToGoal = Float.MAX_VALUE;
        this.travelCost = Float.MAX_VALUE;
        this.totalCost = Float.MAX_VALUE;
        this.predecessor = null;
        this.predecessorDirection = -1;
        Arrays.fill(this.successors, null);
        Arrays.fill(this.stepCost, 0.0f);
        this.length = -1;
        return this;
    }
    
    public void adjustOptimalPath(final AStarNode parentNode, final float deltaCost, final int direction) {
        this.predecessor = parentNode;
        this.predecessorDirection = direction;
        this.travelCost += deltaCost;
        this.totalCost = this.travelCost + this.estimateToGoal;
        this.length = this.predecessor.length + 1;
        for (int successorDirection = 0; successorDirection < this.successors.length; ++successorDirection) {
            final AStarNode successor = this.successors[successorDirection];
            if (successor != null && !AStarNode.ENTRY_NODE_TAG.equals(successor)) {
                final float delta = this.travelCost + this.stepCost[successorDirection] - successor.travelCost;
                if (delta < 0.0f) {
                    successor.adjustOptimalPath(this, deltaCost, successorDirection);
                }
            }
        }
    }
    
    @Nonnull
    @Override
    public String toString() {
        return "AStarNode{position=" + String.valueOf(this.position) + ", travelCost=" + this.travelCost + ", estimateToGoal=" + this.estimateToGoal + ", totalCost=" + this.totalCost + ", predecessorDirection=" + this.predecessorDirection + ", stepCost=" + Arrays.toString(this.stepCost) + ", length=" + this.length + ", positionIndex=" + this.positionIndex + ", open=" + this.open;
    }
    
    static {
        ENTRY_NODE_TAG = new AStarNode(0);
    }
}
