// Copyright (c) 2015 Christopher "BlayTheNinth" Baker
package net.blay09.mods.eirairc.config.property;
import com.google.common.collect.Maps;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import net.blay09.mods.eirairc.api.config.IConfigManager;
import net.blay09.mods.eirairc.api.config.IConfigProperty;
import net.blay09.mods.eirairc.api.config.StringList;
import net.blay09.mods.eirairc.config.SharedGlobalConfig;
import net.blay09.mods.eirairc.util.I19n;
import net.blay09.mods.eirairc.util.IRCFormatting;
import net.minecraft.util.EnumChatFormatting;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Collection;
import java.util.Map;
public class ConfigManager implements IConfigManager {
private final Logger logger = LogManager.getLogger();
private final Map<String, ConfigProperty> properties = Maps.newHashMap();
private static Class colorGuiClass;
private ConfigManager parentManager;
private Configuration parentConfig;
public void setParentConfig(Configuration parentConfig) {
this.parentConfig = parentConfig;
}
public ConfigManager() {
if (colorGuiClass == null) {
try {
colorGuiClass = Class.forName("net.blay09.mods.eirairc.client.BetterColorEntry");
} catch (ClassNotFoundException ignored) {
}
}
}
@Override
@SuppressWarnings("unchecked")
public <T> IConfigProperty<T> getProperty(String modid, String name) {
return getProperty((modid == null || modid.equals("eirairc")) ? name : (modid + "_" + name));
}
@Override
public <T> IConfigProperty<T> registerProperty(String modid, String name, String langKey, T defaultValue) {
ConfigProperty<T> property = new ConfigProperty<>(this, SharedGlobalConfig.ADDONS, modid + "_" + name, langKey, defaultValue);
if (parentConfig != null) {
getProperty(parentConfig, property);
}
return property;
}
@SuppressWarnings("unchecked")
public void registerProperty(ConfigProperty property) {
properties.put(property.getName(), property);
if (parentManager != null) {
property.setParentProperty(parentManager.getProperty(property.getName()));
}
}
public void load(Configuration config) {
load(config, false);
}
@SuppressWarnings("unchecked")
public void load(Configuration config, boolean ignoreDefaultValues) {
for (ConfigProperty property : properties.values()) {
if (ignoreDefaultValues && !config.hasKey(property.getCategory(), property.getName())) {
continue;
}
Object type = property.getDefaultValue();
if (type.getClass() == String.class) {
String value = config.getString(property.getName(), property.getCategory(), (String) property.getDefaultValue(), I19n.format(property.getLangKey() + ".tooltip"), property.getLangKey());
if (!ignoreDefaultValues || !value.equals(property.getDefaultValue())) {
property.set(value);
}
} else if (type.getClass() == Boolean.class) {
boolean value = config.getBoolean(property.getName(), property.getCategory(), (Boolean) property.getDefaultValue(), I19n.format(property.getLangKey() + ".tooltip"), property.getLangKey());
if (!ignoreDefaultValues || value != (Boolean) property.getDefaultValue()) {
property.set(value);
}
} else if (type.getClass() == Integer.class) {
int value = config.getInt(property.getName(), property.getCategory(), (Integer) property.getDefaultValue(), Integer.MIN_VALUE, Integer.MAX_VALUE, I19n.format(property.getLangKey() + ".tooltip"), property.getLangKey());
if (!ignoreDefaultValues || value != (Integer) property.getDefaultValue()) {
property.set(value);
}
} else if (type.getClass() == Float.class) {
float value = config.getFloat(property.getName(), property.getCategory(), (Float) property.getDefaultValue(), Float.MIN_VALUE, Float.MAX_VALUE, I19n.format(property.getLangKey() + ".tooltip"), property.getLangKey());
if (!ignoreDefaultValues || value != (Float) property.getDefaultValue()) {
property.set(value);
}
} else if (type.getClass() == StringList.class) {
String[] value = config.getStringList(property.getName(), property.getCategory(), ((StringList) property.getDefaultValue()).getAsArray(), I19n.format(property.getLangKey() + ".tooltip"), null, property.getLangKey());
if (value.length > 0) {
property.set(new StringList(value));
}
} else if (type.getClass() == EnumChatFormatting.class) {
String stringValue = config.getString(property.getName(), property.getCategory(), IRCFormatting.getNameFromColor((EnumChatFormatting) property.getDefaultValue()), I19n.format(property.getLangKey() + ".tooltip"), IRCFormatting.mcColorNames, property.getLangKey());
if (stringValue.isEmpty()) {
continue;
}
EnumChatFormatting color = IRCFormatting.getColorFromName(stringValue);
if (color != null) {
if (!ignoreDefaultValues || !color.equals(property.getDefaultValue())) {
property.set(color);
}
} else {
StringBuilder validValues = new StringBuilder();
for (String colorName : IRCFormatting.mcColorNames) {
if (validValues.length() > 0) {
validValues.append(", ");
}
validValues.append(colorName);
}
logger.error("Invalid config value {} for option {} - valid values are: {}", stringValue.toLowerCase(), property.getName(), validValues.toString());
}
} else if (type instanceof Enum) {
Enum[] enums = ((Enum) type).getClass().getEnumConstants();
String[] validValues = new String[enums.length];
for (int i = 0; i < validValues.length; i++) {
validValues[i] = enums[i].name().toLowerCase();
}
String stringValue = config.getString(property.getName(), property.getCategory(), ((Enum) property.getDefaultValue()).name(), I19n.format("eirairc:config.property." + property.getName() + ".tooltip"), validValues, "eirairc:config.property." + property.getName());
if (stringValue.isEmpty()) {
continue;
}
try {
Enum value = Enum.valueOf((Class<? extends Enum>) type.getClass(), stringValue.toUpperCase());
if (!ignoreDefaultValues || !value.equals(property.getDefaultValue())) {
property.set(value);
}
} catch (IllegalArgumentException e) {
logger.error("Invalid config value {} for option {} - valid values are: {}", stringValue.toLowerCase(), property.getName(), StringUtils.join(validValues, ", ", 0, validValues.length)); // StringUtils.join(Serializable...) is a horrible thing to do, Apache
}
}
}
}
public void save(Configuration config) {
for (ConfigProperty property : properties.values()) {
Object value = property.get();
if (value.getClass() == String.class) {
getProperty(config, property).set((String) value);
} else if (value.getClass() == Boolean.class) {
getProperty(config, property).set((Boolean) value);
} else if (value.getClass() == Integer.class) {
getProperty(config, property).set((Integer) value);
} else if (value.getClass() == Float.class) {
getProperty(config, property).set((Float) value);
} else if (value.getClass() == StringList.class) {
getProperty(config, property).set(((StringList) value).getAsArray());
} else if (value.getClass() == EnumChatFormatting.class) {
getProperty(config, property).set(IRCFormatting.getNameFromColor((EnumChatFormatting) value));
} else if (value instanceof Enum) {
Enum[] enums = ((Enum) value).getClass().getEnumConstants();
String[] validValues = new String[enums.length];
for (int i = 0; i < validValues.length; i++) {
validValues[i] = enums[i].name().toLowerCase();
}
getProperty(config, property).set(((Enum) value).name());
}
}
}
public Property getProperty(Configuration config, ConfigProperty property) {
Object value = property.get();
if (value.getClass() == String.class) {
return config.get(property.getCategory(), property.getName(), (String) property.getDefaultValue(), I19n.format(property.getLangKey() + ".tooltip"));
} else if (value.getClass() == Boolean.class) {
return config.get(property.getCategory(), property.getName(), (Boolean) property.getDefaultValue(), I19n.format(property.getLangKey() + ".tooltip"));
} else if (value.getClass() == Integer.class) {
return config.get(property.getCategory(), property.getName(), (Integer) property.getDefaultValue(), I19n.format(property.getLangKey() + ".tooltip"));
} else if (value.getClass() == Float.class) {
return config.get(property.getCategory(), property.getName(), (Float) property.getDefaultValue(), I19n.format(property.getLangKey() + ".tooltip"));
} else if (value.getClass() == StringList.class) {
return config.get(property.getCategory(), property.getName(), ((StringList) property.getDefaultValue()).getAsArray(), I19n.format(property.getLangKey() + ".tooltip"));
} else if (value.getClass() == EnumChatFormatting.class) {
Property prop = config.get(property.getCategory(), property.getName(), IRCFormatting.getNameFromColor((EnumChatFormatting) property.getDefaultValue()), I19n.format(property.getLangKey() + ".tooltip"), IRCFormatting.mcColorNames);
prop.setConfigEntryClass(colorGuiClass);
return prop;
} else if (value instanceof Enum) {
Enum[] enums = ((Enum) value).getClass().getEnumConstants();
String[] validValues = new String[enums.length];
for (int i = 0; i < validValues.length; i++) {
validValues[i] = enums[i].name().toLowerCase();
}
return config.get(property.getCategory(), property.getName(), ((Enum) property.getDefaultValue()).name(), I19n.format(property.getLangKey() + ".tooltip"), validValues);
}
return null;
}
public Collection<ConfigProperty> getProperties() {
return properties.values();
}
public ConfigProperty getProperty(String name) {
return properties.get(name);
}
public String getAsString(String name) {
ConfigProperty property = getProperty(name);
if (property == null) {
return null;
}
return String.valueOf(property.get());
}
@SuppressWarnings("unchecked")
public boolean setFromString(String name, String value) {
ConfigProperty property = getProperty(name);
if (property == null) {
return false;
}
Object type = property.getDefaultValue();
if (type.getClass() == String.class) {
property.set(value);
} else if (type.getClass() == Boolean.class) {
property.set(Boolean.parseBoolean(value));
} else if (type.getClass() == Integer.class) {
property.set(Integer.parseInt(value));
} else if (type.getClass() == Float.class) {
property.set(Float.parseFloat(value));
} else if (type.getClass() == StringList.class) {
StringList list = new StringList(((StringList) property.get()).getAsArray());
if (value.startsWith("add ")) {
list.add(value.substring(4));
} else if (value.startsWith("remove ")) {
list.remove(value.substring(7));
}
property.set(list);
} else if (type.getClass() == EnumChatFormatting.class) {
EnumChatFormatting color = IRCFormatting.getColorFromName(value);
if (color != null) {
property.set(color);
} else {
// TODO print error message
}
} else if (type instanceof Enum) {
try {
property.set(Enum.valueOf((Class<? extends Enum>) type.getClass(), value));
} catch (IllegalArgumentException e) {
// TODO print error message
}
}
return true;
}
@SuppressWarnings("unchecked")
public void setParentManager(ConfigManager manager) {
this.parentManager = manager;
for (ConfigProperty property : properties.values()) {
property.setParentProperty(manager.getProperty(property.getName()));
}
}
public void resetProperties() {
for (ConfigProperty property : properties.values()) {
property.reset();
}
}
public Configuration pullDummyConfig() {
Configuration dummyConfig = new Configuration();
for (ConfigProperty property : properties.values()) {
Object type = property.getDefaultValue();
Property dummyProperty;
if (type.getClass() == String.class) {
dummyProperty = dummyConfig.get(property.getCategory(), property.getName(), (String) property.getDefaultValue(), I19n.format(property.getLangKey() + ".tooltip"));
} else if (type.getClass() == Boolean.class) {
dummyProperty = dummyConfig.get(property.getCategory(), property.getName(), (Boolean) property.getDefaultValue(), I19n.format(property.getLangKey() + ".tooltip"));
} else if (type.getClass() == Integer.class) {
dummyProperty = dummyConfig.get(property.getCategory(), property.getName(), (Integer) property.getDefaultValue(), I19n.format(property.getLangKey() + ".tooltip"));
} else if (type.getClass() == Float.class) {
dummyProperty = dummyConfig.get(property.getCategory(), property.getName(), (Float) property.getDefaultValue(), I19n.format(property.getLangKey() + ".tooltip"));
} else if (type.getClass() == StringList.class) {
dummyProperty = dummyConfig.get(property.getCategory(), property.getName(), ((StringList) property.getDefaultValue()).getAsArray(), I19n.format(property.getLangKey() + ".tooltip"));
} else if (type.getClass() == EnumChatFormatting.class) {
dummyProperty = dummyConfig.get(property.getCategory(), property.getName(), IRCFormatting.getNameFromColor((EnumChatFormatting) property.getDefaultValue()), I19n.format(property.getLangKey() + ".tooltip"));
} else if (type instanceof Enum) {
dummyProperty = dummyConfig.get(property.getCategory(), property.getName(), ((Enum) property.getDefaultValue()).name(), I19n.format(property.getLangKey() + ".tooltip"));
} else {
continue;
}
dummyProperty.setLanguageKey(property.getLangKey());
if (property.hasValue()) {
if (type.getClass() == String.class) {
dummyProperty.set((String) property.get());
} else if (type.getClass() == Boolean.class) {
dummyProperty.set((Boolean) property.get());
} else if (type.getClass() == Integer.class) {
dummyProperty.set((Integer) property.get());
} else if (type.getClass() == Float.class) {
dummyProperty.set((Float) property.get());
} else if (type.getClass() == StringList.class) {
dummyProperty.set(((StringList) property.get()).getAsArray());
} else if (type.getClass() == EnumChatFormatting.class) {
dummyProperty.setConfigEntryClass(colorGuiClass);
dummyProperty.set(IRCFormatting.getNameFromColor((EnumChatFormatting) property.get()));
} else if (type.getClass() == Enum.class) {
dummyProperty.set(((Enum) property.get()).name());
}
}
}
return dummyConfig;
}
@SuppressWarnings("unchecked")
public void load(JsonObject object) {
for (ConfigProperty property : properties.values()) {
if (!object.has(property.getName())) {
continue;
}
Object type = property.getDefaultValue();
if (type.getClass() == String.class) {
property.set(object.get(property.getName()).getAsString());
} else if (type.getClass() == Boolean.class) {
property.set(object.get(property.getName()).getAsBoolean());
} else if (type.getClass() == Integer.class) {
property.set(object.get(property.getName()).getAsInt());
} else if (type.getClass() == Float.class) {
property.set(object.get(property.getName()).getAsFloat());
} else if (type.getClass() == StringList.class) {
StringList stringList = new StringList();
JsonArray stringArray = object.get(property.getName()).getAsJsonArray();
for (int i = 0; i < stringArray.size(); i++) {
stringList.add(stringArray.get(i).getAsString());
}
property.set(stringList);
} else if (type.getClass() == EnumChatFormatting.class) {
String stringValue = object.get(property.getName()).getAsString();
if (stringValue.isEmpty()) {
continue;
}
EnumChatFormatting color = IRCFormatting.getColorFromName(stringValue);
if (color != null) {
property.set(color);
} else {
StringBuilder validValues = new StringBuilder();
for (String colorName : IRCFormatting.mcColorNames) {
if (validValues.length() > 0) {
validValues.append(", ");
}
validValues.append(colorName);
}
logger.error("Invalid config value {} for option {} - valid values are: {}", stringValue.toLowerCase(), property.getName(), validValues.toString());
}
} else if (type instanceof Enum) {
String stringValue = object.get(property.getName()).getAsString();
if (stringValue.isEmpty()) {
continue;
}
try {
Enum value = Enum.valueOf((Class<? extends Enum>) type.getClass(), stringValue.toUpperCase());
property.set(value);
} catch (IllegalArgumentException e) {
StringBuilder validValues = new StringBuilder();
for (Enum enumValue : ((Enum) type).getClass().getEnumConstants()) {
if (validValues.length() > 0) {
validValues.append(", ");
}
validValues.append(enumValue.name().toLowerCase());
}
logger.error("Invalid config value {} for option {} - valid values are: {}", stringValue.toLowerCase(), property.getName(), validValues.toString());
}
}
}
}
@SuppressWarnings("unchecked")
public void save(JsonObject object) {
for (ConfigProperty property : properties.values()) {
if (!property.hasValue()) {
continue;
}
Object type = property.getDefaultValue();
if (type.getClass() == String.class) {
object.addProperty(property.getName(), (String) property.get());
} else if (type.getClass() == Boolean.class) {
object.addProperty(property.getName(), (Boolean) property.get());
} else if (type.getClass() == Integer.class) {
object.addProperty(property.getName(), (Integer) property.get());
} else if (type.getClass() == Float.class) {
object.addProperty(property.getName(), (Float) property.get());
} else if (type.getClass() == StringList.class) {
JsonArray stringArray = new JsonArray();
for (String s : (StringList) property.get()) {
stringArray.add(new JsonPrimitive(s));
}
object.add(property.getName(), stringArray);
} else if (type instanceof Enum) {
object.addProperty(property.getName(), ((Enum) property.get()).name());
}
}
}
public void updateProperty(ConfigProperty property) {
if (parentConfig != null) {
Property prop = getProperty(parentConfig, property);
if (property.getValidValues() != null) {
prop.setValidValues(property.getValidValues());
}
if (property.getMin() != null && property.getMax() != null) {
if (property.getDefaultValue().getClass() == Integer.class) {
prop.setMinValue((int) property.getMin());
prop.setMaxValue((int) property.getMax());
} else if (property.getDefaultValue().getClass() == Float.class) {
prop.setMinValue((float) property.getMin());
prop.setMaxValue((float) property.getMax());
}
}
}
}
}