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

package com.hypixel.hytale.server.npc.corecomponents.movement.builders;

import com.hypixel.hytale.server.npc.asset.builder.BuilderSupport;
import com.hypixel.hytale.server.npc.asset.builder.validators.StringValidator;
import com.hypixel.hytale.server.npc.asset.builder.validators.IntSingleValidator;
import com.hypixel.hytale.server.npc.asset.builder.validators.DoubleArrayValidator;
import com.hypixel.hytale.server.npc.asset.builder.validators.DoubleSequenceValidator;
import com.hypixel.hytale.server.npc.asset.builder.validators.DoubleSingleValidator;
import com.hypixel.hytale.server.npc.asset.builder.validators.DoubleValidator;
import com.hypixel.hytale.server.npc.asset.builder.BuilderDescriptorState;
import com.hypixel.hytale.server.npc.asset.builder.validators.DoubleRangeValidator;
import com.google.gson.JsonElement;
import com.hypixel.hytale.server.npc.asset.builder.holder.NumberArrayHolder;
import com.hypixel.hytale.server.npc.asset.builder.holder.DoubleHolder;
import com.hypixel.hytale.server.npc.asset.builder.holder.BooleanHolder;
import com.hypixel.hytale.server.npc.asset.builder.holder.IntHolder;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.npc.corecomponents.movement.BodyMotionFindBase;
import java.util.EnumSet;
import com.hypixel.hytale.server.npc.instructions.BodyMotion;
import com.hypixel.hytale.server.npc.asset.builder.Builder;
import com.hypixel.hytale.server.npc.corecomponents.builders.BuilderBodyMotionBase;

public abstract class BuilderBodyMotionFindBase extends BuilderBodyMotionBase implements Builder<BodyMotion>
{
    protected static final double[] THROTTLE_DELAY;
    @Nonnull
    protected EnumSet<BodyMotionFindBase.DebugFlags> parsedDebugFlags;
    protected String debugFlags;
    protected final IntHolder nodesPerTick;
    protected final IntHolder maxPathLength;
    protected final IntHolder maxOpenNodes;
    protected final IntHolder maxTotalNodes;
    protected final BooleanHolder diagonalMoves;
    protected final BooleanHolder useBestPath;
    protected final BooleanHolder buildOptimisedPath;
    protected final IntHolder pathSmoothing;
    protected final DoubleHolder relativeSpeed;
    protected final DoubleHolder relativeSpeedWaypoint;
    protected final DoubleHolder waypointRadius;
    protected final DoubleHolder rejectionWeight;
    protected final DoubleHolder blendHeading;
    protected final BooleanHolder isAvoidingBlockDamage;
    protected final BooleanHolder isRelaxedMoveConstraints;
    protected final NumberArrayHolder throttleDelayRangeHolder;
    protected final IntHolder throttleIgnoreCount;
    protected final BooleanHolder useSteering;
    protected final BooleanHolder usePathfinder;
    protected final BooleanHolder skipSteering;
    protected final DoubleHolder minPathLength;
    protected final DoubleHolder desiredAltitudeWeight;
    protected final boolean enableSteering;
    
    public BuilderBodyMotionFindBase() {
        this.parsedDebugFlags = EnumSet.noneOf(BodyMotionFindBase.DebugFlags.class);
        this.nodesPerTick = new IntHolder();
        this.maxPathLength = new IntHolder();
        this.maxOpenNodes = new IntHolder();
        this.maxTotalNodes = new IntHolder();
        this.diagonalMoves = new BooleanHolder();
        this.useBestPath = new BooleanHolder();
        this.buildOptimisedPath = new BooleanHolder();
        this.pathSmoothing = new IntHolder();
        this.relativeSpeed = new DoubleHolder();
        this.relativeSpeedWaypoint = new DoubleHolder();
        this.waypointRadius = new DoubleHolder();
        this.rejectionWeight = new DoubleHolder();
        this.blendHeading = new DoubleHolder();
        this.isAvoidingBlockDamage = new BooleanHolder();
        this.isRelaxedMoveConstraints = new BooleanHolder();
        this.throttleDelayRangeHolder = new NumberArrayHolder();
        this.throttleIgnoreCount = new IntHolder();
        this.useSteering = new BooleanHolder();
        this.usePathfinder = new BooleanHolder();
        this.skipSteering = new BooleanHolder();
        this.minPathLength = new DoubleHolder();
        this.desiredAltitudeWeight = new DoubleHolder();
        this.enableSteering = true;
    }
    
    public BuilderBodyMotionFindBase(final boolean enableSteering) {
        this.parsedDebugFlags = EnumSet.noneOf(BodyMotionFindBase.DebugFlags.class);
        this.nodesPerTick = new IntHolder();
        this.maxPathLength = new IntHolder();
        this.maxOpenNodes = new IntHolder();
        this.maxTotalNodes = new IntHolder();
        this.diagonalMoves = new BooleanHolder();
        this.useBestPath = new BooleanHolder();
        this.buildOptimisedPath = new BooleanHolder();
        this.pathSmoothing = new IntHolder();
        this.relativeSpeed = new DoubleHolder();
        this.relativeSpeedWaypoint = new DoubleHolder();
        this.waypointRadius = new DoubleHolder();
        this.rejectionWeight = new DoubleHolder();
        this.blendHeading = new DoubleHolder();
        this.isAvoidingBlockDamage = new BooleanHolder();
        this.isRelaxedMoveConstraints = new BooleanHolder();
        this.throttleDelayRangeHolder = new NumberArrayHolder();
        this.throttleIgnoreCount = new IntHolder();
        this.useSteering = new BooleanHolder();
        this.usePathfinder = new BooleanHolder();
        this.skipSteering = new BooleanHolder();
        this.minPathLength = new DoubleHolder();
        this.desiredAltitudeWeight = new DoubleHolder();
        this.enableSteering = enableSteering;
    }
    
    @Nonnull
    @Override
    public BuilderBodyMotionFindBase readConfig(@Nonnull final JsonElement data) {
        this.getDouble(data, "RelativeSpeed", this.relativeSpeed, 1.0, DoubleRangeValidator.fromExclToIncl(0.0, 2.0), BuilderDescriptorState.Stable, "Maximum relative speed the NPC should move", null);
        this.getDouble(data, "RelativeSpeedWaypoint", this.relativeSpeedWaypoint, 0.5, DoubleRangeValidator.fromExclToIncl(0.0, 1.0), BuilderDescriptorState.Stable, "Maximum relative speed the NPC should move close to waypoints", null);
        this.getDouble(data, "WaypointRadius", this.waypointRadius, 0.5, DoubleSingleValidator.greater(0.1), BuilderDescriptorState.Stable, "Radius to slow down around waypoints", null);
        this.getBoolean(data, "UseBestPath", this.useBestPath, true, BuilderDescriptorState.Stable, "Use best partial path if goal can't be reached", null);
        this.getDoubleRange(data, "ThrottleDelayRange", this.throttleDelayRangeHolder, BuilderBodyMotionFindBase.THROTTLE_DELAY, DoubleSequenceValidator.betweenWeaklyMonotonic(0.0, Double.MAX_VALUE), BuilderDescriptorState.Stable, "Time to delay after no path finding solution found", null);
        this.getInt(data, "ThrottleIgnoreCount", this.throttleIgnoreCount, 3, IntSingleValidator.greaterEqual0(), BuilderDescriptorState.Stable, "How often no valid path solution can be found before throttling delay is applied", null);
        this.getBoolean(data, "BuildOptimisedPath", this.buildOptimisedPath, true, BuilderDescriptorState.Stable, "Try to reduce number of nodes of generated path", null);
        this.getBoolean(data, "AvoidBlockDamage", this.isAvoidingBlockDamage, true, BuilderDescriptorState.Stable, "Should avoid environmental damage from blocks", null);
        this.getBoolean(data, "RelaxedMoveConstraints", this.isRelaxedMoveConstraints, true, BuilderDescriptorState.Stable, "NPC can do movements like wading (depends on motion controller type)", null);
        this.getDouble(data, "BlendHeading", this.blendHeading, 0.5, DoubleRangeValidator.between01(), BuilderDescriptorState.Stable, "Relative rotation angle into next waypoint when arriving at current waypoint", null);
        this.getInt(data, "PathSmoothing", this.pathSmoothing, 2, IntSingleValidator.greaterEqual0(), BuilderDescriptorState.Stable, "Try to smooth followed path. Larger values smooth more.", null);
        this.getDouble(data, "RejectionWeight", this.rejectionWeight, 3.0, DoubleSingleValidator.greater0(), BuilderDescriptorState.Stable, "Weight of rejection vector pushing entity closer to original path", null);
        if (this.enableSteering) {
            this.getBoolean(data, "UseSteering", this.useSteering, true, BuilderDescriptorState.Stable, "Use simple/cheap steering if available", null);
            this.getBoolean(data, "SkipSteering", this.skipSteering, true, BuilderDescriptorState.Experimental, "Skip steering if target not reachable", null);
            this.getBoolean(data, "UsePathfinder", this.usePathfinder, true, BuilderDescriptorState.Stable, "Use path finder", null);
        }
        this.getDouble(data, "MinPathLength", this.minPathLength, 2.0, DoubleSingleValidator.greaterEqual0(), BuilderDescriptorState.Experimental, "Minimum length of path required when not able to reach target (should be greater equal 2)", null);
        this.getBoolean(data, "DiagonalMoves", this.diagonalMoves, true, BuilderDescriptorState.Stable, "Allow diagonal moves", null);
        this.getInt(data, "StepsPerTick", this.nodesPerTick, 50, IntSingleValidator.greater0(), BuilderDescriptorState.Stable, "Steps per iteration", null);
        this.getInt(data, "MaxPathLength", this.maxPathLength, 200, IntSingleValidator.greater0(), BuilderDescriptorState.Stable, "Max path steps before aborting path finding", null);
        this.getInt(data, "MaxOpenNodes", this.maxOpenNodes, 200, IntSingleValidator.greater0(), BuilderDescriptorState.Stable, "Max open nodes before aborting path finding", null);
        this.getInt(data, "MaxTotalNodes", this.maxTotalNodes, 900, IntSingleValidator.greater0(), BuilderDescriptorState.Stable, "Max total node before aborting path finding", null);
        this.getString(data, "Debug", e -> this.debugFlags = e, "", null, BuilderDescriptorState.Stable, "Debugging flags", null);
        this.getDouble(data, "DesiredAltitudeWeight", this.desiredAltitudeWeight, -1.0, DoubleRangeValidator.between(-1.0, 1.0), BuilderDescriptorState.Stable, "How much this NPC prefers being within the desired height range", "How much this NPC prefers being within the desired height range. 0 means it doesn't care much, 1 means it will do its best to get there fast. Values below 0 mean the default in the motion controller will be used.");
        if (this.debugFlags != null && !this.debugFlags.isEmpty()) {
            this.toSet("Debug", BodyMotionFindBase.DebugFlags.class, this.parsedDebugFlags, this.debugFlags);
        }
        return this;
    }
    
    @Nonnull
    public EnumSet<BodyMotionFindBase.DebugFlags> getParsedDebugFlags() {
        return this.parsedDebugFlags;
    }
    
    public int getNodesPerTick(@Nonnull final BuilderSupport support) {
        return this.nodesPerTick.get(support.getExecutionContext());
    }
    
    public int getMaxPathLength(@Nonnull final BuilderSupport support) {
        return this.maxPathLength.get(support.getExecutionContext());
    }
    
    public int getMaxOpenNodes(@Nonnull final BuilderSupport support) {
        return this.maxOpenNodes.get(support.getExecutionContext());
    }
    
    public int getMaxTotalNodes(@Nonnull final BuilderSupport support) {
        return this.maxTotalNodes.get(support.getExecutionContext());
    }
    
    public boolean isDiagonalMoves(@Nonnull final BuilderSupport support) {
        return this.diagonalMoves.get(support.getExecutionContext());
    }
    
    public boolean getUseBestPath(@Nonnull final BuilderSupport support) {
        return this.useBestPath.get(support.getExecutionContext());
    }
    
    public boolean isBuildOptimisedPath(@Nonnull final BuilderSupport support) {
        return this.buildOptimisedPath.get(support.getExecutionContext());
    }
    
    public int getPathSmoothing(@Nonnull final BuilderSupport support) {
        return this.pathSmoothing.get(support.getExecutionContext());
    }
    
    public double getRelativeSpeed(@Nonnull final BuilderSupport support) {
        return this.relativeSpeed.get(support.getExecutionContext());
    }
    
    public double getRelativeSpeedWaypoint(@Nonnull final BuilderSupport support) {
        return this.relativeSpeedWaypoint.get(support.getExecutionContext());
    }
    
    public double getWaypointRadius(@Nonnull final BuilderSupport support) {
        return this.waypointRadius.get(support.getExecutionContext());
    }
    
    public double getRejectionWeight(@Nonnull final BuilderSupport support) {
        return this.rejectionWeight.get(support.getExecutionContext());
    }
    
    public double getBlendHeading(@Nonnull final BuilderSupport support) {
        return this.blendHeading.get(support.getExecutionContext());
    }
    
    public boolean isAvoidingBlockDamage(@Nonnull final BuilderSupport support) {
        return this.isAvoidingBlockDamage.get(support.getExecutionContext());
    }
    
    public boolean isRelaxedMoveConstraints(@Nonnull final BuilderSupport support) {
        return this.isRelaxedMoveConstraints.get(support.getExecutionContext());
    }
    
    public double[] getThrottleDelayRange(@Nonnull final BuilderSupport support) {
        return this.throttleDelayRangeHolder.get(support.getExecutionContext());
    }
    
    public int getThrottleIgnoreCount(@Nonnull final BuilderSupport support) {
        return this.throttleIgnoreCount.get(support.getExecutionContext());
    }
    
    public boolean isUseSteering(@Nonnull final BuilderSupport support) {
        return this.enableSteering && this.useSteering.get(support.getExecutionContext());
    }
    
    public boolean isUsePathfinder(@Nonnull final BuilderSupport support) {
        return !this.enableSteering || this.usePathfinder.get(support.getExecutionContext());
    }
    
    public boolean isSkipSteering(@Nonnull final BuilderSupport support) {
        return this.enableSteering && this.skipSteering.get(support.getExecutionContext());
    }
    
    public double getMinPathLength(@Nonnull final BuilderSupport support) {
        return this.minPathLength.get(support.getExecutionContext());
    }
    
    public double getDesiredAltitudeWeight(@Nonnull final BuilderSupport support) {
        return this.desiredAltitudeWeight.get(support.getExecutionContext());
    }
    
    static {
        THROTTLE_DELAY = new double[] { 3.0, 5.0 };
    }
}
