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

package com.hypixel.hytale.server.npc.corecomponents.utility;

import com.hypixel.hytale.server.npc.util.expression.Scope;
import com.hypixel.hytale.server.npc.sensorinfo.InfoProvider;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.npc.role.Role;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.npc.util.expression.StdScope;
import com.hypixel.hytale.server.npc.util.expression.ValueType;
import java.util.List;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import com.hypixel.hytale.server.npc.corecomponents.builders.BuilderSensorBase;
import com.hypixel.hytale.server.npc.asset.builder.BuilderSupport;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderSensorEval;
import com.hypixel.hytale.server.npc.util.expression.ExecutionContext;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.npc.util.expression.compile.CompileContext;
import com.hypixel.hytale.server.npc.corecomponents.SensorBase;

public class SensorEval extends SensorBase
{
    protected final String expression;
    @Nonnull
    protected final CompileContext compileContext;
    protected ExecutionContext.Instruction[] instructions;
    protected boolean isValid;
    
    public SensorEval(@Nonnull final BuilderSensorEval builderSensorEval, @Nonnull final BuilderSupport support) {
        super(builderSensorEval);
        this.expression = builderSensorEval.getExpression();
        this.compileContext = new CompileContext();
        this.isValid = true;
        try {
            final ObjectArrayList<ExecutionContext.Instruction> instructions = new ObjectArrayList<ExecutionContext.Instruction>();
            final StdScope scope = support.getSensorScope();
            final ValueType valueType = this.compile(this.expression, scope, instructions);
            if (valueType != ValueType.BOOLEAN) {
                this.isValid = false;
                throw new IllegalStateException("Expression '" + this.expression + "' must return boolean value but is:" + String.valueOf(valueType));
            }
            this.instructions = instructions.toArray(ExecutionContext.Instruction[]::new);
        }
        catch (final RuntimeException e) {
            this.isValid = false;
            throw new RuntimeException("Error evaluating '" + this.expression, (Throwable)e);
        }
    }
    
    @Override
    public boolean matches(@Nonnull final Ref<EntityStore> ref, @Nonnull final Role role, final double dt, @Nonnull final Store<EntityStore> store) {
        return super.matches(ref, role, dt, store) && this.isValid && this.evalBoolean(role.getEntitySupport().getSensorScope(), this.instructions);
    }
    
    @Override
    public InfoProvider getSensorInfo() {
        return null;
    }
    
    protected ValueType compile(@Nonnull final String expression, final StdScope sensorScope, final List<ExecutionContext.Instruction> instructions) {
        return this.compileContext.compile(expression, sensorScope, true, instructions);
    }
    
    protected boolean evalBoolean(final StdScope sensorScope, @Nonnull final ExecutionContext.Instruction[] instructions) {
        final ExecutionContext executionContext = this.compileContext.getExecutionContext();
        if (executionContext.execute(instructions, sensorScope) != ValueType.BOOLEAN) {
            throw new IllegalStateException("Expression must return boolean value");
        }
        return executionContext.popBoolean();
    }
}
