001package com.mrivanplays.annotationconfig.core.resolver.settings;
002
003import com.mrivanplays.annotationconfig.core.resolver.ConfigResolver;
004import java.util.HashMap;
005import java.util.Map;
006import java.util.Optional;
007
008/**
009 * Represents load settings. They are used upon annotated config load.
010 *
011 * @author MrIvanPlays
012 * @since 2.0.0
013 */
014public final class LoadSettings {
015
016  /**
017   * Creates a new empty {@link LoadSettings.Builder}
018   *
019   * @return empty builder instance
020   */
021  public static LoadSettings.Builder newBuilder() {
022    return newBuilder(false);
023  }
024
025  /**
026   * Creates a new {@link LoadSettings.Builder}
027   *
028   * @param fromDefaults whether to instantiate load settings from {@link LoadSettings#getDefault()}
029   * @return builder instance
030   */
031  public static LoadSettings.Builder newBuilder(boolean fromDefaults) {
032    return new LoadSettings.Builder(fromDefaults);
033  }
034
035  /**
036   * Creates new empty load settings. If used unmodified on a {@link ConfigResolver}, the config
037   * resolver will fall back to the default settings (a.ka {@link LoadSettings#getDefault()}).
038   *
039   * @return empty load settings
040   */
041  public static LoadSettings empty() {
042    return new LoadSettings();
043  }
044
045  private static LoadSettings def;
046
047  /**
048   * Returns the default load settings.
049   *
050   * @return defaults
051   */
052  public static LoadSettings getDefault() {
053    if (def == null) {
054      def = initializeDefaultSettings();
055    }
056    return def;
057  }
058
059  private static LoadSettings initializeDefaultSettings() {
060    LoadSettings settings = new LoadSettings();
061    settings.set(LoadSetting.GENERATE_NEW_OPTIONS, true);
062    settings.set(LoadSetting.NULL_READ_HANDLER, NullReadHandleOption.SET_NULL);
063    return settings;
064  }
065
066  private Map<String, Object> settings;
067
068  private LoadSettings() {
069    this.settings = new HashMap<>();
070  }
071
072  private LoadSettings(Map<String, Object> settings) {
073    this.settings = settings;
074  }
075
076  /**
077   * Returns the value held for the specified {@link LoadSetting} {@code setting}
078   *
079   * @param setting the load setting you want the value for
080   * @param <T> value type
081   * @return load setting value optional, which can be empty
082   */
083  public <T> Optional<T> get(LoadSetting<T> setting) {
084    Object val = settings.get(setting.getKey());
085    if (val == null || !setting.getType().isAssignableFrom(val.getClass())) {
086      return Optional.empty();
087    }
088    return Optional.of(setting.getType().cast(val));
089  }
090
091  /**
092   * Binds the specified {@code value} to the specified {@link LoadSetting} {@code setting}. If the
093   * load setting already has a value, it gets replaced.
094   *
095   * @param setting the load setting you want the value to be bound to
096   * @param value the value you want bound
097   * @param <T> value type
098   */
099  public <T> void set(LoadSetting<T> setting, T value) {
100    if (settings.containsKey(setting.getKey())) {
101      settings.replace(setting.getKey(), value);
102    } else {
103      settings.put(setting.getKey(), value);
104    }
105  }
106
107  /**
108   * Creates a copy of the current load settings
109   *
110   * @return copy
111   */
112  public LoadSettings copy() {
113    return new LoadSettings(this.settings);
114  }
115
116  /**
117   * Represents a builder for {@link LoadSettings}
118   *
119   * @author MrIvanPlays
120   * @since 2.0.0
121   */
122  public static final class Builder {
123
124    private final LoadSettings loadSettings;
125
126    public Builder(boolean fromDefaults) {
127      if (fromDefaults) {
128        loadSettings = LoadSettings.getDefault().copy();
129      } else {
130        loadSettings = LoadSettings.empty();
131      }
132    }
133
134    private Builder(Builder other) {
135      this.loadSettings = other.loadSettings;
136    }
137
138    /**
139     * Creates a copy of the current builder.
140     *
141     * @return copy
142     */
143    public Builder copy() {
144      return new Builder(this);
145    }
146
147    /**
148     * Binds the specified {@code value} to the specified {@link LoadSetting} {@code setting}.
149     *
150     * @param setting the setting you want the value to be bound to
151     * @param value the value you want bound
152     * @param <T> value type
153     * @return this instance for chaining
154     */
155    public <T> Builder withSetting(LoadSetting<T> setting, T value) {
156      loadSettings.set(setting, value);
157      return this;
158    }
159
160    /**
161     * Builds this builder into {@link LoadSettings}
162     *
163     * @return load settings
164     */
165    public LoadSettings build() {
166      return loadSettings;
167    }
168  }
169}