package org.shininet.bukkit.itemrenamer.serialization; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map.Entry; import org.bukkit.configuration.ConfigurationSection; import org.shininet.bukkit.itemrenamer.configuration.DamageLookup; import org.shininet.bukkit.itemrenamer.configuration.RenameRule; import org.shininet.bukkit.itemrenamer.utils.ConfigurationUtils; import com.google.common.collect.ComparisonChain; import com.google.common.collect.Lists; import com.google.common.collect.Range; import com.google.common.collect.Ranges; /** * Serialize and deserialize a damage lookup from a configuration file. * * @author Kristian */ public class DamageSerializer { private static final String DAMAGE_ALL = "all"; private static final String DAMAGE_OTHER = "other"; private static final String RANGE_DELIMITER = "-"; private ConfigurationSection section; private RuleSerializer ruleSerializer; /** * Initialize a new damage lookup from a configuration section. * @param section - the configuration section. */ public DamageSerializer(ConfigurationSection section) { setSection(section); } public ConfigurationSection getSection() { return section; } private void setSection(ConfigurationSection section) { this.section = section; this.ruleSerializer = new RuleSerializer(section); } /** * Deserialize the content of the configuration section to the given damage lookup. * @param destination - the input or destination damage lookup. */ public void readLookup(DamageLookup destination) { int oldModCount = destination.getModificationCount(); destination.setAllRule(ruleSerializer.readRule(DAMAGE_ALL)); destination.setOtherRule(ruleSerializer.readRule(DAMAGE_OTHER)); for (String key : section.getKeys(false)) { if (isNotSpecialKey(key)) { // Parse and save Range<Integer> range = parseRange(key); destination.setRule(range.lowerEndpoint(), range.upperEndpoint(), ruleSerializer.readRule(key)); } } destination.setModificationCount(oldModCount); } /** * Serialize (write out) the content of the given damage lookup. * @param source - the damage lookup to write. */ public void writeLookup(DamageLookup source) { setSection(ConfigurationUtils.resetSection(section)); ruleSerializer.writeRule(DAMAGE_ALL, source.getAllRule()); ruleSerializer.writeRule(DAMAGE_OTHER, source.getOtherRule()); // Next, sort the ranges List<Entry<Range<Integer>, RenameRule>> entries = Lists.newArrayList(source.toLookup().entrySet()); Collections.sort(entries, new Comparator<Entry<Range<Integer>, RenameRule>>() { @Override public int compare(Entry<Range<Integer>, RenameRule> a, Entry<Range<Integer>, RenameRule> b) { Range<Integer> keyA = a.getKey(); Range<Integer> keyB = b.getKey(); return ComparisonChain.start(). compare(keyA.lowerEndpoint(), keyB.lowerEndpoint()). compare(keyA.upperEndpoint(), keyB.upperEndpoint()). result(); } }); // Save all the rules for (Entry<Range<Integer>, RenameRule> rules : entries) { Range<Integer> range = rules.getKey(); if (range.lowerEndpoint().equals(range.upperEndpoint())) { ruleSerializer.writeRule(range.lowerEndpoint().toString(), rules.getValue()); } else { ruleSerializer.writeRule(range.lowerEndpoint() + "-" + range.upperEndpoint(), rules.getValue()); } } } private boolean isNotSpecialKey(String key) { return !DAMAGE_ALL.equalsIgnoreCase(key) && !DAMAGE_OTHER.equalsIgnoreCase(key); } /** * Parse a single number or a range (num-num). * @param text - the range to parse. * @return The range. * @throws IllegalArgumentException If this is not a valid range. */ private static Range<Integer> parseRange(String text) { String[] values = text.split(RANGE_DELIMITER, 2); try { // Parse the range if (values.length == 1) { return Ranges.singleton(Integer.parseInt(values[0].trim())); } else if (values.length == 2) { return Ranges.closed( Integer.parseInt(values[0].trim()), Integer.parseInt(values[1].trim()) ); } else { throw new IllegalArgumentException("Cannot parse range: " + text); } } catch (NumberFormatException e) { throw new IllegalArgumentException("Unable to parse range " + text); } } }