/*
* GamePreset.java
*
* Copyright (c) 2015 Jay Lawson <jaylawson39 at yahoo.com>. All rights reserved.
*
* This file is part of MekHQ.
*
* MekHQ 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.
*
* MekHQ 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 MekHQ. If not, see <http://www.gnu.org/licenses/>.
*/
package mekhq.campaign;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.PrintWriter;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Hashtable;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import megamek.common.options.PilotOptions;
import mekhq.MekHQ;
import mekhq.MekHqXmlSerializable;
import mekhq.MekHqXmlUtil;
import mekhq.NullEntityException;
import mekhq.Utilities;
import mekhq.campaign.personnel.SkillType;
import mekhq.campaign.personnel.SpecialAbility;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* This is an object which holds a set of objects that collectively define the game options
* for a campaign. This includes the campaign options, the skill types, the random skill preferences,
* and the special ability list. There will also be a short title and description here that allows users
* to create and save different presets. The goal is to allow users to create and load various different
* presets.
* @author Jay Lawson <jaylawson39 at yahoo.com>
*/
public class GamePreset implements MekHqXmlSerializable {
String title;
String description;
CampaignOptions options;
RandomSkillPreferences rskillPrefs;
Hashtable<String, SkillType> skillHash;
Hashtable<String, SpecialAbility> specialAbilities;
public GamePreset() {
title = "Title missing";
description = "Description missing";
options = null;
rskillPrefs = null;
skillHash = new Hashtable<String, SkillType>();
specialAbilities = new Hashtable<String, SpecialAbility>();
}
public GamePreset(String t, String d, CampaignOptions o, RandomSkillPreferences r, Hashtable<String, SkillType> sk, Hashtable<String, SpecialAbility> sp) {
title = t;
description = d;
options = o;
rskillPrefs = r;
skillHash = sk;
specialAbilities = sp;
}
public String getTitle() {
return title;
}
public void setTitle(String s) {
title = s;
}
public String getDescription() {
return description;
}
public void setDescription(String s) {
description = s;
}
public void apply(Campaign campaign) {
if(null != options) {
campaign.setCampaignOptions(options);
}
if(null != rskillPrefs) {
campaign.setRandomSkillPreferences(rskillPrefs);
}
if(null != skillHash) {
SkillType.setSkillTypes(skillHash);
}
if(null != specialAbilities) {
SpecialAbility.setSpecialAbilities(specialAbilities);
}
}
public boolean isValid() {
//could be used to disqualify bad presets
return true;
}
public void writeToXml(PrintWriter pw, int indent) {
pw.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
pw.println("<gamePreset>");
pw.println("\t<title>"+ MekHqXmlUtil.escape(title) + "</title>");
pw.println("\t<description>" + MekHqXmlUtil.escape(description) + "</description>");
if(null != options) {
options.writeToXml(pw,1);
}
if(null != skillHash) {
pw.println("\t<skillTypes>");
for (String name : SkillType.skillList) {
SkillType type = skillHash.get(name);
if (null != type) {
type.writeToXml(pw, 2);
}
}
pw.println("\t</skillTypes>");
}
if(null != specialAbilities) {
pw.println("\t<specialAbilities>");
for(String key : specialAbilities.keySet()) {
specialAbilities.get(key).writeToXml(pw, 2);
}
pw.println("\t</specialAbilities>");
}
if(null != rskillPrefs) {
rskillPrefs.writeToXml(pw, 1);
}
pw.println("</gamePreset>");
}
public static GamePreset createGamePresetFromXMLFileInputStream(
FileInputStream fis) throws DOMException, ParseException,
NullEntityException {
GamePreset preset = new GamePreset();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
Document xmlDoc = null;
try {
// Using factory get an instance of document builder
DocumentBuilder db = dbf.newDocumentBuilder();
// Parse using builder to get DOM representation of the XML file
xmlDoc = db.parse(fis);
} catch (Exception ex) {
MekHQ.logError(ex);
return preset;
}
Element optionsEle = xmlDoc.getDocumentElement();
NodeList nl = optionsEle.getChildNodes();
// Get rid of empty text nodes and adjacent text nodes...
// Stupid weird parsing of XML. At least this cleans it up.
optionsEle.normalize();
// Okay, lets iterate through the children, eh?
for (int x = 0; x < nl.getLength(); x++) {
Node wn = nl.item(x);
if (wn.getParentNode() != optionsEle) {
continue;
}
int xc = wn.getNodeType();
if (xc == Node.ELEMENT_NODE) {
String xn = wn.getNodeName();
if (xn.equalsIgnoreCase("title")) {
preset.title = wn.getTextContent();
} else if (xn.equalsIgnoreCase("description")) {
preset.description = wn.getTextContent();
}
else if (xn.equalsIgnoreCase("campaignOptions")) {
preset.options = CampaignOptions.generateCampaignOptionsFromXml(wn);
} else if (xn.equalsIgnoreCase("randomSkillPreferences")) {
preset.rskillPrefs = RandomSkillPreferences.generateRandomSkillPreferencesFromXml(wn);
} else if (xn.equalsIgnoreCase("skillTypes")) {
NodeList wList = wn.getChildNodes();
// Okay, lets iterate through the children, eh?
for (int z = 0; z < wList.getLength(); z++) {
Node wn2 = wList.item(z);
// If it's not an element node, we ignore it.
if (wn2.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
if (wn2.getNodeName().startsWith("ability-")) {
continue;
} else if (!wn2.getNodeName().equalsIgnoreCase("skillType")) {
// Error condition of sorts!
// Errr, what should we do here?
MekHQ.logMessage("Unknown node type not loaded in Skill Type nodes: "
+ wn2.getNodeName());
continue;
}
SkillType.generateSeparateInstanceFromXML(wn2, preset.skillHash);
}
} else if (xn.equalsIgnoreCase("specialAbilities")) {
PilotOptions options = new PilotOptions();
NodeList wList = wn.getChildNodes();
// Okay, lets iterate through the children, eh?
for (int z = 0; z < wList.getLength(); z++) {
Node wn2 = wList.item(z);
// If it's not an element node, we ignore it.
if (wn2.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
if (!wn2.getNodeName().equalsIgnoreCase("ability")) {
// Error condition of sorts!
// Errr, what should we do here?
MekHQ.logMessage("Unknown node type not loaded in Special Ability nodes: "
+ wn2.getNodeName());
continue;
}
SpecialAbility.generateSeparateInstanceFromXML(wn2, preset.specialAbilities, options);
}
}
}
}
return preset;
}
/**
* Collect and load all the Game Presets in files in a given directory and
* return an ArrayList of them
* @param directory
* @return
*/
public static ArrayList<GamePreset> getGamePresetsIn(String directory) {
ArrayList<GamePreset> presets = new ArrayList<GamePreset>();
File[] files = Utilities.getAllFiles(MekHQ.PRESET_DIR, new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".xml");
}
});
for(File file : files) {
// And then load the campaign object from it.
FileInputStream fis = null;
GamePreset preset = null;
try {
fis = new FileInputStream(file);
preset = GamePreset.createGamePresetFromXMLFileInputStream(fis);
if(preset.isValid()) {
presets.add(preset);
}
fis.close();
} catch (Exception ex) {
ex.printStackTrace();
/* JOptionPane.showMessageDialog(null,
"The campaign file could not be loaded.\nPlease check the log file for details.",
"Campaign Loading Error",
JOptionPane.ERROR_MESSAGE);*/
}
}
return presets;
}
}