001package com.mrivanplays.annotationconfig.yaml;
002
003import java.util.Collections;
004import java.util.Iterator;
005import java.util.LinkedHashMap;
006import java.util.Map;
007import java.util.Map.Entry;
008import java.util.Objects;
009
010/**
011 * Represents a section list. A YAML example:
012 *
013 * <pre><code>
014 * foo:
015 *   bar:
016 *     baz: aa
017 *     lorem: ipsum
018 *     dolor: sit
019 *     amet: lorem
020 *   ipsum:
021 *     baz: bb
022 *     lorem: dolor
023 *     dolor: lorem
024 *     amet: ipsum
025 * </code></pre>
026 *
027 * <p>How to use: you have to register a {@link SectionObjectListSerializer} with the help of a
028 * {@link com.mrivanplays.annotationconfig.core.utils.TypeToken} in order for this list to properly
029 * (de)serialize.
030 *
031 * @author MrIvanPlays
032 * @since v2.1.1
033 */
034public final class SectionObjectList<T> implements Iterable<Entry<String, T>> {
035
036  /**
037   * Creates a new {@link SectionObjectListBuilder} with pre-defined {@link Class} type.
038   *
039   * @param type type
040   * @param <T> object type
041   * @return new builder
042   */
043  public static <T> SectionObjectListBuilder<T> newBuilderForType(Class<? extends T> type) {
044    return new SectionObjectListBuilder<>(type);
045  }
046
047  private final Map<String, T> values;
048  private final Class<? extends T> clazz;
049
050  SectionObjectList(Class<? extends T> clazz, Map<String, T> values) {
051    this.clazz = clazz;
052    this.values = values;
053  }
054
055  /**
056   * Returns the {@link Class} type of the value objects held in this section object list.
057   *
058   * @return objects type
059   */
060  public Class<? extends T> getObjectsType() {
061    return clazz;
062  }
063
064  /**
065   * Returns an unmodifiable representation of this {@code SectionObjectList} as a {@link Map}
066   *
067   * @return as map
068   */
069  public Map<String, T> getAsMap() {
070    return Collections.unmodifiableMap(values);
071  }
072
073  /** {@inheritDoc} */
074  @Override
075  public Iterator<Entry<String, T>> iterator() {
076    return this.values.entrySet().iterator();
077  }
078
079  /**
080   * Represents a builder of {@link SectionObjectList}
081   *
082   * @param <T> object type
083   * @author MrIvanPlays
084   * @since v2.1.1
085   */
086  public static final class SectionObjectListBuilder<T> {
087
088    private final Map<String, T> values = new LinkedHashMap<>();
089    private final Class<? extends T> type;
090
091    private SectionObjectListBuilder(Class<? extends T> type) {
092      this.type = Objects.requireNonNull(type, "type");
093      if (SectionObjectList.class.isAssignableFrom(type)) {
094        throw new IllegalArgumentException("SectionObjectList<SectionObjectList>");
095      }
096      if (SectionObjectListBuilder.class.isAssignableFrom(type)) {
097        throw new IllegalArgumentException("SectionObjectList<SectionObjectListBuilder>");
098      }
099    }
100
101    /**
102     * Specify a default value held by the created {@link SectionObjectList}
103     *
104     * @param key default value key
105     * @param value default value value
106     * @return this instance for chaining
107     */
108    public SectionObjectListBuilder<T> defaultValue(String key, T value) {
109      this.values.put(key, value);
110      return this;
111    }
112
113    /**
114     * Builds a new {@link SectionObjectList} from the given parameters.
115     *
116     * @return new section object list
117     */
118    public SectionObjectList<T> build() {
119      if (values.isEmpty()) {
120        throw new IllegalStateException(
121            "No defaults for SectionObjectList<" + type.getSimpleName() + ">");
122      }
123      return new SectionObjectList<>(type, values);
124    }
125  }
126}