232 lines
8.6 KiB
Java
232 lines
8.6 KiB
Java
package io.gitlab.jfronny.libjf.config.impl.dsl;
|
|
|
|
import io.gitlab.jfronny.commons.serialize.SerializeReader;
|
|
import io.gitlab.jfronny.commons.throwable.Coerce;
|
|
import io.gitlab.jfronny.libjf.LibJf;
|
|
import io.gitlab.jfronny.libjf.config.api.v2.*;
|
|
import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder;
|
|
import io.gitlab.jfronny.libjf.config.api.v2.dsl.Migration;
|
|
import io.gitlab.jfronny.libjf.config.api.v2.type.Type;
|
|
|
|
import java.util.*;
|
|
import java.util.function.Consumer;
|
|
import java.util.function.Supplier;
|
|
|
|
public class CategoryBuilderImpl<Builder extends CategoryBuilderImpl<Builder>> implements CategoryBuilder<Builder> {
|
|
public final List<CategoryBuilder<?>> categories = new LinkedList<>();
|
|
public final String id;
|
|
public final String categoryPath;
|
|
public String translationPrefix;
|
|
public final List<EntryInfo<?>> entries = new LinkedList<>();
|
|
public final Map<String, Consumer<ConfigCategory>> presets = new LinkedHashMap<>();
|
|
public final List<Supplier<List<ConfigInstance>>> referencedConfigs = new LinkedList<>();
|
|
public final List<Consumer<ConfigCategory>> verifiers = new LinkedList<>();
|
|
@SuppressWarnings("rawtypes") // recursive types aren't really needed here
|
|
public final Map<String, Consumer<SerializeReader>> migrations = new LinkedHashMap<>();
|
|
private boolean built = false;
|
|
|
|
public CategoryBuilderImpl(String id, String categoryPath) {
|
|
this.id = id;
|
|
this.categoryPath = categoryPath;
|
|
this.translationPrefix = id + ".jfconfig." + categoryPath;
|
|
addPreset(CONFIG_PRESET_DEFAULT, ConfigCategory::reset);
|
|
}
|
|
|
|
@Override
|
|
public Builder setTranslationPrefix(String translationPrefix) {
|
|
checkBuilt();
|
|
this.translationPrefix = translationPrefix;
|
|
return asBuilder();
|
|
}
|
|
|
|
@Override
|
|
public String getTranslationPrefix() {
|
|
checkBuilt();
|
|
return translationPrefix;
|
|
}
|
|
|
|
@Override
|
|
public Builder addPreset(String id, Consumer<ConfigCategory> action) {
|
|
checkBuilt();
|
|
if (presets.containsKey(id)) LibJf.LOGGER.warn("Duplicate preset registered for " + categoryPath + this.id + ": " + id + ", overriding");
|
|
presets.put(id, action);
|
|
return asBuilder();
|
|
}
|
|
|
|
@Override
|
|
public Builder addPreset(String id, Runnable preset) {
|
|
return addPreset(id, cfg -> preset.run());
|
|
}
|
|
|
|
@Override
|
|
public Builder removePreset(String id) {
|
|
checkBuilt();
|
|
if (presets.remove(id) == null) throw new NoSuchElementException();
|
|
return asBuilder();
|
|
}
|
|
|
|
@Override
|
|
public Builder addVerifier(Consumer<ConfigCategory> verifier) {
|
|
checkBuilt();
|
|
verifiers.add(verifier);
|
|
return asBuilder();
|
|
}
|
|
|
|
@Override
|
|
public Builder addVerifier(Runnable verifier) {
|
|
return addVerifier(cfg -> verifier.run());
|
|
}
|
|
|
|
@Override
|
|
public Builder referenceConfig(String id) {
|
|
return referenceConfig(() -> List.of(ConfigHolder.getInstance().get(id)));
|
|
}
|
|
|
|
@Override
|
|
public Builder referenceConfig(ConfigInstance config) {
|
|
return referenceConfig(() -> List.of(config));
|
|
}
|
|
|
|
@Override
|
|
public Builder referenceConfig(Supplier<List<ConfigInstance>> gen) {
|
|
checkBuilt();
|
|
referencedConfigs.add(Objects.requireNonNull(gen));
|
|
return asBuilder();
|
|
}
|
|
|
|
@Override
|
|
public Builder category(String id, CategoryBuilderFunction builder) {
|
|
checkBuilt();
|
|
categories.add(builder.apply(new CategoryBuilderImpl(id, categoryPath + id + ".").setTranslationPrefix(translationPrefix + id + ".")));
|
|
return asBuilder();
|
|
}
|
|
|
|
@Override
|
|
public Builder value(String id, int def, double min, double max, Supplier<Integer> get, Consumer<Integer> set) {
|
|
checkBuilt();
|
|
entries.add(new DslEntryInfo<>(id, def, get::get, set::accept, Type.TInt.INSTANCE, 100, min, max));
|
|
return asBuilder();
|
|
}
|
|
|
|
@Override
|
|
public Builder value(String id, long def, double min, double max, Supplier<Long> get, Consumer<Long> set) {
|
|
checkBuilt();
|
|
entries.add(new DslEntryInfo<>(id, def, get::get, set::accept, Type.TLong.INSTANCE, 100, min, max));
|
|
return asBuilder();
|
|
}
|
|
|
|
@Override
|
|
public Builder value(String id, float def, double min, double max, Supplier<Float> get, Consumer<Float> set) {
|
|
checkBuilt();
|
|
entries.add(new DslEntryInfo<>(id, def, get::get, set::accept, Type.TFloat.INSTANCE, 100, min, max));
|
|
return asBuilder();
|
|
}
|
|
|
|
@Override
|
|
public Builder value(String id, double def, double min, double max, Supplier<Double> get, Consumer<Double> set) {
|
|
checkBuilt();
|
|
entries.add(new DslEntryInfo<>(id, def, get::get, set::accept, Type.TDouble.INSTANCE, 100, min, max));
|
|
return asBuilder();
|
|
}
|
|
|
|
@Override
|
|
public Builder value(String id, String def, Supplier<String> get, Consumer<String> set) {
|
|
checkBuilt();
|
|
entries.add(new DslEntryInfo<>(id, def, get::get, set::accept, Type.TString.INSTANCE));
|
|
return asBuilder();
|
|
}
|
|
|
|
@Override
|
|
public Builder value(String id, boolean def, Supplier<Boolean> get, Consumer<Boolean> set) {
|
|
checkBuilt();
|
|
entries.add(new DslEntryInfo<>(id, def, get::get, set::accept, Type.TBool.INSTANCE));
|
|
return asBuilder();
|
|
}
|
|
|
|
@Override
|
|
public Builder value(String id, String def, String[] options, Supplier<String> get, Consumer<String> set) {
|
|
checkBuilt();
|
|
entries.add(new DslEntryInfo<>(id, def, get::get, set::accept, Type.TEnum.create(id, options)));
|
|
return asBuilder();
|
|
}
|
|
|
|
@Override
|
|
public <T extends Enum<T>> Builder value(String id, T def, Class<T> klazz, Supplier<T> get, Consumer<T> set) {
|
|
checkBuilt();
|
|
entries.add(new DslEntryInfo<>(id, def, get::get, set::accept, new Type.TEnum<>(klazz)));
|
|
return asBuilder();
|
|
}
|
|
|
|
@Override
|
|
public <T> Builder value(String id, T def, double min, double max, Type type, int width, Supplier<T> get, Consumer<T> set) {
|
|
checkBuilt();
|
|
entries.add(new DslEntryInfo<>(id, def, get::get, set::accept, type, width, min, max));
|
|
return asBuilder();
|
|
}
|
|
|
|
@Override
|
|
public <T> Builder value(EntryInfo<T> entry) {
|
|
checkBuilt();
|
|
entries.add(Objects.requireNonNull(entry));
|
|
return asBuilder();
|
|
}
|
|
|
|
@Override
|
|
public Builder addMigration(String element, Migration migration) {
|
|
checkBuilt();
|
|
if (migrations.containsKey(element)) LibJf.LOGGER.warn("Duplicate migration registered for " + categoryPath + id + ": " + element + ", overriding");
|
|
migrations.put(element, Coerce.<SerializeReader, Exception>consumer(migration::apply).addHandler(e -> LibJf.LOGGER.error("Could not apply migration for " + element, e)));
|
|
return asBuilder();
|
|
}
|
|
|
|
@Override
|
|
public String getId() {
|
|
return id;
|
|
}
|
|
|
|
protected Builder asBuilder() {
|
|
//noinspection unchecked
|
|
return (Builder) this;
|
|
}
|
|
|
|
protected void checkBuilt() {
|
|
if (built) throw new IllegalStateException("This builder was already used to build a category!");
|
|
}
|
|
|
|
protected void markBuilt() {
|
|
checkBuilt();
|
|
built = true;
|
|
}
|
|
|
|
@Override
|
|
public DslConfigCategory build(Supplier<ConfigInstance> root) {
|
|
markBuilt();
|
|
Set<String> migrationNames = migrations.keySet();
|
|
Set<String> entryNames = new HashSet<>();
|
|
for (EntryInfo<?> entry : entries) {
|
|
String name = entry.getName();
|
|
if (migrationNames.contains(name)) LibJf.LOGGER.warn("Entry conflict: " + categoryPath + id + " contains both a migration and an entry for " + name);
|
|
if (!entryNames.add(name)) LibJf.LOGGER.warn("Entry conflict: " + categoryPath + id + " contains two entries for " + name);
|
|
}
|
|
Set<String> categoryNames = new HashSet<>();
|
|
for (CategoryBuilder<?> category : categories) {
|
|
String name = category.getId();
|
|
if (migrationNames.contains(name)) LibJf.LOGGER.warn("Entry conflict: " + categoryPath + id + " contains both a migration and a category for " + name);
|
|
if (entryNames.contains(name)) LibJf.LOGGER.warn("Entry conflict: " + categoryPath + id + " contains both an entry and a category for " + name);
|
|
if (!categoryNames.add(name)) LibJf.LOGGER.warn("Entry conflict: " + categoryPath + id + " contains two categories for " + name);
|
|
}
|
|
return new DslConfigCategory(
|
|
id,
|
|
categoryPath,
|
|
translationPrefix,
|
|
entries,
|
|
presets,
|
|
referencedConfigs,
|
|
categories,
|
|
root,
|
|
verifiers,
|
|
migrations
|
|
);
|
|
}
|
|
}
|