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

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

import com.hypixel.hytale.server.npc.asset.builder.Builder;
import com.hypixel.hytale.server.core.asset.type.model.config.Model;
import com.hypixel.hytale.server.spawning.SpawnTestResult;
import com.hypixel.hytale.server.spawning.SpawningContext;
import com.hypixel.hytale.server.npc.movement.controllers.MotionController;
import com.hypixel.hytale.server.npc.asset.builder.validators.RelationalOperator;
import com.hypixel.hytale.server.npc.asset.builder.validators.DoubleRangeValidator;
import com.hypixel.hytale.server.npc.asset.builder.validators.DoubleValidator;
import com.hypixel.hytale.server.npc.asset.builder.validators.DoubleSingleValidator;
import com.google.gson.JsonElement;
import com.hypixel.hytale.server.npc.movement.controllers.MotionControllerDive;
import com.hypixel.hytale.server.npc.asset.builder.BuilderSupport;
import com.hypixel.hytale.server.npc.asset.builder.BuilderDescriptorState;
import javax.annotation.Nonnull;

public class BuilderMotionControllerDive extends BuilderMotionControllerBase
{
    private double minHorizontalSpeed;
    private double maxVerticalSpeed;
    private double acceleration;
    private double gravity;
    private double maxFallSpeed;
    private double maxSinkSpeed;
    private double maxRotationSpeed;
    private float maxMoveTurnAngle;
    private double minDiveDepth;
    private double maxDiveDepth;
    private double minWaterDepth;
    private double maxWaterDepth;
    private double minDepthAboveGround;
    private double minDepthBelowSurface;
    private double swimDepth;
    private double sinkRatio;
    private double fastDiveThreshold;
    private double desiredDepthWeight;
    
    @Nonnull
    @Override
    public String getShortDescription() {
        return "Provide diving abilities for NPC";
    }
    
    @Nonnull
    @Override
    public String getLongDescription() {
        return this.getShortDescription();
    }
    
    @Nonnull
    @Override
    public BuilderDescriptorState getBuilderDescriptorState() {
        return BuilderDescriptorState.WorkInProgress;
    }
    
    @Nonnull
    @Override
    public MotionControllerDive build(@Nonnull final BuilderSupport builderSupport) {
        return new MotionControllerDive(builderSupport, this);
    }
    
    @Nonnull
    @Override
    public BuilderMotionControllerDive readConfig(@Nonnull final JsonElement data) {
        this.getDouble(data, "MaxSwimSpeed", this.maxHorizontalSpeed, 3.0, DoubleSingleValidator.greater0(), BuilderDescriptorState.Stable, "Maximum horizontal speed", null);
        this.getDouble(data, "MaxDiveSpeed", v -> this.maxVerticalSpeed = v, 8.0, DoubleSingleValidator.greater0(), BuilderDescriptorState.Stable, "Maximum vertical speed", null);
        this.getDouble(data, "MaxFallSpeed", v -> this.maxFallSpeed = v, 10.0, DoubleSingleValidator.greater0(), BuilderDescriptorState.Stable, "Terminal velocity falling in air", null);
        this.getDouble(data, "MaxSinkSpeed", v -> this.maxSinkSpeed = v, 4.0, DoubleSingleValidator.greater0(), BuilderDescriptorState.Stable, "Terminal velocity sinking in water", null);
        this.getDouble(data, "Gravity", v -> this.gravity = v, 10.0, DoubleSingleValidator.greater0(), BuilderDescriptorState.Stable, "Gravity", null);
        this.getDouble(data, "Acceleration", v -> this.acceleration = v, 3.0, DoubleSingleValidator.greater0(), BuilderDescriptorState.Stable, "Acceleration", null);
        this.getDouble(data, "MaxRotationSpeed", v -> this.maxRotationSpeed = v, 360.0, DoubleSingleValidator.greater0(), BuilderDescriptorState.Stable, "Maximum rotational speed in degrees", null);
        this.getFloat(data, "MaxSwimTurnAngle", v -> this.maxMoveTurnAngle = v, 90.0f, DoubleRangeValidator.between(0.0, 180.0), BuilderDescriptorState.WorkInProgress, "Maximum angle NPC can walk without explicit turning in degrees", null);
        this.validateDoubleRelation("MinSwimSpeed", this.minHorizontalSpeed, RelationalOperator.LessEqual, this.maxHorizontalSpeed);
        this.getDouble(data, "FastSwimThreshold", v -> this.fastDiveThreshold = v, 0.6, DoubleRangeValidator.between01(), BuilderDescriptorState.WorkInProgress, "Relative threshold when fast swimming animation should be used", null);
        this.getDouble(data, "SwimDepth", v -> this.swimDepth = v, 0.4, DoubleRangeValidator.between(-1.0, 1.0), BuilderDescriptorState.WorkInProgress, "Minimum height NPC needs to be submerged to be able to swim", "0 is at eye height, -1 is bottom of bounding box, +1 top of bounding box. other values between -1 and +1 scale linear");
        this.getDouble(data, "SinkRatio", v -> this.sinkRatio = v, 1.0, DoubleSingleValidator.greaterEqual0(), BuilderDescriptorState.WorkInProgress, "Relative sink or climb speed while wandering", null);
        this.getDouble(data, "MinDiveDepth", v -> this.minDiveDepth = v, 0.0, DoubleSingleValidator.greaterEqual0(), BuilderDescriptorState.Unknown, null, null);
        this.getDouble(data, "MaxDiveDepth", v -> this.maxDiveDepth = v, Double.MAX_VALUE, DoubleSingleValidator.greater0(), BuilderDescriptorState.WorkInProgress, "Maximum dive depth below surface desired", null);
        this.getDouble(data, "MinDepthAboveGround", v -> this.minDepthAboveGround = v, 1.0, DoubleSingleValidator.greaterEqual0(), BuilderDescriptorState.WorkInProgress, "Minimum distance from ground desired", null);
        this.getDouble(data, "MinDepthBelowSurface", v -> this.minDepthBelowSurface = v, 1.0, DoubleSingleValidator.greaterEqual0(), BuilderDescriptorState.WorkInProgress, "Minimum distance from water surface desired", null);
        this.getDouble(data, "MinWaterDepth", v -> this.minWaterDepth = v, 1.0, DoubleSingleValidator.greaterEqual0(), BuilderDescriptorState.Unknown, null, null);
        this.getDouble(data, "MaxWaterDepth", v -> this.maxWaterDepth = v, 0.0, DoubleSingleValidator.greaterEqual0(), BuilderDescriptorState.Unknown, null, null);
        this.getDouble(data, "DesiredDepthWeight", v -> this.desiredDepthWeight = v, 0.0, DoubleRangeValidator.between(0.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.");
        return this;
    }
    
    @Nonnull
    @Override
    public Class<MotionController> category() {
        return MotionController.class;
    }
    
    public double getMinHorizontalSpeed() {
        return this.minHorizontalSpeed;
    }
    
    public double getAcceleration() {
        return this.acceleration;
    }
    
    public double getMaxVerticalSpeed() {
        return this.maxVerticalSpeed;
    }
    
    public double getGravity() {
        return this.gravity;
    }
    
    public double getMaxFallSpeed() {
        return this.maxFallSpeed;
    }
    
    public double getMaxSinkSpeed() {
        return this.maxSinkSpeed;
    }
    
    public float getMaxMoveTurnAngle() {
        return 0.017453292f * this.maxMoveTurnAngle;
    }
    
    public double getMaxRotationSpeed() {
        return this.maxRotationSpeed * 0.01745329238474369;
    }
    
    public double getMinDiveDepth() {
        return this.minDiveDepth;
    }
    
    public double getMaxDiveDepth() {
        return this.maxDiveDepth;
    }
    
    public double getMinWaterDepth() {
        return this.minWaterDepth;
    }
    
    public double getMaxWaterDepth() {
        return this.maxWaterDepth;
    }
    
    public double getMinDepthAboveGround() {
        return this.minDepthAboveGround;
    }
    
    public double getMinDepthBelowSurface() {
        return this.minDepthBelowSurface;
    }
    
    public double getSwimDepth() {
        return this.swimDepth;
    }
    
    public double getSinkRatio() {
        return this.sinkRatio;
    }
    
    public double getFastDiveThreshold() {
        return this.fastDiveThreshold;
    }
    
    public double getDesiredDepthWeight() {
        return this.desiredDepthWeight;
    }
    
    @Nonnull
    @Override
    public SpawnTestResult canSpawn(@Nonnull final SpawningContext context) {
        final Model model = context.getModel();
        final double swimDepth = (model == null) ? 0.5 : MotionControllerDive.relativeSwimDepthToHeight(this.getSwimDepth(), model.getBoundingBox(), model.getEyeHeight());
        if (!context.isInWater((float)swimDepth)) {
            return SpawnTestResult.FAIL_NO_POSITION;
        }
        return context.validatePosition(20) ? SpawnTestResult.TEST_OK : SpawnTestResult.FAIL_INVALID_POSITION;
    }
    
    @Nonnull
    @Override
    public Class<? extends MotionController> getClassType() {
        return MotionControllerDive.class;
    }
}
