package tc.oc.pgm.classes; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Logger; import javax.annotation.Nullable; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.bukkit.material.MaterialData; import org.jdom2.Document; import org.jdom2.Element; import tc.oc.commons.bukkit.util.BukkitUtils; import tc.oc.pgm.kits.Kit; import tc.oc.pgm.kits.KitParser; import tc.oc.pgm.map.MapModule; import tc.oc.pgm.map.MapModuleContext; import tc.oc.pgm.match.Match; import tc.oc.pgm.match.MatchModuleFactory; import tc.oc.pgm.module.ModuleDescription; import tc.oc.pgm.utils.XMLUtils; import tc.oc.pgm.xml.InvalidXMLException; import tc.oc.pgm.xml.Node; import static com.google.common.base.Preconditions.checkNotNull; @ModuleDescription(name = "Classes") public class ClassModule implements MapModule, MatchModuleFactory<ClassMatchModule> { final String family; final Map<String, PlayerClass> classes; final PlayerClass defaultClass; public ClassModule(String family, Map<String, PlayerClass> classes, PlayerClass defaultClass) { this.family = checkNotNull(family, "family"); this.classes = ImmutableMap.copyOf(checkNotNull(classes, "classes")); this.defaultClass = checkNotNull(defaultClass, "default class"); } @Override public ClassMatchModule createMatchModule(Match match) { return new ClassMatchModule(match, this.family, this.classes, this.defaultClass); } public String getFamily() { return this.family; } public @Nullable PlayerClass getPlayerClass(String name) { return this.classes.get(name); } public Set<PlayerClass> getPlayerClasses() { return ImmutableSet.copyOf(this.classes.values()); } // --------------------- // ---- XML Parsing ---- // --------------------- public static ClassModule parse(MapModuleContext context, Logger logger, Document doc) throws InvalidXMLException { List<Element> classElements = XMLUtils.flattenElements(doc.getRootElement(), "classes", "class"); if(classElements.isEmpty()) return null; // first look for the family Map<String, Integer> familyFrequency = Maps.newHashMap(); String family = null; int familyOccurances = 0; for(Element classEl : classElements) { String classFamily = classEl.getAttributeValue("family"); if(classFamily != null) { Integer num = familyFrequency.get(classFamily); familyFrequency.put(classFamily, (num != null ? num.intValue() : 0) + 1); } } for(Map.Entry<String, Integer> entry : familyFrequency.entrySet()) { if(entry.getValue() > familyOccurances) { family = entry.getKey(); } else if (entry.getValue() == familyOccurances) { family = null; } } if(family == null) throw new InvalidXMLException("Unable to determine family for classes", doc); Set<String> usedNames = Sets.newHashSet(); ImmutableMap.Builder<String, PlayerClass> builder = ImmutableMap.builder(); PlayerClass defaultClass = null; for(Element classEl : classElements) { PlayerClass cls = parseClass(classEl, context.needModule(KitParser.class), family); if(usedNames.contains(cls.getName().toLowerCase())) { throw new InvalidXMLException("Class already registered to \" + cls.getName() + \"; skipping second instance", classEl); } String classFamily = classEl.getAttributeValue("family"); if(family == null) { family = classFamily; } else { if(!family.equals(classFamily)) { throw new InvalidXMLException("Family was determined to be '" + family + "' but class specified '" + classFamily, classEl); } } if(XMLUtils.parseBoolean(classEl.getAttribute("default"), false)) { if(defaultClass != null) { throw new InvalidXMLException("Default class already registered to " + defaultClass.getName(), classEl); } else { defaultClass = cls; } } builder.put(cls.getName(), cls); } Map<String, PlayerClass> classes = builder.build(); if(!classes.isEmpty()) { if(defaultClass != null) { return new ClassModule(family, classes, defaultClass); } else { throw new InvalidXMLException("No default class set", doc); } } return null; } private static PlayerClass parseClass(Element classEl, KitParser kitParser, String family) throws InvalidXMLException { String name = classEl.getAttributeValue("name"); if(name == null) { throw new InvalidXMLException("class must have a name", classEl); } String description = classEl.getAttributeValue("description"); if(description != null) { description = BukkitUtils.colorize(description); } String longdescription = classEl.getAttributeValue("longdescription"); if(longdescription != null) { longdescription = BukkitUtils.colorize(longdescription); } boolean sticky = XMLUtils.parseBoolean(classEl.getAttribute("sticky"), false); ImmutableSet.Builder<Kit> kits = ImmutableSet.builder(); for(Element kitEl : classEl.getChildren("kit")) { Kit kit = kitParser.parseElement(kitEl); kits.add(kit); } MaterialData icon = XMLUtils.parseMaterialData(Node.fromAttr(classEl, "icon")); boolean restrict = XMLUtils.parseBoolean(classEl.getAttribute("restrict"), false); return new PlayerClass(name, family, description, longdescription, sticky, kits.build(), icon, restrict); } }