package io.gitlab.jfronny.libjf.config.impl.dsl; import io.gitlab.jfronny.commons.serialize.gson.api.GsonHolder; import io.gitlab.jfronny.commons.throwable.ThrowingConsumer; import io.gitlab.jfronny.commons.throwable.ThrowingSupplier; import io.gitlab.jfronny.gson.JsonElement; import io.gitlab.jfronny.gson.stream.JsonWriter; import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.libjf.config.api.v1.Entry; import io.gitlab.jfronny.libjf.config.api.v1.EntryInfo; import io.gitlab.jfronny.libjf.config.api.v1.type.Type; import io.gitlab.jfronny.libjf.config.impl.entrypoint.JfConfigSafe; import java.io.IOException; import java.lang.reflect.Field; import java.util.Arrays; import java.util.Objects; import java.util.stream.Collectors; public class DslEntryInfo implements EntryInfo { private final String name; private final T defaultValue; private final ThrowingSupplier get; private final ThrowingConsumer set; private final Type type; private final int width; private final double minValue; private final double maxValue; public DslEntryInfo(String name, T defaultValue, ThrowingSupplier get, ThrowingConsumer set, Type type, int width, double minValue, double maxValue) { this.name = name; this.defaultValue = defaultValue; this.get = get; this.set = set; this.type = type; this.width = width; this.minValue = minValue; this.maxValue = maxValue; } public DslEntryInfo(String name, T def, ThrowingSupplier get, ThrowingConsumer set, Type type) { this(name, def, get, set, type, 100, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); } public static DslEntryInfo ofField(Field field) { Entry entry = field.getAnnotation(Entry.class); Object defaultValue = null; try { defaultValue = field.get(null); } catch (IllegalAccessException ignored) { } //noinspection unchecked,rawtypes return new DslEntryInfo( field.getName(), defaultValue, () -> field.get(null), v -> field.set(null, v), (Type) Type.ofClass(field.getGenericType()), entry == null ? 100 : entry.width(), entry == null ? Double.NEGATIVE_INFINITY : entry.min(), entry == null ? Double.POSITIVE_INFINITY : entry.max() ); } @Override public String getName() { return name; } @Override public T getDefault() { return defaultValue; } @Override public T getValue() throws IllegalAccessException { return get.get(); } @Override public void setValue(T value) throws IllegalAccessException { set.accept(value); } @Override public Type getValueType() { return type; } @Override public void fix() { Object value; try { value = getValue(); } catch (IllegalAccessException e) { LibJf.LOGGER.error("Could not read value", e); return; } final Object valueOriginal = value; if (value instanceof final Integer v) { if (v < minValue) value = (int)minValue; if (v > maxValue) value = (int)maxValue; } else if (value instanceof final Float v) { if (v < minValue) value = (float)minValue; if (v > maxValue) value = (float)maxValue; } else if (value instanceof final Double v) { if (v < minValue) value = minValue; if (v > maxValue) value = maxValue; } if (valueOriginal != value) { try { setUnchecked(value); } catch (IllegalAccessException e) { LibJf.LOGGER.error("Could not write value", e); } } } @Override public void loadFromJson(JsonElement element) throws IllegalAccessException { if (type.isBool()) { if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isBoolean()) { setUnchecked(element.getAsBoolean()); } } else if (type.isString()) { if (element.isJsonPrimitive()) { setUnchecked(element.getAsString()); } } else if (type.isInt()) { if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isNumber()) { setUnchecked(element.getAsNumber().intValue()); } } else if (type.isLong()) { if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isNumber()) { setUnchecked(element.getAsNumber().longValue()); } } else if (type.isDouble()) { if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isNumber()) { setUnchecked(element.getAsNumber().doubleValue()); } } else if (type.isFloat()) { if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isNumber()) { setUnchecked(element.getAsNumber().floatValue()); } } else if (type.isEnum()) { Type.TEnum e = (Type.TEnum) type; if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) { setUnchecked(e.optionForString(element.getAsString())); } } else { setValue(GsonHolder.getGson().fromJson(element, type.asClass())); } } @SuppressWarnings("unchecked") private void setUnchecked(Object object) throws IllegalAccessException { if (object == null) return; setValue((T) object); } @Override public void writeTo(JsonWriter writer, String translationPrefix) throws IOException, IllegalAccessException { T value = getValue(); String val; if ((val = JfConfigSafe.TRANSLATION_SUPPLIER.apply(translationPrefix + getName() + ".tooltip")) != null) { writer.comment(val); } if (type.isEnum()) { writer.comment("Valid: [" + Arrays.stream(((Type.TEnum)type).options()).map(Objects::toString).collect(Collectors.joining(", ")) + "]"); } writer.name(name); GsonHolder.getGson().toJson(value, Objects.requireNonNullElse(type.asClass(), String.class), writer); } @Override public int getWidth() { return width; } @Override public double getMinValue() { return minValue; } @Override public double getMaxValue() { return maxValue; } }