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

package com.hypixel.hytale.server.npc.instructions.builders;

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.DoubleValidator;
import com.hypixel.hytale.server.npc.asset.builder.validators.DoubleSingleValidator;
import com.hypixel.hytale.server.npc.asset.builder.validators.ArrayValidator;
import com.hypixel.hytale.server.npc.asset.builder.BuilderObjectArrayHelper;
import com.hypixel.hytale.server.npc.asset.builder.BuilderObjectReferenceHelper;
import com.hypixel.hytale.server.npc.asset.builder.validators.StringNullOrNotEmptyValidator;
import com.hypixel.hytale.server.npc.asset.builder.validators.StringValidator;
import com.hypixel.hytale.server.npc.asset.builder.BuilderDescriptorState;
import com.hypixel.hytale.server.npc.asset.builder.BuilderValidationHelper;
import com.hypixel.hytale.server.npc.asset.builder.FeatureEvaluatorHelper;
import com.hypixel.hytale.server.npc.asset.builder.Builder;
import com.google.gson.JsonElement;
import javax.annotation.Nullable;
import com.hypixel.hytale.server.npc.instructions.Instruction;
import com.hypixel.hytale.server.npc.instructions.Sensor;
import com.hypixel.hytale.server.npc.instructions.InstructionRandomized;
import com.hypixel.hytale.server.npc.asset.builder.BuilderSupport;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.npc.asset.builder.holder.NumberArrayHolder;
import com.hypixel.hytale.server.npc.asset.builder.holder.BooleanHolder;

public class BuilderInstructionRandomized extends BuilderInstruction
{
    public static final double[] DEFAULT_EXECUTION_RANGE;
    protected final BooleanHolder resetOnStateChange;
    protected final NumberArrayHolder executeFor;
    
    public BuilderInstructionRandomized() {
        this.resetOnStateChange = new BooleanHolder();
        this.executeFor = new NumberArrayHolder();
    }
    
    @Nonnull
    @Override
    public String getShortDescription() {
        return "Randomised list of weighted instructions.";
    }
    
    @Nonnull
    @Override
    public String getLongDescription() {
        return "Randomised list of weighted instructions. One will be selected at random and executed until the NPC state changes.";
    }
    
    @Nullable
    @Override
    public InstructionRandomized build(@Nonnull final BuilderSupport builderSupport) {
        if (!this.enabled.get(builderSupport.getExecutionContext())) {
            return null;
        }
        Sensor sensor;
        if (this.sensorBuilderObjectReferenceHelper.isPresent()) {
            sensor = this.getSensor(builderSupport);
            if (sensor == null) {
                return null;
            }
        }
        else {
            sensor = Sensor.NULL;
        }
        if (this.currentStateName != null) {
            builderSupport.pushCurrentStateName(this.currentStateName);
        }
        final Instruction[] instructionList = (Instruction[])(this.hasNestedInstructions() ? this.getSteps(builderSupport) : null);
        if (instructionList == null) {
            if (this.currentStateName != null) {
                builderSupport.popCurrentStateName();
            }
            return null;
        }
        if (this.currentStateName != null) {
            builderSupport.popCurrentStateName();
        }
        return new InstructionRandomized(this, sensor, instructionList, builderSupport);
    }
    
    @Nonnull
    @Override
    public Builder<Instruction> readConfig(@Nonnull final JsonElement data) {
        final FeatureEvaluatorHelper features = new FeatureEvaluatorHelper();
        final BuilderValidationHelper helper = new BuilderValidationHelper(this.fileName, features, this.internalReferenceResolver, this.stateHelper, this.instructionContextHelper, this.extraInfo, this.evaluators, this.readErrors);
        this.increaseDepth();
        if (this.requiresName()) {
            this.requireString(data, "Name", v -> this.name = v, null, BuilderDescriptorState.Stable, "Name for referencing", null);
        }
        else {
            this.getString(data, "Name", v -> this.name = v, null, null, BuilderDescriptorState.Stable, "Optional name for descriptor", null);
        }
        this.getString(data, "Tag", v -> this.tag = v, null, StringNullOrNotEmptyValidator.get(), BuilderDescriptorState.Experimental, "Internal identifier tag for debugging", null);
        this.getBoolean(data, "Enabled", this.enabled, true, BuilderDescriptorState.Stable, "Whether this step should be enabled on the NPC", null);
        this.getObject(data, "Sensor", this.sensorBuilderObjectReferenceHelper, BuilderDescriptorState.Stable, "Sensor for testing if step can be applied", "Sensor for testing if step can be applied. If not supplied, will always match", helper);
        features.lock();
        this.getArray(data, "Instructions", this.steps, null, BuilderDescriptorState.Stable, "List of weighted instructions to select from", null, new BuilderValidationHelper(this.fileName, null, this.internalReferenceResolver, this.stateHelper, this.instructionContextHelper, this.extraInfo, this.evaluators, this.readErrors));
        this.getBoolean(data, "Continue", v -> this.continueAfter = v, false, BuilderDescriptorState.WorkInProgress, "Continue after this step was executed", null);
        this.getDouble(data, "Weight", this.chance, 1.0, DoubleSingleValidator.greater0(), BuilderDescriptorState.Stable, "Weighted chance of picking this step in a random selector", null);
        this.getBoolean(data, "TreeMode", v -> this.treeMode = v, false, BuilderDescriptorState.Stable, "Whether this step and its contents should be treated like a traditional behaviour tree.", "Whether this step and its contents should be treated like a traditional behaviour tree, i.e. will continue if all child steps fail");
        this.getBoolean(data, "InvertTreeModeResult", this.invertTreeModeResult, false, BuilderDescriptorState.Stable, "Whether or not to invert the result of TreeMode evaluation when passing up to parent TreeMode steps", null);
        this.getBoolean(data, "ResetOnStateChange", this.resetOnStateChange, true, BuilderDescriptorState.Stable, "Whether to reset when NPC state changes", null);
        this.getDoubleRange(data, "ExecuteFor", this.executeFor, BuilderInstructionRandomized.DEFAULT_EXECUTION_RANGE, DoubleSequenceValidator.fromExclToInclWeaklyMonotonic(0.0, Double.MAX_VALUE), BuilderDescriptorState.Stable, "How long to execute the chosen step before picking another", null);
        this.decreaseDepth();
        this.validateBooleanImplicationAnyAntecedent(BuilderInstructionRandomized.ANTECEDENT, new boolean[] { this.treeMode }, true, BuilderInstructionRandomized.SUBSEQUENT, new boolean[] { this.continueAfter }, false);
        return this;
    }
    
    @Nonnull
    @Override
    public BuilderDescriptorState getBuilderDescriptorState() {
        return BuilderDescriptorState.Stable;
    }
    
    public boolean getResetOnStateChange(@Nonnull final BuilderSupport support) {
        return this.resetOnStateChange.get(support.getExecutionContext());
    }
    
    public double[] getExecuteFor(@Nonnull final BuilderSupport support) {
        return this.executeFor.get(support.getExecutionContext());
    }
    
    static {
        DEFAULT_EXECUTION_RANGE = new double[] { Double.MAX_VALUE, Double.MAX_VALUE };
    }
}
