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);
}
}