package common.attributes;

import java.util.Collection;
import java.util.Map;
import java.util.Set;

import common.collect.Lists;
import common.collect.Maps;
import common.collect.Sets;

public class AttributeInstance
{
    private final AttributeMap attributeMap;
    private final Attribute genericAttribute;
    private final Set<AttributeModifier> additions = Sets.<AttributeModifier>newHashSet();
    private final Set<AttributeModifier> multipliers = Sets.<AttributeModifier>newHashSet();
    private final Map<String, Set<AttributeModifier>> mapByName = Maps.<String, Set<AttributeModifier>>newHashMap();
    private final Map<Long, AttributeModifier> mapByID = Maps.<Long, AttributeModifier>newHashMap();
    private double baseValue;
    private boolean needsUpdate = true;
    private double cachedValue;

    public AttributeInstance(AttributeMap attributeMapIn, Attribute genericAttributeIn)
    {
        this.attributeMap = attributeMapIn;
        this.genericAttribute = genericAttributeIn;
        this.baseValue = genericAttributeIn.getDefaultValue();
    }

    public Attribute getAttribute()
    {
        return this.genericAttribute;
    }

    public double getBaseValue()
    {
        return this.baseValue;
    }

    public void setBaseValue(double baseValue)
    {
        if (baseValue != this.getBaseValue())
        {
            this.baseValue = baseValue;
            this.flagForUpdate();
        }
    }

//    public Collection<AttributeModifier> getModifiersByOperation(AttributeOp operation)
//    {
//        return (Collection)this.mapByOperation.get(operation);
//    }

    public Collection<AttributeModifier> getModifiers()
    {
        Set<AttributeModifier> set = Sets.<AttributeModifier>newHashSet();

//        for (AttributeOp op : AttributeOp.values())
//        {
//            set.addAll(this.getModifiersByOperation(op));
//        }
        set.addAll(this.additions);
        set.addAll(this.multipliers);

        return set;
    }

    public AttributeModifier getModifier(long id)
    {
        return (AttributeModifier)this.mapByID.get(id);
    }

    public boolean hasModifier(AttributeModifier modifier)
    {
        return this.mapByID.get(modifier.getID()) != null;
    }

    public void applyModifier(AttributeModifier modifier)
    {
        if (this.getModifier(modifier.getID()) != null)
        {
            throw new IllegalArgumentException("Modifier is already applied on this attribute!");
        }
        else
        {
            Set<AttributeModifier> set = (Set)this.mapByName.get(modifier.getName());

            if (set == null)
            {
                set = Sets.<AttributeModifier>newHashSet();
                this.mapByName.put(modifier.getName(), set);
            }

            (modifier.isMultiplied() ? this.multipliers : this.additions).add(modifier);
            set.add(modifier);
            this.mapByID.put(modifier.getID(), modifier);
            this.flagForUpdate();
        }
    }

    protected void flagForUpdate()
    {
        this.needsUpdate = true;
        this.attributeMap.flagDirty(this);
    }

    public void removeModifier(AttributeModifier modifier)
    {
//        for (AttributeOp op : AttributeOp.values())
//        {
//            Set<AttributeModifier> set = (Set)this.mapByOperation.get(op);
//            set.remove(modifier);
//        }
        this.additions.remove(modifier);
        this.multipliers.remove(modifier);

        Set<AttributeModifier> set1 = (Set)this.mapByName.get(modifier.getName());

        if (set1 != null)
        {
            set1.remove(modifier);

            if (set1.isEmpty())
            {
                this.mapByName.remove(modifier.getName());
            }
        }

        this.mapByID.remove(modifier.getID());
        this.flagForUpdate();
    }

    public void removeAllModifiers()
    {
        Collection<AttributeModifier> collection = this.getModifiers();

        if (collection != null)
        {
            for (AttributeModifier attributemodifier : Lists.newArrayList(collection))
            {
                this.removeModifier(attributemodifier);
            }
        }
    }

    public double getAttributeValue()
    {
        if (this.needsUpdate)
        {
            this.cachedValue = this.computeValue();
            this.needsUpdate = false;
        }

        return this.cachedValue;
    }

    private double computeValue()
    {
        double base = this.getBaseValue();

        for (AttributeModifier attributemodifier : this.additions)
        {
            base += attributemodifier.getAmount();
        }

        for (AttributeModifier attributemodifier2 : this.multipliers)
        {
        	base *= 1.0D + attributemodifier2.getAmount();
        }

        return this.genericAttribute.clampValue(base);
    }

//    private Collection<AttributeModifier> getModifierList(AttributeOp operation)
//    {
//        // Set<AttributeModifier> set = 
//        return Sets.newHashSet(this.getModifiersByOperation(operation));
//
////        for (BaseAttribute iattribute = this.genericAttribute.func_180372_d(); iattribute != null; iattribute = iattribute.func_180372_d())
////        {
////            ModifiableAttributeInstance iattributeinstance = this.attributeMap.getAttributeInstance(iattribute);
////
////            if (iattributeinstance != null)
////            {
////                set.addAll(iattributeinstance.getModifiersByOperation(operation));
////            }
////        }
//
//        // return set;
//    }
}
