From 6a9d30e9310ba38db3313cb078fd662d24fb5a97 Mon Sep 17 00:00:00 2001 From: drdev Date: Sun, 27 Dec 2015 00:31:24 +0000 Subject: [PATCH] Start working on more reliable way to load and save Planar Conquest data --- .gitattributes | 3 +- .../screens/planarconquest/ConquestMenu.java | 8 +- .../planarconquest/LoadConquestScreen.java | 16 +- .../planarconquest/ConquestCommander.java | 10 +- .../forge/planarconquest/ConquestData.java | 85 ++++++----- .../forge/planarconquest/ConquestDataIO.java | 143 ------------------ .../planarconquest/ConquestLocation.java | 20 ++- .../planarconquest/ConquestPlaneData.java | 14 +- .../forge/planarconquest/ConquestRecord.java | 12 +- .../src/main/java/forge/util/XmlReader.java | 73 +++++++++ .../src/main/java/forge/util/XmlWriter.java | 102 +++++++++++++ 11 files changed, 284 insertions(+), 202 deletions(-) delete mode 100644 forge-gui/src/main/java/forge/planarconquest/ConquestDataIO.java create mode 100644 forge-gui/src/main/java/forge/util/XmlReader.java create mode 100644 forge-gui/src/main/java/forge/util/XmlWriter.java diff --git a/.gitattributes b/.gitattributes index fbb2c975ccf..8d12cbe34f8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -18306,7 +18306,6 @@ forge-gui/src/main/java/forge/net/server/package-info.java -text forge-gui/src/main/java/forge/planarconquest/ConquestCommander.java -text forge-gui/src/main/java/forge/planarconquest/ConquestController.java -text forge-gui/src/main/java/forge/planarconquest/ConquestData.java -text -forge-gui/src/main/java/forge/planarconquest/ConquestDataIO.java -text forge-gui/src/main/java/forge/planarconquest/ConquestDeckMap.java -text forge-gui/src/main/java/forge/planarconquest/ConquestEvent.java -text forge-gui/src/main/java/forge/planarconquest/ConquestLocation.java -text @@ -18403,7 +18402,9 @@ forge-gui/src/main/java/forge/util/OperatingSystem.java -text forge-gui/src/main/java/forge/util/RestartUtil.java -text forge-gui/src/main/java/forge/util/WaitCallback.java -text forge-gui/src/main/java/forge/util/WaitRunnable.java -text +forge-gui/src/main/java/forge/util/XmlReader.java -text forge-gui/src/main/java/forge/util/XmlUtil.java -text +forge-gui/src/main/java/forge/util/XmlWriter.java -text forge-gui/src/main/java/forge/util/gui/SGuiChoose.java -text forge-gui/src/main/java/forge/util/gui/SOptionPane.java -text forge-gui/src/main/java/forge/util/package-info.java -text diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java index 2b41baf7988..b304bb5cd68 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java @@ -10,7 +10,7 @@ import forge.deck.FDeckEditor.EditorType; import forge.menu.FMenuItem; import forge.menu.FPopupMenu; import forge.model.FModel; -import forge.planarconquest.ConquestDataIO; +import forge.planarconquest.ConquestData; import forge.planarconquest.ConquestPreferences.CQPref; import forge.properties.ForgeConstants; import forge.screens.FScreen; @@ -75,14 +75,14 @@ public class ConquestMenu extends FPopupMenu { public static void launchPlanarConquest(final LaunchReason reason) { //attempt to load current quest final File dirConquests = new File(ForgeConstants.CONQUEST_SAVE_DIR); - final String questname = FModel.getConquestPreferences().getPref(CQPref.CURRENT_CONQUEST); - final File data = new File(dirConquests.getPath(), questname); + final String conquestname = FModel.getConquestPreferences().getPref(CQPref.CURRENT_CONQUEST); + final File data = new File(dirConquests.getPath(), conquestname); if (data.exists()) { LoadingOverlay.show("Loading current conquest...", new Runnable() { @Override @SuppressWarnings("unchecked") public void run() { - FModel.getConquest().load(ConquestDataIO.loadData(data)); + FModel.getConquest().load(new ConquestData(data)); ((DeckController)EditorType.PlanarConquest.getController()).setRootFolder(FModel.getConquest().getDecks()); if (reason == LaunchReason.StartPlanarConquest) { Forge.openScreen(multiverseScreen); diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/LoadConquestScreen.java b/forge-gui-mobile/src/forge/screens/planarconquest/LoadConquestScreen.java index 3341fd58242..f70c3a4649c 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/LoadConquestScreen.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/LoadConquestScreen.java @@ -1,7 +1,6 @@ package forge.screens.planarconquest; import java.io.File; -import java.io.FilenameFilter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -21,7 +20,6 @@ import forge.assets.FSkinImage; import forge.model.FModel; import forge.planarconquest.ConquestController; import forge.planarconquest.ConquestData; -import forge.planarconquest.ConquestDataIO; import forge.planarconquest.ConquestPreferences.CQPref; import forge.properties.ForgeConstants; import forge.quest.QuestUtil; @@ -93,17 +91,11 @@ public class LoadConquestScreen extends LaunchScreen { final File dirConquests = new File(ForgeConstants.CONQUEST_SAVE_DIR); final ConquestController qc = FModel.getConquest(); - // Iterate over files and load quest data for each. - FilenameFilter takeDatFiles = new FilenameFilter() { - @Override - public boolean accept(final File dir, final String name) { - return name.endsWith(".dat"); - } - }; - File[] arrFiles = dirConquests.listFiles(takeDatFiles); Map arrConquests = new HashMap(); - for (File f : arrFiles) { - arrConquests.put(f.getName(), ConquestDataIO.loadData(f)); + for (File f : dirConquests.listFiles()) { + if (f.isDirectory()) { + arrConquests.put(f.getName(), new ConquestData(f)); + } } // Populate list with available quest data. diff --git a/forge-gui/src/main/java/forge/planarconquest/ConquestCommander.java b/forge-gui/src/main/java/forge/planarconquest/ConquestCommander.java index 89630831ab7..a04f855d0a7 100644 --- a/forge-gui/src/main/java/forge/planarconquest/ConquestCommander.java +++ b/forge-gui/src/main/java/forge/planarconquest/ConquestCommander.java @@ -5,8 +5,10 @@ import forge.deck.generation.DeckGenPool; import forge.item.InventoryItem; import forge.item.PaperCard; import forge.planarconquest.ConquestPlane.Region; +import forge.util.XmlWriter; +import forge.util.XmlWriter.IXmlWritable; -public class ConquestCommander implements InventoryItem { +public class ConquestCommander implements InventoryItem, IXmlWritable { private final PaperCard card; private final Deck deck; private final ConquestRecord record; @@ -93,4 +95,10 @@ public class ConquestCommander implements InventoryItem { public String toString() { return card.getName(); } + + @Override + public void saveToXml(XmlWriter xml) { + xml.write("card", card); + xml.write("record", record); + } } diff --git a/forge-gui/src/main/java/forge/planarconquest/ConquestData.java b/forge-gui/src/main/java/forge/planarconquest/ConquestData.java index df6d7be1675..0edaac1864e 100644 --- a/forge-gui/src/main/java/forge/planarconquest/ConquestData.java +++ b/forge-gui/src/main/java/forge/planarconquest/ConquestData.java @@ -30,7 +30,10 @@ import forge.model.FModel; import forge.planarconquest.ConquestPlane.Region; import forge.planarconquest.ConquestPreferences.CQPref; import forge.properties.ForgeConstants; +import forge.util.FileUtil; import forge.util.ItemPool; +import forge.util.XmlReader; +import forge.util.XmlWriter; import java.io.File; import java.util.ArrayList; @@ -45,23 +48,17 @@ import java.util.Map.Entry; import com.google.common.base.Function; public final class ConquestData { - /** Holds the latest version of the Conquest Data. */ - public static final int CURRENT_VERSION_NUMBER = 0; - - // This field places the version number into QD instance, - // but only when the object is created through the constructor - // DO NOT RENAME THIS FIELD - private int versionNumber = ConquestData.CURRENT_VERSION_NUMBER; + private static final String XML_FILE = "data.xml"; private String name; - private ConquestPlane startingPlane; private PaperCard planeswalker; private ISkinImage planeswalkerToken; private ConquestLocation currentLocation; private int aetherShards; + private ConquestCollection collection; - private transient ConquestCollection collection; //don't serialize this - + private final File directory; + private final String xmlFilename; private final EnumMap planeDataMap = new EnumMap(ConquestPlane.class); private final HashSet unlockedCards = new HashSet(); private final List commanders = new ArrayList(); @@ -69,26 +66,44 @@ public final class ConquestData { private final ItemPool decksUsingMyCards = new ItemPool(InventoryItem.class); private final HashSet newCards = new HashSet(); - public ConquestData() { //needed for XML serialization - } - public ConquestData(String name0, PaperCard planeswalker0, ConquestPlane startingPlane0, PaperCard startingCommander0) { name = name0; + directory = new File(ForgeConstants.CONQUEST_SAVE_DIR, name); + xmlFilename = directory.getPath() + ForgeConstants.PATH_SEPARATOR + XML_FILE; aetherShards = FModel.getConquestPreferences().getPrefInt(CQPref.AETHER_START_SHARDS); - startingPlane = startingPlane0; - currentLocation = new ConquestLocation(startingPlane, 0, 0, Region.START_COL); + currentLocation = new ConquestLocation(startingPlane0, 0, 0, Region.START_COL); planeswalker = planeswalker0; planeswalkerToken = PlaneswalkerAchievements.getTrophyImage(planeswalker.getName()); unlockCard(planeswalker); //generate deck for starting commander and add all cards to collection - ConquestCommander commander = new ConquestCommander(startingCommander0, startingPlane.getCardPool(), false); + ConquestCommander commander = new ConquestCommander(startingCommander0, startingPlane0.getCardPool(), false); commanders.add(commander); unlockCard(startingCommander0); unlockCards(commander.getDeck().getMain().toFlatList()); decks.put(commander.getDeck().getName(), commander.getDeck()); } + public ConquestData(File directory0) { + name = directory0.getName(); + directory = directory0; + xmlFilename = directory.getPath() + ForgeConstants.PATH_SEPARATOR + XML_FILE; + + try { + XmlReader xml = new XmlReader(xmlFilename); + planeswalker = xml.read("planeswalker", planeswalker); + aetherShards = xml.read("aetherShards", aetherShards); + currentLocation = xml.read("currentLocation", currentLocation, ConquestLocation.class); + /*xml.read("unlockedCards", unlockedCards); + xml.read("newCards", newCards); + xml.read("commanders", commanders); + xml.read("planeDataMap", planeDataMap);*/ + } + catch (Exception e) { + e.printStackTrace(); + } + } + public String getName() { return name; } @@ -101,10 +116,6 @@ public final class ConquestData { return planeswalkerToken; } - public ConquestPlane getStartingPlane() { - return startingPlane; - } - public ConquestPlane getCurrentPlane() { return currentLocation.getPlane(); } @@ -207,30 +218,28 @@ public final class ConquestData { return Math.round(100f * (float)conquered / (float)total) + "%"; } - // SERIALIZATION - related things - // This must be called by XML-serializer via reflection - public Object readResolve() { - return this; - } - public void saveData() { - ConquestDataIO.saveData(this); - } + FileUtil.ensureDirectoryExists(directory); - public int getVersionNumber() { - return versionNumber; - } - public void setVersionNumber(final int versionNumber0) { - versionNumber = versionNumber0; + try { + XmlWriter xml = new XmlWriter(xmlFilename, "data"); + xml.write("planeswalker", planeswalker); + xml.write("aetherShards", aetherShards); + xml.write("currentLocation", currentLocation); + xml.write("unlockedCards", unlockedCards); + xml.write("newCards", newCards); + xml.write("commanders", commanders); + xml.write("planeDataMap", planeDataMap); + xml.close(); + } + catch (Exception e) { + e.printStackTrace(); + } } public void rename(final String newName) { - File newpath = new File(ForgeConstants.CONQUEST_SAVE_DIR, newName + ".dat"); - File oldpath = new File(ForgeConstants.CONQUEST_SAVE_DIR, name + ".dat"); - oldpath.renameTo(newpath); - name = newName; - saveData(); + directory.renameTo(new File(ForgeConstants.CONQUEST_SAVE_DIR, name)); } public void updateDecksForEachCard() { diff --git a/forge-gui/src/main/java/forge/planarconquest/ConquestDataIO.java b/forge-gui/src/main/java/forge/planarconquest/ConquestDataIO.java deleted file mode 100644 index 801dac828a9..00000000000 --- a/forge-gui/src/main/java/forge/planarconquest/ConquestDataIO.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Forge: Play Magic: the Gathering. - * Copyright (C) 2011 Forge Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package forge.planarconquest; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStreamReader; -import java.io.StringReader; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; - -import org.xml.sax.InputSource; - -import com.thoughtworks.xstream.XStream; - -import forge.deck.CardPool; -import forge.properties.ForgeConstants; -import forge.quest.io.QuestDataIO.DeckToXml; -import forge.quest.io.QuestDataIO.ItemPoolToXml; -import forge.util.FileUtil; -import forge.util.IgnoringXStream; -import forge.util.ItemPool; - -public class ConquestDataIO { - static { - //ensure save directory exists if this class is used - FileUtil.ensureDirectoryExists(ForgeConstants.CONQUEST_SAVE_DIR); - } - - protected static XStream getSerializer(final boolean isIgnoring) { - final XStream xStream = isIgnoring ? new IgnoringXStream() : new XStream(); - xStream.registerConverter(new ItemPoolToXml()); - xStream.registerConverter(new DeckToXml()); - xStream.autodetectAnnotations(true); - xStream.alias("CardPool", ItemPool.class); - xStream.alias("DeckSection", CardPool.class); - return xStream; - } - - public static ConquestData loadData(final File xmlSaveFile) { - try { - ConquestData data = null; - - final GZIPInputStream zin = new GZIPInputStream(new FileInputStream(xmlSaveFile)); - final StringBuilder xml = new StringBuilder(); - final char[] buf = new char[1024]; - final InputStreamReader reader = new InputStreamReader(zin); - while (reader.ready()) { - final int len = reader.read(buf); - if (len == -1) { - break; - } // when end of stream was reached - xml.append(buf, 0, len); - } - - zin.close(); - - String bigXML = xml.toString(); - data = (ConquestData) ConquestDataIO.getSerializer(true).fromXML(bigXML); - - if (data.getVersionNumber() != ConquestData.CURRENT_VERSION_NUMBER) { - try { - ConquestDataIO.updateSaveFile(data, bigXML, xmlSaveFile.getName().replace(".dat", "")); - } - catch (final Exception e) { - //BugReporter.reportException(e); - throw new RuntimeException(e); - } - } - - return data; - } - catch (final Exception ex) { - throw new RuntimeException(ex); - } - } - - private static void updateSaveFile(final ConquestData newData, final String input, String filename) throws Exception { - //final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - final InputSource is = new InputSource(); - is.setCharacterStream(new StringReader(input)); - //final Document document = builder.parse(is); - - final int saveVersion = newData.getVersionNumber(); - switch (saveVersion) { - // There should be a fall-through between the cases so that each - // version's changes get applied progressively - case 0: - - default: - break; - } - - // mark the QD as the latest version - newData.setVersionNumber(ConquestData.CURRENT_VERSION_NUMBER); - } - - public static synchronized void saveData(final ConquestData qd) { - try { - final XStream xStream = ConquestDataIO.getSerializer(false); - - final File f = new File(ForgeConstants.CONQUEST_SAVE_DIR, qd.getName()); - ConquestDataIO.savePacked(f + ".dat", xStream, qd); - // ConquestDataIO.saveUnpacked(f + ".xml", xStream, qd); - } - catch (final Exception ex) { - throw new RuntimeException(ex); - } - } - - private static void savePacked(final String f, final XStream xStream, final ConquestData qd) throws Exception { - final BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(f)); - final GZIPOutputStream zout = new GZIPOutputStream(bout); - xStream.toXML(qd, zout); - zout.flush(); - zout.close(); - } - - @SuppressWarnings("unused") // used only for debug purposes - private static void saveUnpacked(final String f, final XStream xStream, final ConquestData qd) throws Exception { - final BufferedOutputStream boutUnp = new BufferedOutputStream(new FileOutputStream(f)); - xStream.toXML(qd, boutUnp); - boutUnp.flush(); - boutUnp.close(); - } -} diff --git a/forge-gui/src/main/java/forge/planarconquest/ConquestLocation.java b/forge-gui/src/main/java/forge/planarconquest/ConquestLocation.java index 2415ea34ade..e546f154463 100644 --- a/forge-gui/src/main/java/forge/planarconquest/ConquestLocation.java +++ b/forge-gui/src/main/java/forge/planarconquest/ConquestLocation.java @@ -9,8 +9,11 @@ import forge.game.GameType; import forge.item.PaperCard; import forge.planarconquest.ConquestPlane.Region; import forge.util.Aggregates; +import forge.util.XmlReader; +import forge.util.XmlWriter; +import forge.util.XmlWriter.IXmlWritable; -public class ConquestLocation { +public class ConquestLocation implements IXmlWritable { private ConquestPlane plane; private int regionIndex; private int row; @@ -20,6 +23,13 @@ public class ConquestLocation { public ConquestLocation() { } + public ConquestLocation(XmlReader xml) { + plane = xml.read("plane", plane, ConquestPlane.class); + regionIndex = xml.read("regionIndex", regionIndex); + row = xml.read("row", row); + col = xml.read("col", col); + } + public ConquestLocation(ConquestPlane plane0, int regionIndex0, int row0, int col0) { plane = plane0; regionIndex = regionIndex0; @@ -125,4 +135,12 @@ public class ConquestLocation { } }; } + + @Override + public void saveToXml(XmlWriter xml) { + xml.write("plane", plane); + xml.write("regionIndex", regionIndex); + xml.write("row", row); + xml.write("col", col); + } } diff --git a/forge-gui/src/main/java/forge/planarconquest/ConquestPlaneData.java b/forge-gui/src/main/java/forge/planarconquest/ConquestPlaneData.java index 731bc2a2a6c..cd2e4c37cb9 100644 --- a/forge-gui/src/main/java/forge/planarconquest/ConquestPlaneData.java +++ b/forge-gui/src/main/java/forge/planarconquest/ConquestPlaneData.java @@ -3,8 +3,10 @@ package forge.planarconquest; import forge.item.PaperCard; import forge.model.FModel; import forge.planarconquest.ConquestPlane.Region; +import forge.util.XmlWriter; +import forge.util.XmlWriter.IXmlWritable; -public class ConquestPlaneData { +public class ConquestPlaneData implements IXmlWritable { private final ConquestPlane plane; private final ConquestRecord[] eventResults; @@ -63,4 +65,14 @@ public class ConquestPlaneData { } return count; } + + @Override + public void saveToXml(XmlWriter xml) { + xml.write("plane", plane); + xml.startElement("eventResults"); + for (int i = 0; i < eventResults.length; i++) { + xml.write(String.valueOf(i), eventResults[i]); + } + xml.endElement(); + } } diff --git a/forge-gui/src/main/java/forge/planarconquest/ConquestRecord.java b/forge-gui/src/main/java/forge/planarconquest/ConquestRecord.java index bf42e564c59..6ccbee8d546 100644 --- a/forge-gui/src/main/java/forge/planarconquest/ConquestRecord.java +++ b/forge-gui/src/main/java/forge/planarconquest/ConquestRecord.java @@ -1,6 +1,9 @@ package forge.planarconquest; -public class ConquestRecord { +import forge.util.XmlWriter; +import forge.util.XmlWriter.IXmlWritable; + +public class ConquestRecord implements IXmlWritable { private int wins, losses, level; public int getWins() { @@ -26,4 +29,11 @@ public class ConquestRecord { public void levelUp() { level++; } + + @Override + public void saveToXml(XmlWriter xml) { + xml.write("wins", wins); + xml.write("losses", losses); + xml.write("level", level); + } } diff --git a/forge-gui/src/main/java/forge/util/XmlReader.java b/forge-gui/src/main/java/forge/util/XmlReader.java new file mode 100644 index 00000000000..55987ceb3ba --- /dev/null +++ b/forge-gui/src/main/java/forge/util/XmlReader.java @@ -0,0 +1,73 @@ +package forge.util; + +import java.io.File; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import forge.item.PaperCard; +import forge.util.XmlWriter.IXmlWritable; + +public class XmlReader { + private Element currentElement; + + public XmlReader(String filename0) throws Exception { + DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + final Document document = builder.parse(new File(filename0)); + currentElement = (Element)document.getFirstChild(); + } + + public String read(String key, String defaultValue) { + if (currentElement.hasAttribute(key)) { + return currentElement.getAttribute(key); + } + return defaultValue; + } + public > E read(String key, E defaultValue, Class enumType) { + if (currentElement.hasAttribute(key)) { + return Enum.valueOf(enumType, currentElement.getAttribute(key)); + } + return defaultValue; + } + public int read(String key, int defaultValue) { + if (currentElement.hasAttribute(key)) { + return Integer.parseInt(currentElement.getAttribute(key)); + } + return defaultValue; + } + public long read(String key, long defaultValue) { + if (currentElement.hasAttribute(key)) { + return Long.parseLong(currentElement.getAttribute(key)); + } + return defaultValue; + } + public boolean read(String key, boolean defaultValue) { + if (currentElement.hasAttribute(key)) { + return Boolean.parseBoolean(currentElement.getAttribute(key)); + } + return defaultValue; + } + public PaperCard read(String key, PaperCard defaultValue) { + //TODO + return defaultValue; + } + public T read(String key, T defaultValue, Class type) { + readChildElement(key); + /*NodeList elements = currentElement.getElementsByTagName(key); + if (elements.getLength() > 0) { + try { + return type.getDeclaredConstructor(XmlReader.class).newInstance(this); + } + catch (Exception e) { + e.printStackTrace(); + } + }*/ + return defaultValue; + } + + private void readChildElement(String key) { + + } +} diff --git a/forge-gui/src/main/java/forge/util/XmlWriter.java b/forge-gui/src/main/java/forge/util/XmlWriter.java new file mode 100644 index 00000000000..0dd356d9edc --- /dev/null +++ b/forge-gui/src/main/java/forge/util/XmlWriter.java @@ -0,0 +1,102 @@ +package forge.util; + +import java.util.EnumMap; +import java.util.HashSet; +import java.util.Map.Entry; +import java.util.Stack; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import forge.item.PaperCard; + +public class XmlWriter { + private final Document document; + private final String filename; + private final Stack parentElements = new Stack(); + + private Element currentElement; + + public XmlWriter(String filename0, String rootName0) throws Exception { + DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + document = builder.newDocument(); + currentElement = document.createElement(rootName0); + document.appendChild(currentElement); + filename = filename0; + } + + public void startElement(String name0) { + parentElements.add(currentElement); + currentElement = document.createElement(name0); + } + + public void endElement() { + Element parentElement = parentElements.pop(); + if (parentElement == null) { return; } + parentElement.appendChild(currentElement); + currentElement = parentElement; + } + + public void write(String key, String value) { + currentElement.setAttribute(key, value); + } + public void write(String key, Enum value) { + write(key, value.name()); + } + public void write(String key, int value) { + write(key, String.valueOf(value)); + } + public void write(String key, long value) { + write(key, String.valueOf(value)); + } + public void write(String key, boolean value) { + write(key, String.valueOf(value)); + } + public void write(String key, PaperCard value) { + if (value == null) { return; } + + startElement(key); + write("name", value.getName()); + write("set", value.getEdition()); + write("art", value.getArtIndex()); + endElement(); + } + public void write(String key, HashSet value) { + startElement(key); + for (PaperCard card : value) { + write("card", card); + } + endElement(); + } + public void write(String key, IXmlWritable value) { + if (value == null) { return; } + + startElement(key); + value.saveToXml(this); + endElement(); + } + public void write(String key, Iterable value) { + startElement(key); + for (IXmlWritable item : value) { + write("item", item); + } + endElement(); + } + public void write(String key, EnumMap, ? extends IXmlWritable> value) { + startElement(key); + for (Entry, ? extends IXmlWritable> entry : value.entrySet()) { + write(entry.getKey().name(), entry.getValue()); + } + endElement(); + } + + public void close() throws Exception { + XmlUtil.saveDocument(document, filename); + } + + public interface IXmlWritable { + void saveToXml(XmlWriter xml); + } +}