You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
446 lines
9.1 KiB
446 lines
9.1 KiB
package mightypork.utils.config;
|
|
|
|
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.Map.Entry;
|
|
import java.util.TreeMap;
|
|
|
|
import mightypork.utils.math.Range;
|
|
import mightypork.utils.math.coord.Coord;
|
|
import mightypork.utils.objects.Convert;
|
|
|
|
|
|
/**
|
|
* Property manager with advanced formatting and value checking.<br>
|
|
* Methods starting with put are for filling. Most of the others are shortcuts
|
|
* to getters.
|
|
*
|
|
* @author MightyPork
|
|
*/
|
|
public class PropertyManager {
|
|
|
|
private abstract class Property<T> {
|
|
|
|
public String comment;
|
|
public String key;
|
|
|
|
public T value;
|
|
public T defaultValue;
|
|
|
|
|
|
public Property(String key, T defaultValue, String comment) {
|
|
super();
|
|
this.comment = comment;
|
|
this.key = key;
|
|
this.defaultValue = defaultValue;
|
|
this.value = defaultValue;
|
|
}
|
|
|
|
|
|
public abstract void parse(String string);
|
|
|
|
|
|
@Override
|
|
public String toString()
|
|
{
|
|
return Convert.toString(value);
|
|
}
|
|
}
|
|
|
|
private class BooleanProperty extends Property<Boolean> {
|
|
|
|
public BooleanProperty(String key, Boolean defaultValue, String comment) {
|
|
super(key, defaultValue, comment);
|
|
}
|
|
|
|
|
|
@Override
|
|
public void parse(String string)
|
|
{
|
|
value = Convert.toBoolean(string, defaultValue);
|
|
}
|
|
}
|
|
|
|
private class IntegerProperty extends Property<Integer> {
|
|
|
|
public IntegerProperty(String key, Integer defaultValue, String comment) {
|
|
super(key, defaultValue, comment);
|
|
}
|
|
|
|
|
|
@Override
|
|
public void parse(String string)
|
|
{
|
|
value = Convert.toInteger(string, defaultValue);
|
|
}
|
|
}
|
|
|
|
private class DoubleProperty extends Property<Double> {
|
|
|
|
public DoubleProperty(String key, Double defaultValue, String comment) {
|
|
super(key, defaultValue, comment);
|
|
}
|
|
|
|
|
|
@Override
|
|
public void parse(String string)
|
|
{
|
|
value = Convert.toDouble(string, defaultValue);
|
|
}
|
|
}
|
|
|
|
private class StringProperty extends Property<String> {
|
|
|
|
public StringProperty(String key, String defaultValue, String comment) {
|
|
super(key, defaultValue, comment);
|
|
}
|
|
|
|
|
|
@Override
|
|
public void parse(String string)
|
|
{
|
|
value = Convert.toString(string, defaultValue);
|
|
}
|
|
}
|
|
|
|
private class RangeProperty extends Property<Range> {
|
|
|
|
public RangeProperty(String key, Range defaultValue, String comment) {
|
|
super(key, defaultValue, comment);
|
|
}
|
|
|
|
|
|
@Override
|
|
public void parse(String string)
|
|
{
|
|
value = Convert.toRange(string, defaultValue);
|
|
}
|
|
}
|
|
|
|
private class CoordProperty extends Property<Coord> {
|
|
|
|
public CoordProperty(String key, Coord defaultValue, String comment) {
|
|
super(key, defaultValue, comment);
|
|
}
|
|
|
|
|
|
@Override
|
|
public void parse(String string)
|
|
{
|
|
value = Convert.toCoord(string, defaultValue);
|
|
}
|
|
}
|
|
|
|
/** put newline before entry comments */
|
|
private boolean cfgNewlineBeforeComments = true;
|
|
/** Put newline between sections. */
|
|
private boolean cfgSeparateSections = true;
|
|
/** Force save, even if nothing changed (used to save changed comments) */
|
|
private boolean cfgForceSave;
|
|
|
|
private final File file;
|
|
private String fileComment = "";
|
|
|
|
private final TreeMap<String, Property<?>> entries;
|
|
private final TreeMap<String, String> renameTable;
|
|
private final TreeMap<String, String> overrideValues;
|
|
private SortedProperties props = new SortedProperties();
|
|
|
|
|
|
/**
|
|
* Create property manager from file path and an initial comment.
|
|
*
|
|
* @param file file with the props
|
|
* @param comment the initial comment. Use \n in it if you want.
|
|
*/
|
|
public PropertyManager(File file, String comment) {
|
|
this.file = file;
|
|
this.entries = new TreeMap<>();
|
|
this.overrideValues = new TreeMap<>();
|
|
this.renameTable = new TreeMap<>();
|
|
this.fileComment = comment;
|
|
}
|
|
|
|
|
|
/**
|
|
* Load, fix and write to file.
|
|
*/
|
|
public void apply()
|
|
{
|
|
boolean needsSave = false;
|
|
new File(file.getParent()).mkdirs();
|
|
|
|
try (FileInputStream fis = new FileInputStream(file)) {
|
|
props.load(fis);
|
|
} catch (final IOException e) {
|
|
needsSave = true;
|
|
props = new SortedProperties();
|
|
}
|
|
|
|
props.cfgBlankRowBetweenSections = cfgSeparateSections;
|
|
props.cfgBlankRowBeforeComment = cfgNewlineBeforeComments;
|
|
|
|
final ArrayList<String> keyList = new ArrayList<>();
|
|
|
|
// rename keys
|
|
for (final Entry<String, String> entry : renameTable.entrySet()) {
|
|
if (props.getProperty(entry.getKey()) == null) {
|
|
continue;
|
|
}
|
|
props.setProperty(entry.getValue(), props.getProperty(entry.getKey()));
|
|
props.remove(entry.getKey());
|
|
needsSave = true;
|
|
}
|
|
|
|
// set the override values into the freshly loaded properties file
|
|
for (final Entry<String, String> entry : overrideValues.entrySet()) {
|
|
props.setProperty(entry.getKey(), entry.getValue());
|
|
needsSave = true;
|
|
}
|
|
|
|
// validate entries one by one, replace with default when needed
|
|
for (final Property<?> entry : entries.values()) {
|
|
keyList.add(entry.key);
|
|
|
|
final String propOrig = props.getProperty(entry.key);
|
|
|
|
entry.parse(propOrig);
|
|
|
|
if (!entry.toString().equals(propOrig)) {
|
|
needsSave = true;
|
|
}
|
|
|
|
if (entry.comment != null) {
|
|
props.setKeyComment(entry.key, entry.comment);
|
|
}
|
|
|
|
if (propOrig == null || !entry.toString().equals(propOrig)) {
|
|
props.setProperty(entry.key, entry.toString());
|
|
|
|
needsSave = true;
|
|
}
|
|
}
|
|
|
|
// removed unused props
|
|
for (final String propname : props.keySet().toArray(new String[props.size()])) {
|
|
if (!keyList.contains(propname)) {
|
|
props.remove(propname);
|
|
needsSave = true;
|
|
}
|
|
|
|
}
|
|
|
|
// save if needed
|
|
if (needsSave || cfgForceSave) {
|
|
try {
|
|
props.store(new FileOutputStream(file), fileComment);
|
|
} catch (final IOException ioe) {
|
|
ioe.printStackTrace();
|
|
}
|
|
}
|
|
|
|
overrideValues.clear();
|
|
renameTable.clear();
|
|
}
|
|
|
|
|
|
/**
|
|
* @param newlineBeforeComments put newline before comments
|
|
*/
|
|
public void cfgNewlineBeforeComments(boolean newlineBeforeComments)
|
|
{
|
|
this.cfgNewlineBeforeComments = newlineBeforeComments;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param separateSections do separate sections by newline
|
|
*/
|
|
public void cfgSeparateSections(boolean separateSections)
|
|
{
|
|
this.cfgSeparateSections = separateSections;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param forceSave save even if unchanged.
|
|
*/
|
|
public void cfgForceSave(boolean forceSave)
|
|
{
|
|
this.cfgForceSave = forceSave;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get a property entry (rarely used)
|
|
*
|
|
* @param n key
|
|
* @return the entry
|
|
*/
|
|
private Property<?> get(String n)
|
|
{
|
|
try {
|
|
return entries.get(n);
|
|
} catch (final Throwable t) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Get boolean property
|
|
*
|
|
* @param n key
|
|
* @return the boolean found, or false
|
|
*/
|
|
public Boolean getBoolean(String n)
|
|
{
|
|
return Convert.toBoolean(get(n).value);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get numeric property
|
|
*
|
|
* @param n key
|
|
* @return the int found, or null
|
|
*/
|
|
public Integer getInteger(String n)
|
|
{
|
|
return Convert.toInteger(get(n).value);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get numeric property as double
|
|
*
|
|
* @param n key
|
|
* @return the double found, or null
|
|
*/
|
|
public Double getDouble(String n)
|
|
{
|
|
return Convert.toDouble(get(n).value);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get string property
|
|
*
|
|
* @param n key
|
|
* @return the string found, or null
|
|
*/
|
|
public String getString(String n)
|
|
{
|
|
return Convert.toString(get(n).value);
|
|
}
|
|
|
|
|
|
/**
|
|
* Add a boolean property
|
|
*
|
|
* @param n key
|
|
* @param d default value
|
|
* @param comment the in-file comment
|
|
*/
|
|
public void putBoolean(String n, boolean d, String comment)
|
|
{
|
|
entries.put(n, new BooleanProperty(n, d, comment));
|
|
}
|
|
|
|
|
|
/**
|
|
* Add a numeric property (double)
|
|
*
|
|
* @param n key
|
|
* @param d default value
|
|
* @param comment the in-file comment
|
|
*/
|
|
public void putDouble(String n, double d, String comment)
|
|
{
|
|
entries.put(n, new DoubleProperty(n, d, comment));
|
|
}
|
|
|
|
|
|
/**
|
|
* Add a numeric property
|
|
*
|
|
* @param n key
|
|
* @param d default value
|
|
* @param comment the in-file comment
|
|
*/
|
|
public void putInteger(String n, int d, String comment)
|
|
{
|
|
entries.put(n, new IntegerProperty(n, d, comment));
|
|
}
|
|
|
|
|
|
/**
|
|
* Add a string property
|
|
*
|
|
* @param n key
|
|
* @param d default value
|
|
* @param comment the in-file comment
|
|
*/
|
|
public void putString(String n, String d, String comment)
|
|
{
|
|
entries.put(n, new StringProperty(n, d, comment));
|
|
}
|
|
|
|
|
|
/**
|
|
* Add a coord property
|
|
*
|
|
* @param n key
|
|
* @param d default value
|
|
* @param comment the in-file comment
|
|
*/
|
|
public void putCoord(String n, Coord d, String comment)
|
|
{
|
|
entries.put(n, new CoordProperty(n, d, comment));
|
|
}
|
|
|
|
|
|
/**
|
|
* Add a range property
|
|
*
|
|
* @param n key
|
|
* @param d default value
|
|
* @param comment the in-file comment
|
|
*/
|
|
public void putRange(String n, Range d, String comment)
|
|
{
|
|
entries.put(n, new RangeProperty(n, d, comment));
|
|
}
|
|
|
|
|
|
/**
|
|
* Rename key before doing "apply"; value is preserved
|
|
*
|
|
* @param oldKey old key
|
|
* @param newKey new key
|
|
*/
|
|
public void renameKey(String oldKey, String newKey)
|
|
{
|
|
renameTable.put(oldKey, newKey);
|
|
return;
|
|
}
|
|
|
|
|
|
/**
|
|
* Set value saved to certain key; use to save runtime-changed configuration
|
|
* values.
|
|
*
|
|
* @param key key
|
|
* @param value the saved value
|
|
*/
|
|
public void setValue(String key, Object value)
|
|
{
|
|
overrideValues.put(key, value.toString());
|
|
return;
|
|
}
|
|
|
|
}
|
|
|