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

package com.hypixel.hytale.server.npc.asset.builder.expression;

import com.hypixel.hytale.codec.schema.config.BooleanSchema;
import com.hypixel.hytale.codec.schema.config.StringSchema;
import com.hypixel.hytale.codec.schema.config.NumberSchema;
import com.hypixel.hytale.codec.schema.config.ArraySchema;
import com.hypixel.hytale.codec.schema.NamedSchema;
import com.hypixel.hytale.codec.schema.SchemaConvertable;
import com.hypixel.hytale.codec.schema.config.Schema;
import com.hypixel.hytale.codec.schema.SchemaContext;
import com.google.gson.JsonArray;
import com.google.gson.JsonPrimitive;
import com.hypixel.hytale.server.npc.asset.builder.BuilderParameters;
import com.google.gson.JsonElement;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.npc.util.expression.StdScope;
import javax.annotation.Nullable;
import com.hypixel.hytale.server.npc.util.expression.ExecutionContext;
import com.hypixel.hytale.server.npc.util.expression.ValueType;

public abstract class BuilderExpression
{
    public static final String STATIC = "<STATIC>";
    
    public abstract ValueType getType();
    
    public abstract boolean isStatic();
    
    public double getNumber(final ExecutionContext executionContext) {
        throw new IllegalStateException("BuilderExpression: Reading number is not supported");
    }
    
    public String getString(final ExecutionContext executionContext) {
        throw new IllegalStateException("BuilderExpression: Reading string is not supported");
    }
    
    public boolean getBoolean(final ExecutionContext executionContext) {
        throw new IllegalStateException("BuilderExpression: Reading boolean is not supported");
    }
    
    public double[] getNumberArray(final ExecutionContext executionContext) {
        throw new IllegalStateException("BuilderExpression: Reading number array is not supported");
    }
    
    public int[] getIntegerArray(final ExecutionContext executionContext) {
        throw new IllegalStateException("BuilderExpression: Reading integer is not supported");
    }
    
    @Nullable
    public String[] getStringArray(final ExecutionContext executionContext) {
        throw new IllegalStateException("BuilderExpression: Reading string array is not supported");
    }
    
    public boolean[] getBooleanArray(final ExecutionContext executionContext) {
        throw new IllegalStateException("BuilderExpression: Reading boolean array is not supported");
    }
    
    public void addToScope(final String name, final StdScope scope) {
        throw new IllegalStateException("This type of builder expression cannot be added to a scope");
    }
    
    public void updateScope(final StdScope scope, final String name, final ExecutionContext executionContext) {
        throw new IllegalStateException("This type of builder expression cannot update a scope");
    }
    
    public String getExpression() {
        return "<STATIC>";
    }
    
    @Nonnull
    public static BuilderExpression fromOperand(@Nonnull final ExecutionContext.Operand operand) {
        return switch (operand.type) {
            case NUMBER -> new BuilderExpressionStaticNumber(operand.number);
            case STRING -> new BuilderExpressionStaticString(operand.string);
            case BOOLEAN -> new BuilderExpressionStaticBoolean(operand.bool);
            case EMPTY_ARRAY -> BuilderExpressionStaticEmptyArray.INSTANCE;
            case NUMBER_ARRAY -> new BuilderExpressionStaticNumberArray(operand.numberArray);
            case STRING_ARRAY -> new BuilderExpressionStaticStringArray(operand.stringArray);
            case BOOLEAN_ARRAY -> new BuilderExpressionStaticBooleanArray(operand.boolArray);
            default -> throw new IllegalStateException("Operand cannot be converted to builder expression");
        };
    }
    
    @Nonnull
    public static BuilderExpression fromJSON(@Nonnull final JsonElement jsonElement, @Nonnull final BuilderParameters builderParameters, final boolean constantsOnly) {
        final BuilderExpression builderExpression = fromJSON(jsonElement, builderParameters);
        if (constantsOnly && !builderExpression.isStatic()) {
            throw new IllegalArgumentException("Only constant string, number or boolean or arrays allowed, found: " + String.valueOf(jsonElement));
        }
        return builderExpression;
    }
    
    @Nonnull
    public static BuilderExpression fromJSON(@Nonnull final JsonElement jsonElement, @Nonnull final BuilderParameters builderParameters, final ValueType expectedType) {
        final BuilderExpression builderExpression = fromJSON(jsonElement, builderParameters);
        if (!ValueType.isAssignableType(builderExpression.getType(), expectedType)) {
            throw new IllegalStateException("Expression type mismatch. Got " + String.valueOf(builderExpression.getType()) + " but expected " + String.valueOf(expectedType) + " from: " + String.valueOf(jsonElement));
        }
        return builderExpression;
    }
    
    @Nonnull
    public static BuilderExpression fromJSON(@Nonnull final JsonElement jsonElement, @Nonnull final BuilderParameters builderParameters) {
        if (jsonElement.isJsonObject()) {
            return BuilderExpressionDynamic.fromJSON(jsonElement, builderParameters);
        }
        if (jsonElement.isJsonPrimitive()) {
            final BuilderExpression jsonPrimitive = readJSONPrimitive(jsonElement);
            if (jsonPrimitive != null) {
                return jsonPrimitive;
            }
        }
        else if (jsonElement.isJsonArray()) {
            final BuilderExpression result = readStaticArray(jsonElement);
            if (result != null) {
                return result;
            }
        }
        throw new IllegalArgumentException("Illegal JSON value for expression: " + String.valueOf(jsonElement));
    }
    
    @Nullable
    private static BuilderExpression readJSONPrimitive(@Nonnull final JsonElement jsonElement) {
        final JsonPrimitive jsonPrimitive = jsonElement.getAsJsonPrimitive();
        if (jsonPrimitive.isString()) {
            return new BuilderExpressionStaticString(jsonPrimitive.getAsString());
        }
        if (jsonPrimitive.isBoolean()) {
            return new BuilderExpressionStaticBoolean(jsonPrimitive.getAsBoolean());
        }
        if (jsonPrimitive.isNumber()) {
            return new BuilderExpressionStaticNumber(jsonPrimitive.getAsDouble());
        }
        return null;
    }
    
    @Nullable
    private static BuilderExpression readStaticArray(@Nonnull final JsonElement jsonElement) {
        final JsonArray jsonArray = jsonElement.getAsJsonArray();
        if (jsonArray.isEmpty()) {
            return BuilderExpressionStaticEmptyArray.INSTANCE;
        }
        final JsonElement firstElement = jsonArray.get(0);
        BuilderExpression result = null;
        if (firstElement.isJsonPrimitive()) {
            final JsonPrimitive jsonPrimitive = firstElement.getAsJsonPrimitive();
            if (jsonPrimitive.isString()) {
                result = BuilderExpressionStaticStringArray.fromJSON(jsonArray);
            }
            else if (jsonPrimitive.isBoolean()) {
                result = BuilderExpressionStaticBooleanArray.fromJSON(jsonArray);
            }
            else if (jsonPrimitive.isNumber()) {
                result = BuilderExpressionStaticNumberArray.fromJSON(jsonArray);
            }
        }
        return result;
    }
    
    public void compile(final BuilderParameters builderParameters) {
    }
    
    @Nonnull
    public static Schema toSchema(@Nonnull final SchemaContext context) {
        return context.refDefinition(SchemaGenerator.INSTANCE);
    }
    
    private static class SchemaGenerator implements SchemaConvertable<Void>, NamedSchema
    {
        @Nonnull
        public static SchemaGenerator INSTANCE;
        
        @Nonnull
        @Override
        public String getSchemaName() {
            return "NPC:Type:BuilderExpression";
        }
        
        @Nonnull
        @Override
        public Schema toSchema(@Nonnull final SchemaContext context) {
            final Schema s = new Schema();
            s.setTitle("Expression");
            s.setAnyOf(new ArraySchema(), new NumberSchema(), new StringSchema(), new BooleanSchema(), BuilderExpressionDynamic.toSchema());
            return s;
        }
        
        static {
            SchemaGenerator.INSTANCE = new SchemaGenerator();
        }
    }
}
