package com.siondream.core;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map.Entry;
import com.badlogic.gdx.Application;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Logger;
import com.badlogic.gdx.utils.XmlReader;
import com.badlogic.gdx.utils.XmlReader.Element;
import com.badlogic.gdx.utils.XmlWriter;
/**
* @class Settings
* @author David Saltares Márquez
* @date 02/09/2012
*
* @brief Holds configuration in a key value fashion
*
* It accepts the following format:
*
* @code
<?xml version="1.0" encoding="UTF-8"?>
<settings>
<string key="appName" value="Sion Engine"
<int key="virtualWidth" value="1280" />
<float key="ppm" value="30.0" />
<vector key="gravity" x="0.0" y="12.0" z="0.0" />
<bool key="drawBodies" value="true" />
</settings>
* @endcode
*/
public class Settings {
private final Logger logger = new Logger("Settings", Logger.ERROR);
private String settingsFile;
private HashMap<String, String> strings = new HashMap<String, String>();
private HashMap<String, Float> floats = new HashMap<String, Float>();
private HashMap<String, Integer> ints = new HashMap<String, Integer>();
private HashMap<String, Boolean> booleans = new HashMap<String, Boolean>();
private HashMap<String, Vector3> vectors = new HashMap<String, Vector3>();
/**
* Loads the default settings file: data/settings.xml
*/
public Settings() {
this("data/settings.xml");
}
/**
* @param settings configuration file to load
*/
public Settings(String settings) {
this.settingsFile = settings;
loadSettings();
}
/**
* @param key setting key
* @return setting value in string form
*/
public String getString(String key) {
return getString(key, "");
}
/**
* @param key setting key
* @param defaultValue default value in case the key doesn't exist
* @return setting value in string form
*/
public String getString(String key, String defaultValue) {
String string = strings.get(key);
if (string != null) {
return string;
}
logger.error(key + " not found, returning default " + defaultValue);
return defaultValue;
}
/**
* @param key setting key
* @return setting value as a float
*/
public float getFloat(String key) {
return getFloat(key, 0.0f);
}
/**
* @param key setting key
* @param defaultValue default value in case the key doesn't exist
* @return setting value as a float
*/
public float getFloat(String key, float defaultValue) {
Float f = floats.get(key);
if (f != null) {
return f;
}
logger.error(key + " not found, returning default " + defaultValue);
return defaultValue;
}
/**
* @param key setting key
* @return setting value as an int
*/
public int getInt(String key) {
return getInt(key, 0);
}
/**
* @param key setting key
* @param defaultValue default value in case the key doesn't exist
* @return setting value as an int
*/
public int getInt(String key, int defaultValue) {
Integer i = ints.get(key);
if (i != null) {
return i;
}
logger.error(key + " not found, returning default " + defaultValue);
return defaultValue;
}
/**
* @param key setting key
* @return setting value as a boolean
*/
public boolean getBoolean(String key) {
return getBoolean(key, false);
}
/**
* @param key setting key
* @param defaultValue default value in case the key doesn't exist
* @return setting value as a boolean
*/
public boolean getBoolean(String key, boolean defaultValue) {
Boolean b = booleans.get(key);
if (b != null) {
return b;
}
logger.error(key + " not found, returning default " + defaultValue);
return defaultValue;
}
/**
* @param key setting key
* @return setting value as a Vector3
*/
public Vector3 getVector(String key) {
return getVector(key, Vector3.Zero.cpy());
}
/**
* @param key setting key
* @param defaultValue default value in case the key doesn't exist
* @return setting value as a Vector3
*/
public Vector3 getVector(String key, Vector3 defaultValue) {
Vector3 v = vectors.get(key);
if (v != null) {
return new Vector3(v);
}
logger.error(key + " not found, returning default " + defaultValue);
return defaultValue;
}
/**
* Modifies or creates a new setting with the given key
*
* @param key key to identify the setting
* @param value value of the setting
*/
public void setString(String key, String value) {
strings.put(key, value);
}
/**
* Modifies or creates a new setting with the given key
*
* @param key key to identify the setting
* @param value value of the setting
*/
public void setFloat(String key, float value) {
floats.put(key, value);
}
/**
* Modifies or creates a new setting with the given key
*
* @param key key to identify the setting
* @param value value of the setting
*/
public void setInt(String key, int value) {
ints.put(key, value);
}
/**
* Modifies or creates a new setting with the given key
*
* @param key key to identify the setting
* @param value value of the setting
*/
public void setBoolean(String key, boolean value) {
booleans.put(key, value);
}
/**
* Modifies or creates a new setting with the given key
*
* @param key key to identify the setting
* @param value value of the setting
*/
public void setVector(String key, Vector3 value) {
vectors.put(key, new Vector3(value));
}
/**
* Modifies or creates a new setting with the given key
*
* @param key key to identify the setting
* @param value value of the setting
*/
public String getFile() {
return settingsFile;
}
/**
* Modifies or creates a new setting with the given key
*
* @param key key to identify the setting
* @param value value of the setting
*/
public void setFile(String settingsFile) {
this.settingsFile = settingsFile;
}
/**
* Reloads all the settings trying to use the external storage by default
*/
public void loadSettings() {
loadSettings(true);
}
/**
* Reloads all the settings
*
* @param tryExternal if true, it looks for an external settings file first (not in the app internal storage).
* Note that external files won't be taken into account in WebGL applications.
*/
public void loadSettings(boolean tryExternal) {
logger.info("Settings: loading file " + settingsFile);
try {
FileHandle fileHandle = null;
if (tryExternal &&
Gdx.app.getType() != Application.ApplicationType.WebGL &&
Gdx.files.external(settingsFile).exists()) {
fileHandle = Gdx.files.external(settingsFile);
logger.info("Settings: loading as external file");
}
else {
fileHandle = Gdx.files.internal(settingsFile);
logger.info("Settings: loading as internal file");
}
XmlReader reader = new XmlReader();
Element root = reader.parse(fileHandle);
// Load strings
strings.clear();
Array<Element> stringNodes = root.getChildrenByName("string");
for (int i = 0; i < stringNodes.size; ++i) {
Element stringNode = stringNodes.get(i);
String key = stringNode.getAttribute("key");
String value = stringNode.getAttribute("value");
strings.put(key, value);
logger.info("Settings: loaded string " + key + " = " + value);
}
// Load floats
floats.clear();
Array<Element> floatNodes = root.getChildrenByName("float");
for (int i = 0; i < floatNodes.size; ++i) {
Element floatNode = floatNodes.get(i);
String key = floatNode.getAttribute("key");
Float value = Float.parseFloat(floatNode.getAttribute("value"));
floats.put(key, value);
logger.info("Settings: loaded float " + key + " = " + value);
}
// Load ints
ints.clear();
Array<Element> intNodes = root.getChildrenByName("int");
for (int i = 0; i < intNodes.size; ++i) {
Element intNode = intNodes.get(i);
String key = intNode.getAttribute("key");
Integer value = Integer.parseInt(intNode.getAttribute("value"));
ints.put(key, value);
logger.info("Settings: loaded int " + key + " = " + value);
}
// Load booleans
booleans.clear();
Array<Element> boolNodes = root.getChildrenByName("bool");
for (int i = 0; i < boolNodes.size; ++i) {
Element boolNode = boolNodes.get(i);
String key = boolNode.getAttribute("key");
Boolean value = Boolean.parseBoolean(boolNode.getAttribute("value"));
booleans.put(key, value);
logger.info("Settings: loaded boolean " + key + " = " + value);
}
// Load vectors
vectors.clear();
Array<Element> vectorNodes = root.getChildrenByName("vector");
for (int i = 0; i < vectorNodes.size; ++i) {
Element vectorNode = vectorNodes.get(i);
String key = vectorNode.getAttribute("key");
Float x = Float.parseFloat(vectorNode.getAttribute("x"));
Float y = Float.parseFloat(vectorNode.getAttribute("y"));
Float z = Float.parseFloat(vectorNode.getAttribute("z"));
vectors.put(key, new Vector3(x, y, z));
logger.info("Settings: loaded vector " + key + " = (" + x + ", " + y + ", " + z + ")");
}
logger.info("Settings: successfully finished loading settings");
}
catch (Exception e) {
logger.error("Settings: error loading file: " + settingsFile + " " + e.getMessage());
}
}
/**
* Saves settings as an external file. If called from a WebGL application, nothing will be done.
*/
public void saveSettings() {
if (Gdx.app.getType() != Application.ApplicationType.WebGL) {
logger.info("Settings: saving file " + settingsFile);
XmlWriter xml;
try {
StringWriter writer = new StringWriter();
xml = new XmlWriter(writer);
// Create root
xml = xml.element("settings");
// Create string nodes
for (Entry<String, String> entry : strings.entrySet()) {
xml = xml.element("string");
xml.attribute("key", entry.getKey());
xml.attribute("value", entry.getValue());
xml = xml.pop();
}
// Create float nodes
for (Entry<String, Float> entry : floats.entrySet()) {
xml = xml.element("float");
xml.attribute("key", entry.getKey());
xml.attribute("value", entry.getValue());
xml = xml.pop();
}
// Create int nodes
for (Entry<String, Integer> entry : ints.entrySet()) {
xml = xml.element("int");
xml.attribute("key", entry.getKey());
xml.attribute("value", entry.getValue());
xml = xml.pop();
}
// Create boolean nodes
for (Entry<String, Boolean> entry : booleans.entrySet()) {
xml = xml.element("bool");
xml.attribute("key", entry.getKey());
xml.attribute("value", entry.getValue());
xml = xml.pop();
}
// Create vector nodes
for (Entry<String, Vector3> entry : vectors.entrySet()) {
xml = xml.element("vector");
xml.attribute("key", entry.getKey());
Vector3 vector = entry.getValue();
xml.attribute("x", vector.x);
xml.attribute("y", vector.y);
xml.attribute("z", vector.z);
xml = xml.pop();
}
xml = xml.pop();
Gdx.files.external(settingsFile).writeString(writer.toString(), true);
xml.close();
logger.info("Settings: successfully saved");
}
catch (Exception e) {
logger.error("Settings: error saving file " + settingsFile);
}
}
else {
logger.error("Settings: saving feature not supported in HTML5");
}
}
}