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

package com.hypixel.hytale.server.core.modules.entitystats;

import java.util.Arrays;
import java.util.Iterator;
import com.hypixel.hytale.server.core.modules.entitystats.modifier.StaticModifier;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import com.hypixel.hytale.math.util.MathUtil;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.modules.entitystats.asset.EntityStatType;
import com.hypixel.hytale.server.core.modules.entitystats.modifier.Modifier;
import java.util.Map;
import javax.annotation.Nullable;
import com.hypixel.hytale.codec.builder.BuilderCodec;

public class EntityStatValue
{
    public static final EntityStatValue[] EMPTY_ARRAY;
    public static final BuilderCodec<EntityStatValue> CODEC;
    private String id;
    private int index;
    private float value;
    private float min;
    private float max;
    private boolean ignoreInvulnerability;
    @Nullable
    private RegeneratingValue[] regeneratingValues;
    @Nullable
    private Map<String, Modifier> modifiers;
    
    protected EntityStatValue() {
        this.index = Integer.MIN_VALUE;
    }
    
    public EntityStatValue(final int index, @Nonnull final EntityStatType asset) {
        this.index = Integer.MIN_VALUE;
        this.id = asset.getId();
        this.index = index;
        this.value = asset.getInitialValue();
        this.synchronizeAsset(index, asset);
    }
    
    public String getId() {
        return this.id;
    }
    
    public int getIndex() {
        return this.index;
    }
    
    public float get() {
        return this.value;
    }
    
    public float asPercentage() {
        if (this.min == this.max) {
            return 0.0f;
        }
        return (this.value - this.min) / (this.max - this.min);
    }
    
    public float getMin() {
        return this.min;
    }
    
    public float getMax() {
        return this.max;
    }
    
    protected float set(final float newValue) {
        return this.value = MathUtil.clamp(newValue, this.min, this.max);
    }
    
    @Nullable
    public RegeneratingValue[] getRegeneratingValues() {
        return this.regeneratingValues;
    }
    
    @Nullable
    public Modifier getModifier(final String key) {
        if (this.modifiers == null) {
            return null;
        }
        return this.modifiers.get(key);
    }
    
    public boolean getIgnoreInvulnerability() {
        return this.ignoreInvulnerability;
    }
    
    @Nullable
    public Map<String, Modifier> getModifiers() {
        return this.modifiers;
    }
    
    @Nullable
    protected Modifier putModifier(final String key, final Modifier modifier) {
        if (this.modifiers == null) {
            this.modifiers = new Object2ObjectOpenHashMap<String, Modifier>();
        }
        final Modifier oldModifier = this.modifiers.put(key, modifier);
        this.computeModifiers(EntityStatType.getAssetMap().getAsset(this.index));
        return oldModifier;
    }
    
    @Nullable
    protected Modifier removeModifier(final String key) {
        if (this.modifiers == null) {
            return null;
        }
        final Modifier modifier = this.modifiers.remove(key);
        if (modifier != null) {
            this.computeModifiers(EntityStatType.getAssetMap().getAsset(this.index));
        }
        return modifier;
    }
    
    public boolean synchronizeAsset(final int index, @Nonnull final EntityStatType asset) {
        this.id = asset.getId();
        this.index = index;
        this.initializeRegenerating(asset);
        final boolean minMaxChanged = this.min != asset.getMin() || this.max != asset.getMax();
        this.ignoreInvulnerability = asset.getIgnoreInvulnerability();
        final float oldValue = this.value;
        this.computeModifiers(asset);
        return minMaxChanged || this.value != oldValue;
    }
    
    private void initializeRegenerating(@Nonnull final EntityStatType entityStatType) {
        final EntityStatType.Regenerating[] regeneratingTypes = entityStatType.getRegenerating();
        if (regeneratingTypes == null) {
            return;
        }
        this.regeneratingValues = new RegeneratingValue[regeneratingTypes.length];
        for (int i = 0; i < regeneratingTypes.length; ++i) {
            this.regeneratingValues[i] = new RegeneratingValue(regeneratingTypes[i]);
        }
    }
    
    protected void computeModifiers(@Nonnull final EntityStatType asset) {
        this.min = asset.getMin();
        this.max = asset.getMax();
        if (this.modifiers != null) {
            for (final Modifier.ModifierTarget target : Modifier.ModifierTarget.VALUES) {
                boolean hasAdditive = false;
                float additive = 0.0f;
                boolean hasMultiplicative = false;
                float multiplicative = 0.0f;
                for (final Modifier modifier : this.modifiers.values()) {
                    if (modifier instanceof final StaticModifier staticModifier) {
                        if (staticModifier.getTarget() != target) {
                            continue;
                        }
                        switch (staticModifier.getCalculationType()) {
                            case ADDITIVE: {
                                hasAdditive = true;
                                additive += staticModifier.getAmount();
                                continue;
                            }
                            case MULTIPLICATIVE: {
                                hasMultiplicative = true;
                                multiplicative += staticModifier.getAmount();
                                continue;
                            }
                        }
                    }
                }
                switch (target) {
                    case MIN: {
                        if (hasAdditive) {
                            this.min = StaticModifier.CalculationType.ADDITIVE.compute(this.min, additive);
                        }
                        if (hasMultiplicative) {
                            this.min = StaticModifier.CalculationType.MULTIPLICATIVE.compute(this.min, multiplicative);
                            break;
                        }
                        break;
                    }
                    case MAX: {
                        if (hasAdditive) {
                            this.max = StaticModifier.CalculationType.ADDITIVE.compute(this.max, additive);
                        }
                        if (hasMultiplicative) {
                            this.max = StaticModifier.CalculationType.MULTIPLICATIVE.compute(this.max, multiplicative);
                            break;
                        }
                        break;
                    }
                }
            }
            for (final Modifier modifier2 : this.modifiers.values()) {
                if (!(modifier2 instanceof StaticModifier)) {
                    this.applyModifier(modifier2);
                }
            }
        }
        this.value = MathUtil.clamp(this.value, this.min, this.max);
    }
    
    private void applyModifier(@Nonnull final Modifier modifier) {
        switch (modifier.getTarget()) {
            case MIN: {
                this.min = modifier.apply(this.min);
                break;
            }
            case MAX: {
                this.max = modifier.apply(this.max);
                break;
            }
        }
    }
    
    @Nonnull
    @Override
    public String toString() {
        return "EntityStatValue{id='" + this.id + "', index=" + this.index + ", value=" + this.value + ", min=" + this.min + ", max=" + this.max + ", regeneratingValues=" + Arrays.toString(this.regeneratingValues) + ", modifiers=" + String.valueOf(this.modifiers);
    }
    
    static {
        // 
        // This method could not be decompiled.
        // 
        // Original Bytecode:
        // 
        //     1: anewarray       Lcom/hypixel/hytale/server/core/modules/entitystats/EntityStatValue;
        //     4: putstatic       com/hypixel/hytale/server/core/modules/entitystats/EntityStatValue.EMPTY_ARRAY:[Lcom/hypixel/hytale/server/core/modules/entitystats/EntityStatValue;
        //     7: ldc             Lcom/hypixel/hytale/server/core/modules/entitystats/EntityStatValue;.class
        //     9: invokedynamic   BootstrapMethod #1, get:()Ljava/util/function/Supplier;
        //    14: invokestatic    com/hypixel/hytale/codec/builder/BuilderCodec.builder:(Ljava/lang/Class;Ljava/util/function/Supplier;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //    17: new             Lcom/hypixel/hytale/codec/KeyedCodec;
        //    20: dup            
        //    21: ldc             "Id"
        //    23: getstatic       com/hypixel/hytale/codec/Codec.STRING:Lcom/hypixel/hytale/codec/codecs/simple/StringCodec;
        //    26: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //    29: invokedynamic   BootstrapMethod #2, accept:()Ljava/util/function/BiConsumer;
        //    34: invokedynamic   BootstrapMethod #3, apply:()Ljava/util/function/Function;
        //    39: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //    42: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //    45: new             Lcom/hypixel/hytale/codec/KeyedCodec;
        //    48: dup            
        //    49: ldc_w           "Value"
        //    52: getstatic       com/hypixel/hytale/codec/Codec.FLOAT:Lcom/hypixel/hytale/codec/codecs/simple/FloatCodec;
        //    55: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //    58: invokedynamic   BootstrapMethod #4, accept:()Ljava/util/function/BiConsumer;
        //    63: invokedynamic   BootstrapMethod #5, apply:()Ljava/util/function/Function;
        //    68: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //    71: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //    74: new             Lcom/hypixel/hytale/codec/KeyedCodec;
        //    77: dup            
        //    78: ldc_w           "Modifiers"
        //    81: new             Lcom/hypixel/hytale/codec/codecs/map/MapCodec;
        //    84: dup            
        //    85: getstatic       com/hypixel/hytale/server/core/modules/entitystats/modifier/Modifier.CODEC:Lcom/hypixel/hytale/codec/lookup/CodecMapCodec;
        //    88: invokedynamic   BootstrapMethod #6, get:()Ljava/util/function/Supplier;
        //    93: iconst_0       
        //    94: invokespecial   com/hypixel/hytale/codec/codecs/map/MapCodec.<init>:(Lcom/hypixel/hytale/codec/Codec;Ljava/util/function/Supplier;Z)V
        //    97: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //   100: invokedynamic   BootstrapMethod #7, accept:()Ljava/util/function/BiConsumer;
        //   105: invokedynamic   BootstrapMethod #8, apply:()Ljava/util/function/Function;
        //   110: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //   113: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //   116: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.build:()Lcom/hypixel/hytale/codec/builder/BuilderCodec;
        //   119: putstatic       com/hypixel/hytale/server/core/modules/entitystats/EntityStatValue.CODEC:Lcom/hypixel/hytale/codec/builder/BuilderCodec;
        //   122: return         
        // 
        // The error that occurred was:
        // 
        // java.lang.UnsupportedOperationException: The requested operation is not supported.
        //     at com.strobel.util.ContractUtils.unsupported(ContractUtils.java:27)
        //     at com.strobel.assembler.metadata.TypeReference.getRawType(TypeReference.java:284)
        //     at com.strobel.assembler.metadata.TypeReference.getRawType(TypeReference.java:279)
        //     at com.strobel.assembler.metadata.TypeReference.makeGenericType(TypeReference.java:154)
        //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitParameterizedType(TypeSubstitutionVisitor.java:225)
        //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitParameterizedType(TypeSubstitutionVisitor.java:25)
        //     at com.strobel.assembler.metadata.ParameterizedType.accept(ParameterizedType.java:103)
        //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visit(TypeSubstitutionVisitor.java:40)
        //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitMethod(TypeSubstitutionVisitor.java:314)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2611)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:790)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2689)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:790)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2689)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1083)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.runInference(TypeAnalysis.java:684)
        //     at com.strobel.decompiler.ast.TypeAnalysis.runInference(TypeAnalysis.java:667)
        //     at com.strobel.decompiler.ast.TypeAnalysis.runInference(TypeAnalysis.java:373)
        //     at com.strobel.decompiler.ast.TypeAnalysis.run(TypeAnalysis.java:95)
        //     at com.strobel.decompiler.ast.AstOptimizer.optimize(AstOptimizer.java:344)
        //     at com.strobel.decompiler.ast.AstOptimizer.optimize(AstOptimizer.java:42)
        //     at com.strobel.decompiler.languages.java.ast.AstMethodBodyBuilder.createMethodBody(AstMethodBodyBuilder.java:206)
        //     at com.strobel.decompiler.languages.java.ast.AstMethodBodyBuilder.createMethodBody(AstMethodBodyBuilder.java:93)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createMethodBody(AstBuilder.java:868)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createMethod(AstBuilder.java:761)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addTypeMembers(AstBuilder.java:638)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeCore(AstBuilder.java:605)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeNoCache(AstBuilder.java:195)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createType(AstBuilder.java:162)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addType(AstBuilder.java:137)
        //     at com.strobel.decompiler.languages.java.JavaLanguage.buildAst(JavaLanguage.java:71)
        //     at com.strobel.decompiler.languages.java.JavaLanguage.decompileType(JavaLanguage.java:59)
        //     at com.strobel.decompiler.DecompilerDriver.decompileType(DecompilerDriver.java:333)
        //     at com.strobel.decompiler.DecompilerDriver.decompileJar(DecompilerDriver.java:254)
        //     at com.strobel.decompiler.DecompilerDriver.main(DecompilerDriver.java:129)
        // 
        throw new IllegalStateException("An error occurred while decompiling this method.");
    }
}
