package org.shininet.bukkit.itemrenamer.configuration; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.shininet.bukkit.itemrenamer.configuration.RenameProcessorFactory.RenameFunction; import com.comphenix.protocol.concurrency.AbstractIntervalTree; import com.google.common.base.Function; import com.google.common.collect.Maps; import com.google.common.collect.Range; /** * Represents a damage lookup interval tree. * @author Kristian */ class MemoryDamageLookup implements DamageLookup { /** * Represents an integer interval tree. * * @author Kristian */ private class IntegerInterval extends AbstractIntervalTree<Integer, RenameRule> { @Override protected Integer decrementKey(Integer key) { return key - 1; } @Override protected Integer incrementKey(Integer key) { return key + 1; } } // Used to store our data private final AbstractIntervalTree<Integer, RenameRule> tree = new IntegerInterval(); private RenameRule all; private RenameRule other; // Whether or not the lookup has changed private int modCount; /** * Construct a new memory damage lookup. */ public MemoryDamageLookup() { // Use default values } /** * Clone a memory damage lookup from a given lookup. * @param other - the other lookup. */ public MemoryDamageLookup(DamageLookup other) { setAllRule(other.getAllRule()); setOtherRule(other.getOtherRule()); // Use the lookup method for (Entry<Range<Integer>, RenameRule> entry : other.toLookup().entrySet()) { Range<Integer> range = entry.getKey(); RenameRule rule = entry.getValue(); setRule(range.lowerEndpoint(), range.upperEndpoint(), rule); } modCount = 0; } @Override public RenameRule getAllRule() { return all; } @Override public void setAllRule(RenameRule rule) { if (!RenameRule.isIdentity(rule)) rule = rule.withSkipRule(true); this.modCount++; this.all = rule; } @Override public RenameRule getOtherRule() { return other; } @Override public void setOtherRule(RenameRule rule) { if (!RenameRule.isIdentity(rule)) rule = rule.withSkipRule(true); this.modCount++; this.other = rule; } @Override public void setTransform(DamageValues value, RenameFunction function) { if (value == DamageValues.ALL) { setAllRule(function.apply(getAllRule() != null ? getAllRule() : RenameRule.IDENTITY)); } else if (value == DamageValues.OTHER) { setOtherRule(function.apply(getOtherRule() != null ? getOtherRule() : RenameRule.IDENTITY)); } else { setTransformed(value.getRange().lowerEndpoint(), value.getRange().upperEndpoint(), function); } } /** * Set all the rules in a given range by applying a transform to any existing rules. * <p> * Ranges that are not already defined will be set with the default rule after a transform. * @param minimum - the minimum value in the range. * @param maximum - the maximum value in the range * @param ruleTransform - the transform to apply in this range, including the default value. */ public void setTransformed(int minimum, int maximum, Function<RenameRule, RenameRule> ruleTransform) { Set<IntegerInterval.Entry> removed = tree.remove(minimum, maximum, true); RenameRule defaultRule = ruleTransform.apply(RenameRule.IDENTITY); // It's been changed modCount++; // Set everything to default setRule(minimum, maximum, defaultRule); // Then set the applied version of every previous rule in this range for (IntegerInterval.Entry rule : removed) { setRule(rule.getKey().lowerEndpoint(), rule.getKey().upperEndpoint(), ruleTransform.apply(rule.getValue())); } } @Override public RenameRule getRule(int damage) { RenameRule value = getDefinedRule(damage); RenameRule all = getAllRule(); // All is our fallback if (value == null) { return RenameRule.merge(getOtherRule(), all); } else { return RenameRule.merge(value, all); } } @Override public RenameRule getDefinedRule(int damage) { return tree.get(damage); } @Override public Map<Range<Integer>, RenameRule> toLookup() { Map<Range<Integer>, RenameRule> lookup = Maps.newLinkedHashMap(); // Enumerate and create the resulting set for (IntegerInterval.Entry entry : tree.entrySet()) { lookup.put(entry.getKey(), entry.getValue()); } return lookup; } @Override public void setRule(int damage, RenameRule rule) { if (damage < 0) throw new IllegalArgumentException("Damage cannot be less than zero."); if (!RenameRule.isIdentity(rule)) rule = rule.withSkipRule(true); modCount++; tree.put(damage, damage, rule); } @Override public void setRule(int lowerDamage, int upperDamage, RenameRule rule) { if (lowerDamage < 0 || upperDamage < 0) throw new IllegalArgumentException("Damage cannot be less than zero."); if (lowerDamage > upperDamage) throw new IllegalArgumentException("Lower damage must be less than upper damage."); if (!RenameRule.isIdentity(rule)) rule = rule.withSkipRule(true); modCount++; tree.put(lowerDamage, upperDamage, rule); } @Override public int getModificationCount() { return modCount; } @Override public void setModificationCount(int value) { this.modCount = value; } }