package mods.betterfoliage.config import me.shedaniel.clothconfig2.api.AbstractConfigListEntry import me.shedaniel.clothconfig2.api.ConfigEntryBuilder import me.shedaniel.clothconfig2.gui.entries.SubCategoryListEntry import me.zeroeightsix.fiber.builder.ConfigValueBuilder import me.zeroeightsix.fiber.tree.ConfigLeaf import me.zeroeightsix.fiber.tree.ConfigNode import me.zeroeightsix.fiber.tree.ConfigValue import net.minecraft.client.resource.language.I18n import java.util.* import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty const val MAX_LINE_LEN = 30 sealed class DelegatingConfigNode(val fiberNode: N) { abstract fun createClothNode(names: List): AbstractConfigListEntry<*> } abstract class DelegatingConfigValue(fiberNode: ConfigValue) : DelegatingConfigNode>(fiberNode), ReadOnlyProperty open class DelegatingConfigGroup(fiberNode: ConfigNode) : DelegatingConfigNode(fiberNode) { val children = mutableListOf>() override fun createClothNode(names: List): SubCategoryListEntry { val builder = ConfigEntryBuilder.create() .startSubCategory(names.joinToString(".").translate()) .setTooltip(*names.joinToString(".").translateTooltip()) .setExpended(false) children.forEach { builder.add(it.createClothNode(names + it.fiberNode.name!!)) } return builder.build() } operator fun get(name: String) = children.find { it.fiberNode.name == name } } interface DelegatingConfigGroupFactory { operator fun provideDelegate(parent: DelegatingConfigGroup, property: KProperty<*>): ReadOnlyProperty } fun subNode(factory: (ConfigNode)->T) = object : DelegatingConfigGroupFactory { override operator fun provideDelegate(parent: DelegatingConfigGroup, property: KProperty<*>): ReadOnlyProperty { val childNode = ConfigNode(property.name, null) val configGroup = factory(childNode) parent.fiberNode.items.add(childNode) parent.children.add(configGroup) return object : ReadOnlyProperty { override fun getValue(thisRef: DelegatingConfigGroup, property: KProperty<*>) = configGroup } } } interface DelegatingConfigValueFactory { fun createFiberNode(parent: ConfigNode, name: String): ConfigValue fun createClothNode(node: ConfigValue, names: List): AbstractConfigListEntry operator fun provideDelegate(parent: DelegatingConfigGroup, property: KProperty<*>): ReadOnlyProperty { return object : DelegatingConfigValue(createFiberNode(parent.fiberNode, property.name)) { override fun createClothNode(names: List) = createClothNode(fiberNode, names) override fun getValue(thisRef: DelegatingConfigGroup, property: KProperty<*>) = fiberNode.value!! }.apply { parent.children.add(this) } } } fun String.translate() = I18n.translate(this) fun String.translateTooltip(lineLength: Int = MAX_LINE_LEN) = ("$this.tooltip").translate().let { tooltip -> tooltip.splitToSequence(" ").fold(mutableListOf("")) { tooltips, word -> if (tooltips.last().length + word.length < lineLength) { tooltips[tooltips.lastIndex] += "$word " } else { tooltips.add("$word ") } tooltips }.map { it.trim() }.toTypedArray() } fun boolean( default: Boolean, langKey: (List)->String = { it.joinToString(".") }, valueOverride: (Boolean)->Boolean = { it } ) = object : DelegatingConfigValueFactory { override fun createFiberNode(parent: ConfigNode, name: String) = ConfigValueBuilder(Boolean::class.java) .withName(name) .withParent(parent) .withDefaultValue(default) .build() override fun createClothNode(node: ConfigValue, names: List) = ConfigEntryBuilder.create() .startBooleanToggle(langKey(names).translate(), node.value!!) .setTooltip(langKey(names).let { if (I18n.hasTranslation("$it.tooltip")) Optional.of(it.translateTooltip()) else Optional.empty() }) .setSaveConsumer { node.value = valueOverride(it) } .build() } fun integer( default: Int, min: Int, max: Int, langKey: (List)->String = { it.joinToString(".") }, valueOverride: (Int)->Int = { it } ) = object : DelegatingConfigValueFactory { override fun createFiberNode(parent: ConfigNode, name: String) = ConfigValueBuilder(Int::class.java) .withName(name) .withParent(parent) .withDefaultValue(default) .constraints().minNumerical(min).maxNumerical(max).finish() .build() override fun createClothNode(node: ConfigValue, names: List) = ConfigEntryBuilder.create() .startIntField(langKey(names).translate(), node.value!!) .setTooltip(langKey(names).let { if (I18n.hasTranslation("$it.tooltip")) Optional.of(it.translateTooltip()) else Optional.empty() }) .setMin(min).setMax(max) .setSaveConsumer { node.value = valueOverride(it) } .build() } fun double( default: Double, min: Double, max: Double, langKey: (List)->String = { it.joinToString(".") }, valueOverride: (Double)->Double = { it } ) = object : DelegatingConfigValueFactory { override fun createFiberNode(parent: ConfigNode, name: String) = ConfigValueBuilder(Double::class.java) .withName(name) .withParent(parent) .withDefaultValue(default) .constraints().minNumerical(min).maxNumerical(max).finish() .build() override fun createClothNode(node: ConfigValue, names: List) = ConfigEntryBuilder.create() .startDoubleField(langKey(names).translate(), node.value!!) .setTooltip(langKey(names).let { if (I18n.hasTranslation("$it.tooltip")) Optional.of(it.translateTooltip()) else Optional.empty() }) .setMin(min).setMax(max) .setSaveConsumer { node.value = valueOverride(it) } .build() } val recurring = { names: List -> "${names.first()}.${names.last()}" } fun fakeCategory(name: String) = { names: List -> (listOf(names.first(), name) + names.drop(1)).joinToString(".") }