package jk_5.nailed.server.mappack.metadata.xml;
import jk_5.nailed.api.mappack.MappackConfigurationException;
import jk_5.nailed.api.mappack.metadata.*;
import jk_5.nailed.api.mappack.metadata.impl.DefaultMappackAuthor;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.Namespace;
import org.jdom2.input.SAXBuilder;
import javax.annotation.Nonnull;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class XmlMappackMetadata implements MappackMetadata {
private static final SAXBuilder builder = new SAXBuilder();
private final String name;
private final String version;
private final MappackAuthor[] authors;
private final XmlTutorial tutorial;
private final MappackTeam[] teams;
private final MappackWorld[] worlds;
private final String gameType;
private final StatConfig[] stats;
public static XmlMappackMetadata fromFile(File file) throws MappackConfigurationException {
try {
Document doc = builder.build(file);
Element e = doc.getRootElement();
if(e.getName().equals("game")){
return new XmlMappackMetadata(e, e.getNamespace());
}else{
throw new MappackConfigurationException("game.xml does not contain the root game element");
}
}catch(JDOMException e){
throw new MappackConfigurationException("game.xml syntax error", e);
}catch(IOException e){
throw new MappackConfigurationException("Was not able to read game.xml", e);
}
}
public static XmlMappackMetadata fromResource(String path) throws MappackConfigurationException {
try {
Document doc = builder.build(XmlMappackMetadata.class.getResourceAsStream("/" + path));
Element e = doc.getRootElement();
if(e.getName().equals("game")){
return new XmlMappackMetadata(e, e.getNamespace());
}else{
throw new MappackConfigurationException("game.xml does not contain the root game element");
}
}catch(JDOMException e){
throw new MappackConfigurationException("game.xml syntax error", e);
}catch(IOException e){
throw new MappackConfigurationException("Was not able to read game.xml", e);
}
}
public XmlMappackMetadata(Element element, Namespace ns) throws MappackConfigurationException {
if(element.getChild("name", ns) == null){
throw new MappackConfigurationException("Missing required <name> element");
}
if(element.getChild("version", ns) == null){
throw new MappackConfigurationException("Missing required <version> element");
}
if(element.getChild("authors", ns) == null){
throw new MappackConfigurationException("Missing required <authors> element");
}
if(element.getChild("worlds", ns) == null){
throw new MappackConfigurationException("Missing required <worlds> element");
}
if(element.getChild("worlds", ns).getChildren().size() == 0){
throw new MappackConfigurationException("<worlds> element should have at least 1 <world>");
}
this.name = element.getChild("name", ns).getText();
this.version = element.getChild("version", ns).getText();
List<MappackAuthor> authors = new ArrayList<MappackAuthor>();
for (Element e : element.getChild("authors", ns).getChildren()) {
if(!e.getName().equals("author")){
throw new MappackConfigurationException("Invalid element in authors list: " + e.getName());
}
if(e.getChild("name", ns) == null){
throw new MappackConfigurationException("Missing required element <name> in <author> element");
}
if(e.getChild("role", ns) == null){
throw new MappackConfigurationException("Missing required element <role> in <author> element");
}
authors.add(new DefaultMappackAuthor(e.getChild("name", ns).getText(), e.getChild("role", ns).getText()));
}
this.authors = authors.toArray(new MappackAuthor[authors.size()]);
if(element.getChild("tutorial", ns) == null){
this.tutorial = null;
}else{
this.tutorial = new XmlTutorial(element.getChild("tutorial", ns));
}
if(element.getChild("teams", ns) == null){
this.teams = new MappackTeam[0];
}else{
List<MappackTeam> teams = new ArrayList<MappackTeam>();
for (Element e : element.getChild("teams", ns).getChildren()) {
teams.add(new XmlMappackTeam(e));
}
this.teams = teams.toArray(new MappackTeam[teams.size()]);
}
List<MappackWorld> worlds = new ArrayList<MappackWorld>();
for (Element e : element.getChild("worlds", ns).getChildren()) {
if(e.getChild("name", ns) == null){
throw new MappackConfigurationException("Missing required element <name> in <world> element");
}
worlds.add(new XmlMappackWorld(e.getChild("name", ns).getText(), e));
}
this.worlds = worlds.toArray(new MappackWorld[worlds.size()]);
if(element.getChild("gametype", ns) == null){
this.gameType = null;
}else{
this.gameType = XmlUtils.getAttributeValue(element.getChild("gametype"), "name");
}
if(element.getChild("stats", ns) == null){
this.stats = new StatConfig[0];
}else{
List<StatConfig> stats = new ArrayList<StatConfig>();
for (Element e : element.getChild("stats", ns).getChildren()) {
if(!e.getName().equals("stat")){
throw new MappackConfigurationException("Invalid element in stats list: " + e.getName());
}
String name = XmlUtils.getAttributeValue(e, "name");
stats.add(new XmlStatConfig(name, e));
}
this.stats = stats.toArray(new StatConfig[stats.size()]);
}
}
@Nonnull
@Override
public String name() {
return this.name;
}
@Nonnull
@Override
public String version() {
return this.version;
}
@Nonnull
@Override
public MappackAuthor[] authors() {
return this.authors;
}
@Nonnull
@Override
public MappackWorld[] worlds() {
return this.worlds;
}
@Nonnull
@Override
public MappackTeam[] teams() {
return this.teams;
}
@Nonnull
@Override
public Tutorial tutorial() {
return this.tutorial;
}
@Nonnull
@Override
public String gameType() {
return this.gameType;
}
@Nonnull
@Override
public StatConfig[] stats() {
return this.stats;
}
}