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

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

import com.hypixel.hytale.server.npc.asset.builder.Builder;
import com.hypixel.hytale.server.npc.movement.controllers.MotionController;
import com.hypixel.hytale.server.npc.movement.controllers.MotionControllerWalk;
import java.util.List;
import com.hypixel.hytale.server.npc.util.expression.Scope;
import com.hypixel.hytale.server.npc.util.expression.ExecutionContext;
import com.hypixel.hytale.server.npc.validators.NPCLoadTimeValidationHelper;
import com.hypixel.hytale.server.npc.asset.builder.Feature;
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.validators.DoubleRangeValidator;
import com.hypixel.hytale.server.npc.asset.builder.validators.DoubleArrayValidator;
import com.hypixel.hytale.server.npc.asset.builder.validators.DoubleSequenceValidator;
import com.google.gson.JsonElement;
import com.hypixel.hytale.server.npc.asset.builder.BuilderDescriptorState;
import com.hypixel.hytale.server.npc.corecomponents.movement.BodyMotionMaintainDistance;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.npc.asset.builder.BuilderSupport;
import com.hypixel.hytale.server.npc.asset.builder.holder.DoubleHolder;
import com.hypixel.hytale.server.npc.asset.builder.holder.NumberArrayHolder;
import com.hypixel.hytale.server.npc.corecomponents.builders.BuilderBodyMotionBase;

public class BuilderBodyMotionMaintainDistance extends BuilderBodyMotionBase
{
    public static final String MIN_RANGE_PARAMETER = "MinRange";
    public static final String MAX_RANGE_PARAMETER = "MaxRange";
    public static final String POSITIONING_ANGLE_PARAMETER = "PositioningAngle";
    public static final double NO_POSITIONING = Double.MAX_VALUE;
    public static final double[] DEFAULT_STRAFING_DURATION_RANGE;
    public static final double[] DEFAULT_STRAFING_FREQUENCY_RANGE;
    protected final NumberArrayHolder desiredDistanceRange;
    protected final DoubleHolder targetDistanceFactor;
    protected final DoubleHolder moveThreshold;
    protected final DoubleHolder relativeForwardsSpeed;
    protected final DoubleHolder relativeBackwardsSpeed;
    protected final DoubleHolder moveTowardsSlowdownThreshold;
    protected final NumberArrayHolder strafingDurationRange;
    protected final NumberArrayHolder strafingFrequencyRange;
    
    public BuilderBodyMotionMaintainDistance() {
        this.desiredDistanceRange = new NumberArrayHolder();
        this.targetDistanceFactor = new DoubleHolder();
        this.moveThreshold = new DoubleHolder();
        this.relativeForwardsSpeed = new DoubleHolder();
        this.relativeBackwardsSpeed = new DoubleHolder();
        this.moveTowardsSlowdownThreshold = new DoubleHolder();
        this.strafingDurationRange = new NumberArrayHolder();
        this.strafingFrequencyRange = new NumberArrayHolder();
    }
    
    @Nonnull
    @Override
    public BodyMotionMaintainDistance build(@Nonnull final BuilderSupport builderSupport) {
        return new BodyMotionMaintainDistance(this, builderSupport);
    }
    
    @Nonnull
    @Override
    public String getShortDescription() {
        return "Maintain distance from a given position";
    }
    
    @Nonnull
    @Override
    public String getLongDescription() {
        return this.getShortDescription();
    }
    
    @Nonnull
    @Override
    public BuilderDescriptorState getBuilderDescriptorState() {
        return BuilderDescriptorState.Stable;
    }
    
    @Nonnull
    @Override
    public BuilderBodyMotionMaintainDistance readConfig(@Nonnull final JsonElement data) {
        this.requireDoubleRange(data, "DesiredDistanceRange", this.desiredDistanceRange, DoubleSequenceValidator.betweenWeaklyMonotonic(-1.7976931348623157E308, Double.MAX_VALUE), BuilderDescriptorState.Stable, "The desired distance to remain at.", null);
        this.getDouble(data, "TargetDistanceFactor", this.targetDistanceFactor, 0.5, DoubleRangeValidator.between(0.0, 1.0), BuilderDescriptorState.Stable, "A factor used to decide what distance to move to within the target range.", "A factor used to decide what distance to move to within the target range when the target falls outside of it. 0 will result in moving the shortest distance to fall within the range, 1 the furthest distance, and 0.5 roughly the middle of the range.");
        this.getDouble(data, "MoveThreshold", this.moveThreshold, 1.0, DoubleSingleValidator.greater0(), BuilderDescriptorState.Stable, "An extra threshold distance on either side of the desired range before the NPC will trigger movement.", null);
        this.getDouble(data, "RelativeForwardsSpeed", this.relativeForwardsSpeed, 1.0, DoubleRangeValidator.fromExclToIncl(0.0, 2.0), BuilderDescriptorState.Stable, "Maximum relative speed for the NPC moving forwards", null);
        this.getDouble(data, "RelativeBackwardsSpeed", this.relativeBackwardsSpeed, 1.0, DoubleRangeValidator.fromExclToIncl(0.0, 2.0), BuilderDescriptorState.Stable, "Maximum relative speed for the NPC moving backwards", null);
        this.getDouble(data, "MoveTowardsSlowdownThreshold", this.moveTowardsSlowdownThreshold, 2.0, DoubleSingleValidator.greaterEqual0(), BuilderDescriptorState.Stable, "The distance away from the target stopping point at which the NPC will start to slow down while moving towards the target", null);
        this.getDoubleRange(data, "StrafingDurationRange", this.strafingDurationRange, BuilderBodyMotionMaintainDistance.DEFAULT_STRAFING_DURATION_RANGE, DoubleSequenceValidator.betweenWeaklyMonotonic(0.0, Double.MAX_VALUE), BuilderDescriptorState.Stable, "How long to strafe for.", "How long to strafe for (moving left or right around the target). If set to [ 0, 0 ], will not move horizontally at all.");
        this.getDoubleRange(data, "StrafingFrequencyRange", this.strafingFrequencyRange, BuilderBodyMotionMaintainDistance.DEFAULT_STRAFING_FREQUENCY_RANGE, DoubleSequenceValidator.fromExclToInclWeaklyMonotonic(0.0, Double.MAX_VALUE), BuilderDescriptorState.Stable, "How frequently to execute strafing", null);
        this.requireFeature(Feature.AnyPosition);
        return this;
    }
    
    @Override
    public boolean validate(final String configName, @Nonnull final NPCLoadTimeValidationHelper validationHelper, final ExecutionContext context, final Scope globalScope, @Nonnull final List<String> errors) {
        final boolean result = super.validate(configName, validationHelper, context, globalScope, errors);
        validationHelper.requireMotionControllerType(MotionControllerWalk.class);
        return result;
    }
    
    public double[] getDesiredDistanceRange(@Nonnull final BuilderSupport support) {
        return this.desiredDistanceRange.get(support.getExecutionContext());
    }
    
    public double getTargetDistanceFactor(@Nonnull final BuilderSupport support) {
        return this.targetDistanceFactor.get(support.getExecutionContext());
    }
    
    public double getMoveThreshold(@Nonnull final BuilderSupport support) {
        return this.moveThreshold.get(support.getExecutionContext());
    }
    
    public double getRelativeForwardsSpeed(@Nonnull final BuilderSupport support) {
        return this.relativeForwardsSpeed.get(support.getExecutionContext());
    }
    
    public double getRelativeBackwardsSpeed(@Nonnull final BuilderSupport support) {
        return this.relativeBackwardsSpeed.get(support.getExecutionContext());
    }
    
    public double getMoveTowardsSlowdownThreshold(@Nonnull final BuilderSupport support) {
        return this.moveTowardsSlowdownThreshold.get(support.getExecutionContext());
    }
    
    public double[] getStrafingDurationRange(@Nonnull final BuilderSupport support) {
        return this.strafingDurationRange.get(support.getExecutionContext());
    }
    
    public double[] getStrafingFrequencyRange(@Nonnull final BuilderSupport support) {
        return this.strafingFrequencyRange.get(support.getExecutionContext());
    }
    
    static {
        DEFAULT_STRAFING_DURATION_RANGE = new double[] { 0.0, 0.0 };
        DEFAULT_STRAFING_FREQUENCY_RANGE = new double[] { 2.0, 2.0 };
    }
}
