001/*
002 * Configurate
003 * Copyright (C) zml and Configurate contributors
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.spongepowered.configurate.extra.dfu.v4;
018
019import static java.util.Objects.requireNonNull;
020
021import com.mojang.serialization.Dynamic;
022import org.spongepowered.configurate.CommentedConfigurationNode;
023import org.spongepowered.configurate.ConfigurationNode;
024import org.spongepowered.configurate.ConfigurationNodeFactory;
025import org.spongepowered.configurate.ConfigurationOptions;
026import org.spongepowered.configurate.serialize.TypeSerializerCollection;
027
028/**
029 * A builder for {@link ConfigurateOps} instances.
030 *
031 * @since 4.0.0
032 */
033public final class ConfigurateOpsBuilder {
034
035    private ConfigurationNodeFactory<? extends ConfigurationNode> nodeSupplier = CommentedConfigurationNode.factory();
036    private boolean compressed;
037    private ConfigurateOps.Protection readProtection = ConfigurateOps.Protection.COPY_DEEP;
038    private ConfigurateOps.Protection writeProtection = ConfigurateOps.Protection.COPY_DEEP;
039
040    ConfigurateOpsBuilder() {}
041
042    /**
043     * Set the node factory for the returned ops.
044     *
045     * <p>The default node factory wil create {@link CommentedConfigurationNode}
046     * instances using Confabricate's minecraft serializers.
047     *
048     * @param supplier source for new nodes created to store values in
049     *     the {@code create*} methods
050     * @return this builder
051     * @since 4.0.0
052     */
053    public ConfigurateOpsBuilder factory(final ConfigurationNodeFactory<? extends ConfigurationNode> supplier) {
054        this.nodeSupplier = requireNonNull(supplier, "nodeSupplier");
055        return this;
056    }
057
058    /**
059     * Set a node factory that will use the provided collection.
060     *
061     * <p>This will replace any set {@link #factory(ConfigurationNodeFactory)}.
062     *
063     * @param collection type serializers to use for nodes.
064     * @return this builder
065     * @since 4.0.0
066     */
067    public ConfigurateOpsBuilder factoryFromSerializers(final TypeSerializerCollection collection) {
068        requireNonNull(collection, "collection");
069        return factory(options -> CommentedConfigurationNode.root(options.serializers(collection)));
070    }
071
072    /**
073     * Set the node factory based on the options of the provided node.
074     *
075     * <p>This will replace any set {@link #factory(ConfigurationNodeFactory)}.
076     *
077     * @param node node to use
078     * @return this builder
079     * @since 4.0.0
080     */
081    public ConfigurateOpsBuilder factoryFromNode(final ConfigurationNode node) {
082        final ConfigurationOptions options = requireNonNull(node, "node").options();
083        return factory(new ConfigurationNodeFactory<ConfigurationNode>() {
084            @Override
085            public ConfigurationNode createNode(final ConfigurationOptions options) {
086                return CommentedConfigurationNode.root(options);
087            }
088
089            @Override public ConfigurationOptions defaultOptions() {
090                return options;
091            }
092        });
093    }
094
095    /**
096     * Set whether {@link com.mojang.serialization.Keyable} values should be compressed.
097     *
098     * @param compressed whether to compress values
099     * @return this builder
100     * @see ConfigurateOps#compressMaps() for more about what compression is
101     * @since 4.0.0
102     */
103    public ConfigurateOpsBuilder compressed(final boolean compressed) {
104        this.compressed = compressed;
105        return this;
106    }
107
108    /**
109     * Set how nodes returned from read methods will be protected
110     * from modification.
111     *
112     * <p>For read protection, the protection level refers to how the attached
113     * node will be affected by modifications made to the nodes returned from
114     * {@code get*} methods.
115     *
116     * @param readProtection protection level
117     * @return this builder
118     * @since 4.0.0
119     */
120    public ConfigurateOpsBuilder readProtection(final ConfigurateOps.Protection readProtection) {
121        this.readProtection = requireNonNull(readProtection, "readProtection");
122        return this;
123    }
124
125    /**
126     * Set how nodes provided to mutator methods will be protected
127     * from modification.
128     *
129     * <p>For write protection, the protection level refers to how the provided
130     * {@code prefix} node will be protected from seeing changes to the
131     * operation
132     *
133     * @param writeProtection protection level
134     * @return this builder
135     * @since 4.0.0
136     */
137    public ConfigurateOpsBuilder writeProtection(final ConfigurateOps.Protection writeProtection) {
138        this.writeProtection = requireNonNull(writeProtection, "writeProtection");
139        return this;
140    }
141
142    /**
143     * Set how nodes will be protected from both read and write modifications.
144     *
145     * @param protection protection level
146     * @return this builder
147     * @see #readProtection(ConfigurateOps.Protection) for how this level
148     *      affects value reads
149     * @see #writeProtection(ConfigurateOps.Protection) for how this level
150     *      affects value writes
151     * @since 4.0.0
152     */
153    public ConfigurateOpsBuilder readWriteProtection(final ConfigurateOps.Protection protection) {
154        requireNonNull(protection, "protection");
155        this.readProtection = protection;
156        this.writeProtection = protection;
157        return this;
158    }
159
160    /**
161     * Create a new ops instance.
162     *
163     * <p>All options have defaults provided and all setters validate their
164     * input, so by the time this method is reached the builder will be in a
165     * valid state.
166     *
167     * @return the new instance
168     * @since 4.0.0
169     */
170    public ConfigurateOps build() {
171        return new ConfigurateOps(this.nodeSupplier, this.compressed, this.readProtection, this.writeProtection);
172    }
173
174    /**
175     * Build a new ops instance, returned as part of a {@linkplain Dynamic}.
176     *
177     * <p>Returned ops instances will not take type serializers or other options
178     * from the provided node. For that, use {@link #factoryFromNode(ConfigurationNode)}.
179     *
180     * @param node wrapped node
181     * @return new dynamic
182     * @since 4.0.0
183     */
184    public Dynamic<ConfigurationNode> buildWrapping(final ConfigurationNode node) {
185        return new Dynamic<>(build(), node);
186    }
187
188}