package net.minecraft.world.entity.ai.attributes;

import java.util.Iterator;
import com.google.common.collect.Lists;
import javax.annotation.Nullable;
import java.util.Collection;
import com.google.common.collect.Sets;
import com.google.common.collect.Maps;
import java.util.UUID;
import java.util.Set;
import java.util.Map;

public class ModifiableAttributeInstance implements AttributeInstance {
    private final BaseAttributeMap attributeMap;
    private final Attribute attribute;
    private final Map<AttributeModifier.Operation, Set<AttributeModifier>> modifiers;
    private final Map<String, Set<AttributeModifier>> modifiersByName;
    private final Map<UUID, AttributeModifier> modifierById;
    private double baseValue;
    private boolean dirty;
    private double cachedValue;
    
    public ModifiableAttributeInstance(final BaseAttributeMap alu, final Attribute alq) {
        this.modifiers = Maps.newEnumMap(AttributeModifier.Operation.class);
        this.modifiersByName = Maps.newHashMap();
        this.modifierById = Maps.newHashMap();
        this.dirty = true;
        this.attributeMap = alu;
        this.attribute = alq;
        this.baseValue = alq.getDefaultValue();
        for (final AttributeModifier.Operation a7 : AttributeModifier.Operation.values()) {
            this.modifiers.put(a7, Sets.newHashSet());
        }
    }
    
    @Override
    public Attribute getAttribute() {
        return this.attribute;
    }
    
    @Override
    public double getBaseValue() {
        return this.baseValue;
    }
    
    @Override
    public void setBaseValue(final double double1) {
        if (double1 == this.getBaseValue()) {
            return;
        }
        this.baseValue = double1;
        this.setDirty();
    }
    
    @Override
    public Set<AttributeModifier> getModifiers(final AttributeModifier.Operation a) {
        return this.modifiers.get(a);
    }
    
    @Override
    public Set<AttributeModifier> getModifiers() {
        final Set<AttributeModifier> set2 = Sets.newHashSet();
        for (final AttributeModifier.Operation a6 : AttributeModifier.Operation.values()) {
            set2.addAll(this.getModifiers(a6));
        }
        return set2;
    }
    
    @Nullable
    @Override
    public AttributeModifier getModifier(final UUID uUID) {
        return this.modifierById.get(uUID);
    }
    
    @Override
    public boolean hasModifier(final AttributeModifier als) {
        return this.modifierById.get(als.getId()) != null;
    }
    
    @Override
    public void addModifier(final AttributeModifier als) {
        if (this.getModifier(als.getId()) != null) {
            throw new IllegalArgumentException("Modifier is already applied on this attribute!");
        }
        final Set<AttributeModifier> set3 = this.modifiersByName.computeIfAbsent(als.getName(), string -> Sets.newHashSet());
        this.modifiers.get(als.getOperation()).add(als);
        set3.add(als);
        this.modifierById.put(als.getId(), als);
        this.setDirty();
    }
    
    protected void setDirty() {
        this.dirty = true;
        this.attributeMap.onAttributeModified(this);
    }
    
    @Override
    public void removeModifier(final AttributeModifier als) {
        for (final AttributeModifier.Operation a6 : AttributeModifier.Operation.values()) {
            this.modifiers.get(a6).remove(als);
        }
        final Set<AttributeModifier> set3 = this.modifiersByName.get(als.getName());
        if (set3 != null) {
            set3.remove(als);
            if (set3.isEmpty()) {
                this.modifiersByName.remove(als.getName());
            }
        }
        this.modifierById.remove(als.getId());
        this.setDirty();
    }
    
    @Override
    public void removeModifier(final UUID uUID) {
        final AttributeModifier als3 = this.getModifier(uUID);
        if (als3 != null) {
            this.removeModifier(als3);
        }
    }
    
    @Override
    public void removeModifiers() {
        Collection<AttributeModifier> collection2 = this.getModifiers();
        if (collection2 == null) {
            return;
        }
        collection2 = Lists.newArrayList(collection2);
        for (final AttributeModifier als4 : collection2) {
            this.removeModifier(als4);
        }
    }
    
    @Override
    public double getValue() {
        if (this.dirty) {
            this.cachedValue = this.calculateValue();
            this.dirty = false;
        }
        return this.cachedValue;
    }
    
    private double calculateValue() {
        double double2 = this.getBaseValue();
        for (final AttributeModifier als5 : this.getAppliedModifiers(AttributeModifier.Operation.ADDITION)) {
            double2 += als5.getAmount();
        }
        double double3 = double2;
        for (final AttributeModifier als6 : this.getAppliedModifiers(AttributeModifier.Operation.MULTIPLY_BASE)) {
            double3 += double2 * als6.getAmount();
        }
        for (final AttributeModifier als6 : this.getAppliedModifiers(AttributeModifier.Operation.MULTIPLY_TOTAL)) {
            double3 *= 1.0 + als6.getAmount();
        }
        return this.attribute.sanitizeValue(double3);
    }
    
    private Collection<AttributeModifier> getAppliedModifiers(final AttributeModifier.Operation a) {
        final Set<AttributeModifier> set3 = Sets.newHashSet(this.getModifiers(a));
        for (Attribute alq4 = this.attribute.getParentAttribute(); alq4 != null; alq4 = alq4.getParentAttribute()) {
            final AttributeInstance alr5 = this.attributeMap.getInstance(alq4);
            if (alr5 != null) {
                set3.addAll(alr5.getModifiers(a));
            }
        }
        return set3;
    }
}
