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.v3;
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     * @param node node to use
076     * @return this builder
077     * @since 4.0.0
078     */
079    public ConfigurateOpsBuilder factoryFromNode(final ConfigurationNode node) {
080        final ConfigurationOptions options = requireNonNull(node, "node").options();
081        return factory(new ConfigurationNodeFactory<ConfigurationNode>() {
082            @Override
083            public ConfigurationNode createNode(final ConfigurationOptions options) {
084                return CommentedConfigurationNode.root(options);
085            }
086
087            @Override public ConfigurationOptions defaultOptions() {
088                return options;
089            }
090        });
091    }
092
093    /**
094     * Set whether {@link com.mojang.serialization.Keyable} values should be compressed.
095     *
096     * @param compressed whether to compress values
097     * @return this builder
098     * @see ConfigurateOps#compressMaps() for more about what compression is
099     * @since 4.0.0
100     */
101    public ConfigurateOpsBuilder compressed(final boolean compressed) {
102        this.compressed = compressed;
103        return this;
104    }
105
106    /**
107     * Set how nodes returned from read methods will be protected
108     * from modification.
109     *
110     * <p>For read protection, the protection level refers to how the attached
111     * node will be affected by modifications made to the nodes returned from
112     * {@code get*} methods.
113     *
114     * @param readProtection protection level
115     * @return this builder
116     * @since 4.0.0
117     */
118    public ConfigurateOpsBuilder readProtection(final ConfigurateOps.Protection readProtection) {
119        this.readProtection = requireNonNull(readProtection, "readProtection");
120        return this;
121    }
122
123    /**
124     * Set how nodes provided to mutator methods will be protected
125     * from modification.
126     *
127     * <p>For write protection, the protection level refers to how the provided
128     * {@code prefix} node will be protected from seeing changes to the
129     * operation
130     *
131     * @param writeProtection protection level
132     * @return this builder
133     * @since 4.0.0
134     */
135    public ConfigurateOpsBuilder writeProtection(final ConfigurateOps.Protection writeProtection) {
136        this.writeProtection = requireNonNull(writeProtection, "writeProtection");
137        return this;
138    }
139
140    /**
141     * Set how nodes will be protected from both read and write modifications.
142     *
143     * @param protection protection level
144     * @return this builder
145     * @see #readProtection(ConfigurateOps.Protection) for how this level
146     *      affects value reads
147     * @see #writeProtection(ConfigurateOps.Protection) for how this level
148     *      affects value writes
149     * @since 4.0.0
150     */
151    public ConfigurateOpsBuilder readWriteProtection(final ConfigurateOps.Protection protection) {
152        requireNonNull(protection, "protection");
153        this.readProtection = protection;
154        this.writeProtection = protection;
155        return this;
156    }
157
158    /**
159     * Create a new ops instance.
160     *
161     * <p>All options have defaults provided and all setters validate their
162     * input, so by the time this method is reached the builder will be in a
163     * valid state.
164     *
165     * @return the new instance
166     * @since 4.0.0
167     */
168    public ConfigurateOps build() {
169        return new ConfigurateOps(this.nodeSupplier, this.compressed, this.readProtection, this.writeProtection);
170    }
171
172    /**
173     * Build a new ops instance, returned as part of a {@linkplain Dynamic}.
174     *
175     * <p>Returned ops instances will not take type serializers or other options
176     * from the provided node. For that, use {@link #factoryFromNode(ConfigurationNode)}.
177     *
178     * @param node wrapped node
179     * @return new dynamic
180     * @since 4.0.0
181     */
182    public Dynamic<ConfigurationNode> buildWrapping(final ConfigurationNode node) {
183        return new Dynamic<>(build(), node);
184    }
185
186}