package com.kartoflane.superluminal2.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.JDOMParseException;
import com.kartoflane.superluminal2.components.enums.Directions;
import com.kartoflane.superluminal2.components.enums.DroneStats;
import com.kartoflane.superluminal2.components.enums.DroneTypes;
import com.kartoflane.superluminal2.components.enums.WeaponStats;
import com.kartoflane.superluminal2.components.enums.WeaponTypes;
import com.kartoflane.superluminal2.core.Database;
import com.kartoflane.superluminal2.core.DatabaseEntry;
import com.kartoflane.superluminal2.ftl.AnimationObject;
import com.kartoflane.superluminal2.ftl.AugmentObject;
import com.kartoflane.superluminal2.ftl.BlueprintList;
import com.kartoflane.superluminal2.ftl.DroneList;
import com.kartoflane.superluminal2.ftl.DroneObject;
import com.kartoflane.superluminal2.ftl.GameObject;
import com.kartoflane.superluminal2.ftl.GlowObject;
import com.kartoflane.superluminal2.ftl.ShipMetadata;
import com.kartoflane.superluminal2.ftl.WeaponList;
import com.kartoflane.superluminal2.ftl.WeaponObject;
/**
* This class contains utility methods used to interpret XML tags as game objects.
*
* @author kartoFlane
*
*/
public class DataUtils {
public static final Logger log = LogManager.getLogger(DataUtils.class);
/**
* Finds all ships with the specified blueprintName within the file.
*
* @param f
* @param blueprintName
* @return
* @throws JDOMParseException
* when the contents of the stream could not be parsed.
* @throws IOException
*/
public static ArrayList<Element> findShipsWithName(String blueprintName, InputStream is, String fileName)
throws IllegalArgumentException, JDOMParseException, IOException {
if (blueprintName == null)
throw new IllegalArgumentException("Blueprint name must not be null.");
IOUtils.DecodeResult dr = IOUtils.decodeText(is, null);
String contents = dr.text;
Document doc = IOUtils.parseXML(contents);
ArrayList<Element> shipList = new ArrayList<Element>();
Element root = doc.getRootElement();
if (root.getName().equals("shipBlueprint")) {
String blueprint = root.getAttributeValue("name");
if (blueprint != null && blueprint.equals(blueprintName))
shipList.add(root);
} else {
for (Element e : root.getChildren("shipBlueprint")) {
String blueprint = e.getAttributeValue("name");
if (blueprint != null && blueprint.equals(blueprintName))
shipList.add(e);
}
}
return shipList;
}
public static ArrayList<Element> findShipsWithName(File f, String blueprintName)
throws IllegalArgumentException, JDOMParseException, IOException {
return findShipsWithName(blueprintName, new FileInputStream(f), f.getName());
}
public static ArrayList<Element> findTagsNamed(String contents, String tagName) throws JDOMParseException {
Document doc = null;
doc = IOUtils.parseXML(contents);
ArrayList<Element> tagList = new ArrayList<Element>();
Element root = doc.getRootElement();
if (root.getName().equals(tagName)) {
tagList.add(root);
} else {
for (Element e : root.getChildren(tagName))
tagList.add(e);
}
return tagList;
}
public static ArrayList<Element> findTagsNamed(InputStream is, String fileName, String tagName)
throws IllegalArgumentException, JDOMParseException, IOException {
IOUtils.DecodeResult dr = IOUtils.decodeText(is, fileName);
return findTagsNamed(dr.text, tagName);
}
public static ArrayList<Element> findTagsNamed(File f, String tagName)
throws IllegalArgumentException, JDOMParseException, IOException {
return findTagsNamed(new FileInputStream(f), f.getName(), tagName);
}
/**
* Loads the ship's metadata from the supplied Element
*
* @param e
* XML element for the shipBlueprint tag
* @return the ship's metadata - blueprint name, txt and xml layouts, name, class, description
*/
public static ShipMetadata loadShipMetadata(Element e) {
if (e == null)
throw new IllegalArgumentException("Element must not be null.");
String attr = null;
Element child = null;
attr = e.getAttributeValue("name");
if (attr == null)
throw new IllegalArgumentException(e.getName() + " is missing 'name' attribute.");
ShipMetadata metadata = new ShipMetadata(e, attr);
attr = e.getAttributeValue("img");
if (attr == null)
throw new IllegalArgumentException(metadata.getBlueprintName() + " is missing 'img' attribute.");
metadata.setShipImageNamespace(attr);
child = e.getChild("class");
if (child == null)
throw new IllegalArgumentException(metadata.getBlueprintName() + " is missing <class> tag.");
metadata.setShipClass(child.getValue());
if (metadata.isPlayerShip()) {
child = e.getChild("name");
if (child == null)
throw new IllegalArgumentException(metadata.getBlueprintName() + " is missing <name> tag.");
metadata.setShipName(child.getValue());
child = e.getChild("desc");
if (child == null)
metadata.setShipDescription("<desc> tag was missing!");
else
metadata.setShipDescription(child.getValue());
}
return metadata;
}
public static AnimationObject loadAnim(DatabaseEntry de, Element e) {
if (e == null)
throw new IllegalArgumentException("Element must not be null.");
String attr = null;
Element child = null;
attr = e.getAttributeValue("name");
if (attr == null)
throw new IllegalArgumentException(e.getName() + " is missing 'name' attribute.");
AnimationObject anim = new AnimationObject(attr);
// Load mount offset
child = e.getChild("mountPoint");
if (child == null)
throw new IllegalArgumentException(anim.getAnimName() + " is missing <mountPoint> tag");
attr = child.getAttributeValue("x");
if (attr == null)
throw new IllegalArgumentException(anim.getAnimName() + " is missing 'x' attribute.");
int x = Integer.parseInt(attr);
attr = child.getAttributeValue("y");
if (attr == null)
throw new IllegalArgumentException(anim.getAnimName() + " is missing 'y' attribute.");
int y = Integer.parseInt(attr);
anim.setMountOffset(x, y);
// Load the anim sheet
child = e.getChild("sheet");
if (child == null)
throw new IllegalArgumentException(anim.getAnimName() + " is missing <sheet> tag");
Element sheet = de.getAnimSheetElement(child.getValue());
if (sheet == null)
throw new IllegalArgumentException(anim.getAnimName() + "'s animSheet could not be found: " + child.getValue());
// Load sheet dimensions
attr = sheet.getAttributeValue("w");
if (attr == null)
throw new IllegalArgumentException(anim.getAnimName() + " is missing 'w' attribute.");
x = Integer.parseInt(attr);
attr = sheet.getAttributeValue("h");
if (attr == null)
throw new IllegalArgumentException(anim.getAnimName() + " is missing 'h' attribute.");
y = Integer.parseInt(attr);
anim.setSheetSize(x, y);
// Load frame dimensions
attr = sheet.getAttributeValue("fw");
if (attr == null)
throw new IllegalArgumentException(anim.getAnimName() + " is missing 'fw' attribute.");
x = Integer.parseInt(attr);
attr = sheet.getAttributeValue("fh");
if (attr == null)
throw new IllegalArgumentException(anim.getAnimName() + " is missing 'fh' attribute.");
y = Integer.parseInt(attr);
anim.setFrameSize(x, y);
// Load the anim sheet image path
anim.setSheetPath("db:img/" + sheet.getValue());
return anim;
}
/**
*
* @param e
* element to be parsed
* @return blueprint list the element represents, or null if the list was not
* holding weapons or drones
*/
public static BlueprintList<? extends GameObject> loadList(Element e) {
if (e == null)
throw new IllegalArgumentException("Element must not be null.");
String attr = e.getAttributeValue("name");
if (attr == null)
throw new IllegalArgumentException(e.getName() + " is missing 'name' attribute.");
List<Element> children = e.getChildren("name");
if (children.size() == 0) {
throw new IllegalArgumentException(attr + ": list is empty.");
} else {
// Need to figure out the type of the list...
// Checking the type of the first child seems like the most reasonable option
String name = children.get(0).getValue();
if (Database.getInstance().getWeapon(name) != null) {
return loadWeaponList(attr, children);
} else if (Database.getInstance().getDrone(name) != null) {
return loadDroneList(attr, children);
} else {
// Not interested in any other blueprintLists
}
}
return null;
}
private static WeaponList loadWeaponList(String name, List<Element> children) {
if (name == null)
throw new IllegalArgumentException("Name must not be null.");
if (children == null)
throw new IllegalArgumentException("Children list must not be null.");
Database db = Database.getInstance();
WeaponList list = new WeaponList(name);
for (Element child : children) {
WeaponObject weapon = db.getWeapon(child.getValue());
if (weapon != null)
list.add(weapon);
}
return list;
}
private static DroneList loadDroneList(String name, List<Element> children) {
if (name == null)
throw new IllegalArgumentException("Name must not be null.");
if (children == null)
throw new IllegalArgumentException("Children list must not be null.");
Database db = Database.getInstance();
DroneList list = new DroneList(name);
for (Element child : children) {
DroneObject drone = db.getDrone(child.getValue());
if (drone != null)
list.add(drone);
}
return list;
}
public static WeaponObject loadWeapon(Element e) {
if (e == null)
throw new IllegalArgumentException("Element must not be null.");
String attr = null;
Element child = null;
attr = e.getAttributeValue("name");
if (attr == null)
throw new IllegalArgumentException(e.getName() + " is missing 'name' attribute.");
WeaponObject weapon = new WeaponObject(attr);
child = e.getChild("type");
if (child == null)
throw new IllegalArgumentException(weapon.getBlueprintName() + " is missing <type> tag.");
weapon.setType(WeaponTypes.valueOf(child.getValue()));
child = e.getChild("title");
if (child == null)
throw new IllegalArgumentException(weapon.getBlueprintName() + " is missing <title> tag.");
weapon.setTitle(child.getValue());
child = e.getChild("short");
if (child == null)
weapon.setShortName("Missing short name");
else
weapon.setShortName(child.getValue());
child = e.getChild("desc");
if (child == null)
weapon.setDescription("Missing description.");
else
weapon.setDescription(child.getValue());
child = e.getChild("weaponArt");
if (child == null)
throw new IllegalArgumentException(weapon.getBlueprintName() + " is missing <weaponArt> tag.");
try {
weapon.setAnimName(child.getValue());
} catch (IllegalArgumentException ex) {
// Catch an re-throw the error to provide more information
throw new IllegalArgumentException(weapon.getBlueprintName() + ": could not find animation '" + child.getValue() + "'.", ex);
}
for (WeaponStats stat : WeaponStats.values()) {
try {
child = e.getChild(stat.getTagName());
if (child != null)
weapon.setStat(stat, Float.parseFloat(child.getValue()));
} catch (NumberFormatException ex) {
// Catch an re-throw the error to provide more information
throw new IllegalArgumentException(weapon.getBlueprintName() + ": <" + stat.getTagName() + "> tag's value could not be parsed: " + child.getValue());
}
}
return weapon;
}
public static DroneObject loadDrone(Element e) {
if (e == null)
throw new IllegalArgumentException("Element must not be null.");
String attr = null;
Element child = null;
attr = e.getAttributeValue("name");
if (attr == null)
throw new IllegalArgumentException(e.getName() + " is missing 'name' attribute.");
DroneObject drone = new DroneObject(attr);
child = e.getChild("type");
if (child == null)
throw new IllegalArgumentException(drone.getBlueprintName() + " is missing <type> tag.");
drone.setType(DroneTypes.valueOf(child.getValue()));
child = e.getChild("title");
if (child == null)
throw new IllegalArgumentException(drone.getBlueprintName() + " is missing <title> tag.");
drone.setTitle(child.getValue());
child = e.getChild("short");
if (child == null)
drone.setShortName("Missing short name");
else
drone.setShortName(child.getValue());
child = e.getChild("desc");
if (child == null)
drone.setDescription("Missing description.");
else
drone.setDescription(child.getValue());
for (DroneStats stat : DroneStats.values()) {
try {
child = e.getChild(stat.getTagName());
if (child != null)
drone.setStat(stat, Float.parseFloat(child.getValue()));
} catch (NumberFormatException ex) {
// Catch an re-throw the error to provide more information
throw new IllegalArgumentException(drone.getBlueprintName() + ": <" + stat.getTagName() + "> tag's value could not be parsed: " + child.getValue());
}
}
return drone;
}
public static AugmentObject loadAugment(Element e) {
if (e == null)
throw new IllegalArgumentException("Element must not be null.");
String attr = null;
Element child = null;
attr = e.getAttributeValue("name");
if (attr == null)
throw new IllegalArgumentException(e.getName() + " is missing 'name' attribute.");
AugmentObject augment = new AugmentObject(attr);
child = e.getChild("title");
if (child == null)
throw new IllegalArgumentException(augment.getBlueprintName() + " is missing <title> tag.");
augment.setTitle(child.getValue());
child = e.getChild("desc");
if (child == null)
throw new IllegalArgumentException(augment.getBlueprintName() + " is missing <desc> tag.");
augment.setDescription(child.getValue());
return augment;
}
public static GlowObject loadGlow(Element e) {
if (e == null)
throw new IllegalArgumentException("Element must not be null.");
String attr = null;
Element child = null;
// Identifier of the glow set, has to match an existing interior image in order for the game to link them
attr = e.getAttributeValue("name");
if (attr == null)
throw new IllegalArgumentException(e.getName() + " is missing 'name' attribute.");
GlowObject glow = new GlowObject(attr);
child = e.getChild("computerGlow");
if (child == null)
throw new IllegalArgumentException(glow.getIdentifier() + " is missing a <computerGlow> tag.");
// Optional attribute that allows to use a different image for the glow
attr = child.getAttributeValue("name");
if (attr != null)
glow.setGlowSet(Database.getInstance().getGlowSet(attr));
attr = child.getAttributeValue("x");
if (attr == null)
throw new IllegalArgumentException(glow.getIdentifier() + "'s <computerGlow> is missing 'x' attribute.");
glow.setX(Integer.parseInt(attr));
attr = child.getAttributeValue("y");
if (attr == null)
throw new IllegalArgumentException(glow.getIdentifier() + "'s <computerGlow> is missing 'y' attribute.");
glow.setY(Integer.parseInt(attr));
attr = child.getAttributeValue("dir");
if (attr == null)
throw new IllegalArgumentException(glow.getIdentifier() + "'s <computerGlow> is missing 'dir' attribute.");
glow.setDirection(Directions.parseDir(attr));
return glow;
}
}