001//
002// MIT License
003//
004// Copyright (c) 2021 Alexander Söderberg & Contributors
005//
006// Permission is hereby granted, free of charge, to any person obtaining a copy
007// of this software and associated documentation files (the "Software"), to deal
008// in the Software without restriction, including without limitation the rights
009// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
010// copies of the Software, and to permit persons to whom the Software is
011// furnished to do so, subject to the following conditions:
012//
013// The above copyright notice and this permission notice shall be included in all
014// copies or substantial portions of the Software.
015//
016// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
017// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
018// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
019// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
020// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
021// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
022// SOFTWARE.
023//
024package cloud.commandframework.bukkit.parsers;
025
026import cloud.commandframework.ArgumentDescription;
027import cloud.commandframework.arguments.CommandArgument;
028import cloud.commandframework.arguments.parser.ArgumentParseResult;
029import cloud.commandframework.arguments.parser.ArgumentParser;
030import cloud.commandframework.bukkit.BukkitCaptionKeys;
031import cloud.commandframework.captions.CaptionVariable;
032import cloud.commandframework.context.CommandContext;
033import cloud.commandframework.exceptions.parsing.NoInputProvidedException;
034import cloud.commandframework.exceptions.parsing.ParserException;
035import org.bukkit.Material;
036import org.checkerframework.checker.nullness.qual.NonNull;
037import org.checkerframework.checker.nullness.qual.Nullable;
038
039import java.util.ArrayList;
040import java.util.List;
041import java.util.Queue;
042import java.util.function.BiFunction;
043
044/**
045 * cloud argument type that parses Bukkit {@link Material materials}
046 *
047 * @param <C> Command sender type
048 */
049public class MaterialArgument<C> extends CommandArgument<C, Material> {
050
051    protected MaterialArgument(
052            final boolean required,
053            final @NonNull String name,
054            final @NonNull String defaultValue,
055            final @Nullable BiFunction<@NonNull CommandContext<C>, @NonNull String,
056                    @NonNull List<@NonNull String>> suggestionsProvider,
057            final @NonNull ArgumentDescription defaultDescription
058            ) {
059        super(required, name, new MaterialParser<>(), defaultValue, Material.class, suggestionsProvider);
060    }
061
062    /**
063     * Create a new builder
064     *
065     * @param name Name of the argument
066     * @param <C>  Command sender type
067     * @return Created builder
068     */
069    public static <C> MaterialArgument.@NonNull Builder<C> newBuilder(final @NonNull String name) {
070        return new MaterialArgument.Builder<>(name);
071    }
072
073    /**
074     * Create a new required argument
075     *
076     * @param name Argument name
077     * @param <C>  Command sender type
078     * @return Created argument
079     */
080    public static <C> @NonNull CommandArgument<C, Material> of(final @NonNull String name) {
081        return MaterialArgument.<C>newBuilder(name).asRequired().build();
082    }
083
084    /**
085     * Create a new optional argument
086     *
087     * @param name Argument name
088     * @param <C>  Command sender type
089     * @return Created argument
090     */
091    public static <C> @NonNull CommandArgument<C, Material> optional(final @NonNull String name) {
092        return MaterialArgument.<C>newBuilder(name).asOptional().build();
093    }
094
095    /**
096     * Create a new optional argument with a default value
097     *
098     * @param name     Argument name
099     * @param material Default value
100     * @param <C>      Command sender type
101     * @return Created argument
102     */
103    public static <C> @NonNull CommandArgument<C, Material> optional(
104            final @NonNull String name,
105            final @NonNull Material material
106    ) {
107        return MaterialArgument.<C>newBuilder(name).asOptionalWithDefault(material.name().toLowerCase()).build();
108    }
109
110    public static final class Builder<C> extends CommandArgument.Builder<C, Material> {
111
112        private Builder(final @NonNull String name) {
113            super(Material.class, name);
114        }
115
116        @Override
117        public @NonNull CommandArgument<C, Material> build() {
118            return new MaterialArgument<>(
119                    this.isRequired(),
120                    this.getName(),
121                    this.getDefaultValue(),
122                    this.getSuggestionsProvider(),
123                    this.getDefaultDescription()
124            );
125        }
126
127    }
128
129    public static final class MaterialParser<C> implements ArgumentParser<C, Material> {
130
131        @Override
132        public @NonNull ArgumentParseResult<Material> parse(
133                final @NonNull CommandContext<C> commandContext,
134                final @NonNull Queue<@NonNull String> inputQueue
135        ) {
136            String input = inputQueue.peek();
137            if (input == null) {
138                return ArgumentParseResult.failure(new NoInputProvidedException(
139                        MaterialParser.class,
140                        commandContext
141                ));
142            }
143
144            try {
145                final Material material = Material.valueOf(input.toUpperCase());
146                inputQueue.remove();
147                return ArgumentParseResult.success(material);
148            } catch (final IllegalArgumentException exception) {
149                return ArgumentParseResult.failure(new MaterialParseException(input, commandContext));
150            }
151        }
152
153        @Override
154        public @NonNull List<@NonNull String> suggestions(
155                final @NonNull CommandContext<C> commandContext,
156                final @NonNull String input
157        ) {
158            final List<String> completions = new ArrayList<>();
159            for (Material value : Material.values()) {
160                completions.add(value.name().toLowerCase());
161            }
162            return completions;
163        }
164
165    }
166
167
168    public static final class MaterialParseException extends ParserException {
169
170        private static final long serialVersionUID = 1615554107385965610L;
171        private final String input;
172
173        /**
174         * Construct a new MaterialParseException
175         *
176         * @param input   Input
177         * @param context Command context
178         */
179        public MaterialParseException(
180                final @NonNull String input,
181                final @NonNull CommandContext<?> context
182        ) {
183            super(
184                    MaterialParser.class,
185                    context,
186                    BukkitCaptionKeys.ARGUMENT_PARSE_FAILURE_MATERIAL,
187                    CaptionVariable.of("input", input)
188            );
189            this.input = input;
190        }
191
192        /**
193         * Get the input
194         *
195         * @return Input
196         */
197        public @NonNull String getInput() {
198            return this.input;
199        }
200
201    }
202
203}