/*
* The MIT License (MIT)
*
* Copyright (c) 2014 Cayde Dixon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.cazzar.corelib.configuration;
import net.cazzar.corelib.configuration.annotations.ConfigurationClass;
import net.cazzar.corelib.configuration.annotations.ConfigurationComment;
import net.cazzar.corelib.configuration.annotations.ConfigurationOption;
import net.cazzar.corelib.lib.LogHelper;
import net.minecraftforge.common.config.Configuration;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
@SuppressWarnings("UnusedDeclaration")
public class Config {
static Marker marker = MarkerManager.getMarker("ConfigManager");
public final Configuration config;
public Object clazz;
public Config(Configuration config) {
this.config = config;
}
public Config(File configFile) {
this(new Configuration(configFile));
}
static boolean isParseable(@NotNull Class<?> type) {
if (type.isPrimitive() || type == String.class || type == Boolean.class || type == Double.class || type == Integer.class || type == Float.class)
return true;
if (type.isArray()) {
Class<?> type1 = type.getComponentType();
if (type1.isPrimitive() || type1 == String.class || type1 == Boolean.class || type1 == Double.class || type1 == Integer.class || type1 == Float.class)
return true;
}
return false;
}
public Config setInstance(Object clazz) {
this.clazz = clazz;
return this;
}
public void build() throws IllegalAccessException {
parseFieldsInClass(clazz);
}
private void parseFieldsInClass(@NotNull Object o) throws IllegalAccessException {
LogHelper.coreLog.info(marker, "Parsing Object {}", o);
for (Field field : o.getClass().getDeclaredFields()) {
field.setAccessible(true);
LogHelper.coreLog.debug(marker, "Parsing field {}.{} of type {}", field.getDeclaringClass().getName(), field.getName(), field.getType());
if (field.getAnnotation(Config.Exclude.class) != null) {
LogHelper.coreLog.debug(marker, "Skipping...");
continue;
}
if (isParseable(field.getType())) parseField(field, o);
else if (!field.isSynthetic()) parseFieldsInClass(field.get(o));
}
}
public void parseField(@NotNull Field field, @NotNull Object instance) throws IllegalAccessException {
ConfigurationComment configComment = field.getAnnotation(ConfigurationComment.class);
String comment = "", category, key;
if (configComment != null) comment = configComment.value();
ConfigurationOption configurationOption = field.getAnnotation(ConfigurationOption.class);
if (configurationOption != null) {
category = configurationOption.category();
key = configurationOption.key();
if (key.isEmpty()) key = field.getName();
if (comment.isEmpty() && (configurationOption.comment() != null || !configurationOption.comment().isEmpty()))
comment = configurationOption.comment();
} else {
key = field.getName();
category = field.getDeclaringClass().getSimpleName();
}
parseField(field, instance, category, key, comment);
}
/**
* Parse the passed class for annotated fields with the <i>@ConfigurationOption</i> or a class with
* <i>@ConfigurationClass</i>
*
* @param instance the instance of the configurations option if it is non static
*/
private void parse(@NotNull Object instance) {
Class clazz = instance.getClass();
if (clazz.isAnnotationPresent(ConfigurationClass.class)) {
parseClass(instance, config);
return;
}
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (!field.isAccessible()) field.setAccessible(true);
ConfigurationOption annotation = field.getAnnotation(ConfigurationOption.class);
if (annotation == null) {
continue;
}
String category = annotation.category();
String comment = annotation.comment();
String key = annotation.key();
try {
parseField(field, instance, category, key, comment);
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
if (config.hasChanged()) {
config.save();
}
}
}
private void parseField(@NotNull Field field, @NotNull Object instance, @NotNull String category, @NotNull String key, @Nullable String comment) throws IllegalArgumentException, IllegalAccessException {
Class<?> type = field.getType();
//null check or if it is empty
if (comment == null || comment.isEmpty()) comment = null;
if (type == boolean.class || type == Boolean.class) {
//boolean or Boolean
Object def = field.get(instance);
Object value = config.get(category, key, (Boolean) def, comment).getBoolean((Boolean) def);
field.set(instance, value);
} else if (type.isArray() && (type.getComponentType() == boolean.class)) {
//boolean[]
boolean[] def = ((boolean[]) field.get(instance));
boolean[] value = config.get(category, key, def, comment).getBooleanList();
field.set(instance, value);
} else if (type == double.class || type == Double.class) {
//Double or double
Object def = field.get(instance);
Object value = config.get(category, key, (Double) def, comment).getDouble((Double) def);
field.set(instance, value);
} else if (type.isArray() && type.getComponentType() == double.class) {
//double[]
double[] def = ((double[]) field.get(instance));
double[] value = config.get(category, key, def, comment).getDoubleList();
field.set(instance, value);
} else if (type == String.class) {
//String
Object def = field.get(instance);
Object value = config.get(category, key, (String) def, comment).getString();
field.set(instance, value);
} else if (type.isArray() && type.getComponentType() == String.class) {
//String[]
String[] def = ((String[]) field.get(instance));
String[] value = config.get(category, key, def, comment).getStringList();
field.set(instance, value);
} else if (type == Integer.class || type == int.class) {
//Integer and int
Object def = field.get(instance);
Object value = config.get(category, key, (Integer) def, comment).getInt((Integer) def);
field.set(instance, value);
} else if (type.isArray() && type.getComponentType() == int.class) {
//int[]
int[] def = ((int[]) field.get(instance));
int[] value = config.get(category, key, def, comment).getIntList();
field.set(instance, value);
} else if (type == float.class || type == Float.class) {
//float and Float
Object def = field.get(instance);
String value = config.get(category, key, String.valueOf(def), comment).getString();
Float actual = Float.valueOf(value);
field.set(instance, actual);
} else if (type.isArray() && type.getComponentType() == float.class) {
//float[]
float[] def = ((float[]) field.get(instance));
String[] stringDef = new String[def.length];
for (int i = 0; i < def.length; i++) stringDef[i] = String.valueOf(def[i]);
String[] value = config.get(category, key, stringDef, comment).getStringList();
float[] actual = new float[value.length];
for (int i = 0; i < value.length; i++) {
actual[i] = Float.valueOf(value[i]);
}
field.set(instance, actual);
}
}
private void parseClass(@NotNull Object instance, @NotNull Configuration config) {
Class<?> clazz = instance.getClass();
@Nullable ConfigurationClass annotation = clazz.getAnnotation(ConfigurationClass.class);
if (annotation == null) {
return;
}
String category = (annotation.category().isEmpty()) ? clazz.getSimpleName() : annotation.category();
if (clazz.isAnnotationPresent(ConfigurationComment.class)) {
config.getCategory(category).setComment(clazz.getAnnotation(ConfigurationComment.class).value());
}
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (!field.isAccessible()) field.setAccessible(true);
ConfigurationComment commentAnnotation = field.getAnnotation(ConfigurationComment.class);
String comment = (commentAnnotation == null) ? "" : commentAnnotation.value();
String key = field.getName();
try {
parseField(field, instance, category, key, comment);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if (config.hasChanged()) {
config.save();
}
}
}
@Retention(RetentionPolicy.RUNTIME)
public static @interface Exclude {
}
}