package com.simon816.chatui.tabs.config; import static com.google.common.base.Preconditions.checkArgument; import com.simon816.chatui.util.ExtraUtils; import ninja.leaping.configurate.ConfigurationNode; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.action.ClickAction; import org.spongepowered.api.text.action.TextActions; import org.spongepowered.api.text.format.TextColors; import org.spongepowered.api.text.format.TextFormat; import org.spongepowered.api.text.format.TextStyles; class ConfigEntry { static abstract class ConfigValue { public abstract Text toText(boolean focus); protected ClickAction<?> createClickAction(ConfigEntry entry, ConfigEditTab boundTab) { return null; } public Object onSetValue(String input) { throw new UnsupportedOperationException("Cannot set value of this node"); } } static class UnknownValueType extends ConfigValue { private final Text text; public UnknownValueType(Object value) { this.text = Text.of("[Unknown] ", value); } @Override public Text toText(boolean focus) { return this.text; } } static class ComplexValue extends ConfigValue { private static final Text LINK = Text.of(TextFormat.of(TextColors.BLUE, TextStyles.UNDERLINE), "Click to open"); private static final Text LINK_BLUR = Text.of(TextFormat.of(TextColors.DARK_GRAY, TextStyles.UNDERLINE), "Click to open"); private final ConfigurationNode node; public ComplexValue(ConfigurationNode node) { this.node = node; } @Override public Text toText(boolean focus) { return focus ? LINK : LINK_BLUR; } @Override protected ClickAction<?> createClickAction(ConfigEntry entry, ConfigEditTab boundTab) { return ExtraUtils.clickAction(() -> { boundTab.control.setNode(this.node); }, boundTab); } } static class SimpleValue extends ConfigValue { private final ValueType type; private Object value; private Text text; public SimpleValue(Object value, ValueType type) { this.type = type; this.value = value; this.text = this.type.toText(this.value).build(); } @Override public Text toText(boolean focus) { if (!focus) { return this.text.toBuilder().color(TextColors.DARK_GRAY).build(); } return this.text; } @Override protected ClickAction<?> createClickAction(ConfigEntry entry, ConfigEditTab boundTab) { if (!boundTab.control.options.canEdit) { return null; } return this.type.createClickAction(this.value, entry, boundTab); } @Override public Object onSetValue(String input) { this.value = this.type.setValue(this.value, input); this.text = this.type.toText(this.value).build(); return this.value; } } static enum ValueType { BOOLEAN(Boolean.class) { @Override public Text.Builder toText(Object value) { return super.toText(value).color((Boolean) value ? TextColors.GREEN : TextColors.RED); } @Override public void onClick(ConfigEntry entry, ConfigEditTab tab) { ConfigurationNode node = tab.control.getNode().getNode(entry.key); Object value = entry.value.onSetValue(Boolean.toString(!this.<Boolean>checkType(node.getValue()))); node.setValue(value); tab.control.onNodeChanged(node); } @Override public Object setValue(Object old, String input) { return Boolean.parseBoolean(input); } }, NUMBER(Number.class) { @Override public Object setValue(Object old, String input) { if (old instanceof Double) { return Double.parseDouble(input); } else if (old instanceof Long) { return Long.parseLong(input); } else if (old instanceof Integer) { return Integer.parseInt(input); } // Safest bet - use double return Double.parseDouble(input); } @Override public Text.Builder toText(Object value) { return super.toText(value).color(TextColors.GOLD); } }, STRING(String.class) { @Override public Object setValue(Object old, String input) { return input; } }, NULL(null) { @Override public void onClick(ConfigEntry entry, ConfigEditTab tab) { } @Override public ClickAction<?> createClickAction(Object value, ConfigEntry entry, ConfigEditTab boundTab) { return null; } @Override public Text.Builder toText(Object value) { return Text.builder("NULL"); } @Override public Object setValue(Object old, String input) { throw new UnsupportedOperationException("Cannot set value of this node"); } }; private final Class<?> type; private ValueType(Class<?> type) { this.type = type; } @SuppressWarnings("unchecked") protected final <T> T checkType(Object value) { if (this == NULL) { checkArgument(value == null, "Value must be null"); return null; } checkArgument(this.type.isInstance(value), "Value must be instance of %s, found %s", this.type, value.getClass()); return (T) value; } public Text.Builder toText(Object value) { return Text.builder(checkType(value).toString()); } public void onClick(ConfigEntry entry, ConfigEditTab tab) { tab.control.setFocused(entry); } public ClickAction<?> createClickAction(Object value, ConfigEntry entry, ConfigEditTab boundTab) { checkType(value); if (boundTab.control.hasExplicitFocus(entry)) { return TextActions.suggestCommand(value.toString()); } return ExtraUtils.clickAction(() -> { this.onClick(entry, boundTab); }, boundTab); } public abstract Object setValue(Object old, String input); } public final Object key; final ConfigValue value; public ConfigEntry(Object key, ConfigValue value) { this.key = key; this.value = value; } }