001package com.mrivanplays.annotationconfig.yaml;
002
003import com.mrivanplays.annotationconfig.core.resolver.ConfigResolver;
004import com.mrivanplays.annotationconfig.core.resolver.ValueReader;
005import com.mrivanplays.annotationconfig.core.resolver.ValueWriter;
006import com.mrivanplays.annotationconfig.core.resolver.options.CustomOptions;
007import com.mrivanplays.annotationconfig.core.resolver.settings.LoadSettings;
008import java.io.File;
009import java.io.PrintWriter;
010import java.io.Reader;
011import java.util.Collections;
012import java.util.LinkedHashMap;
013import java.util.List;
014import java.util.Map;
015import org.yaml.snakeyaml.Yaml;
016
017/**
018 * Represents configuration, utilising YAML
019 *
020 * @since 1.0
021 * @author MrIvanPlays
022 */
023public final class YamlConfig {
024
025  private static final Yaml YAML = new Yaml();
026  private static final ValueWriter VALUE_WRITER = new YamlValueWriter();
027
028  private static ConfigResolver configResolver;
029
030  /**
031   * Returns the {@link ConfigResolver} instance of YamlConfig
032   *
033   * @return config resolver
034   */
035  public static ConfigResolver getConfigResolver() {
036    if (configResolver == null) {
037      generateConfigResolver();
038    }
039    return configResolver;
040  }
041
042  private static void generateConfigResolver() {
043    configResolver =
044        ConfigResolver.newBuilder()
045            .withValueWriter(VALUE_WRITER)
046            .shouldReverseFields(true)
047            .withCommentPrefix("# ")
048            .withValueReader(
049                new ValueReader() {
050                  @Override
051                  public Map<String, Object> read(Reader reader) {
052                    Map<String, Object> values = YAML.loadAs(reader, LinkedHashMap.class);
053                    if (values == null) {
054                      return Collections.emptyMap();
055                    }
056                    return values;
057                  }
058                })
059            .build();
060  }
061
062  /**
063   * Loads the config object from the file. If the file does not exist, it creates one.
064   *
065   * @param annotatedConfig annotated config
066   * @param file file
067   * @deprecated use {@link #getConfigResolver()}. it has a much better description of methods. the
068   *     equivalent of this method there is {@link ConfigResolver#loadOrDump(Object, File,
069   *     LoadSettings)}
070   */
071  @Deprecated
072  public static void load(Object annotatedConfig, File file) {
073    getConfigResolver().loadOrDump(annotatedConfig, file);
074  }
075
076  private static final class YamlValueWriter implements ValueWriter {
077
078    @Override
079    public void write(
080        String key,
081        Object value,
082        PrintWriter writer,
083        CustomOptions options,
084        boolean sectionExists) {
085      write(key, value, writer, 2, sectionExists);
086    }
087
088    private void write(
089        String key, Object value, PrintWriter writer, int childIndents, boolean sectionExists) {
090      StringBuilder intentPrefixBuilder = new StringBuilder();
091      for (int i = 0; i < childIndents; i++) {
092        intentPrefixBuilder.append(" ");
093      }
094      String intentPrefix = intentPrefixBuilder.toString();
095      if (value instanceof Map<?, ?>) {
096        if (!sectionExists) {
097          writer.println(key + ":");
098        }
099        for (Map.Entry<String, Object> entry : ((Map<String, Object>) value).entrySet()) {
100          String mapKey = entry.getKey();
101          Object v = entry.getValue();
102          if (v instanceof List<?>) {
103            writer.println(intentPrefix + mapKey + ":");
104            for (Object b : (List<?>) v) {
105              if (!(b instanceof String)) {
106                writer.println(intentPrefix + "    - " + b);
107              } else {
108                writer.println(intentPrefix + "    - \"" + b + "\"");
109              }
110            }
111          } else if (v instanceof Map<?, ?>) {
112            write(mapKey, v, writer, childIndents + 2, sectionExists);
113          } else {
114            if (!(v instanceof String)) {
115              writer.println(intentPrefix + mapKey + ": " + v);
116            } else {
117              writer.println(intentPrefix + mapKey + ": \"" + v + "\"");
118            }
119          }
120        }
121      } else if (value instanceof List<?>) {
122        writer.println(key + ":");
123        for (Object b : (List<?>) value) {
124          if (!(b instanceof String)) {
125            writer.println(intentPrefix + "- " + b);
126          } else {
127            writer.println(intentPrefix + "- \"" + b + "\"");
128          }
129        }
130      } else {
131        if (!(value instanceof String)) {
132          writer.println(key + ": " + value);
133        } else {
134          writer.println(key + ": \"" + value + "\"");
135        }
136      }
137      writer.append('\n');
138    }
139  }
140}