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.arguments.standard;
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.captions.CaptionVariable;
031import cloud.commandframework.captions.StandardCaptionKeys;
032import cloud.commandframework.context.CommandContext;
033import cloud.commandframework.exceptions.parsing.NoInputProvidedException;
034import cloud.commandframework.exceptions.parsing.ParserException;
035import org.checkerframework.checker.nullness.qual.NonNull;
036import org.checkerframework.checker.nullness.qual.Nullable;
037
038import java.util.List;
039import java.util.Queue;
040import java.util.UUID;
041import java.util.function.BiFunction;
042
043@SuppressWarnings("unused")
044public final class UUIDArgument<C> extends CommandArgument<C, UUID> {
045
046    private UUIDArgument(
047            final boolean required,
048            final @NonNull String name,
049            final @NonNull String defaultValue,
050            final @Nullable BiFunction<@NonNull CommandContext<C>,
051                    @NonNull String, @NonNull List<@NonNull String>> suggestionsProvider,
052            final @NonNull ArgumentDescription defaultDescription
053    ) {
054        super(required, name, new UUIDParser<>(), defaultValue, UUID.class, suggestionsProvider, defaultDescription);
055    }
056
057    /**
058     * Create a new builder
059     *
060     * @param name Name of the component
061     * @param <C>  Command sender type
062     * @return Created builder
063     */
064    public static <C> @NonNull Builder<C> newBuilder(final @NonNull String name) {
065        return new Builder<>(name);
066    }
067
068    /**
069     * Create a new required command component
070     *
071     * @param name Component name
072     * @param <C>  Command sender type
073     * @return Created component
074     */
075    public static <C> @NonNull CommandArgument<C, UUID> of(final @NonNull String name) {
076        return UUIDArgument.<C>newBuilder(name).asRequired().build();
077    }
078
079    /**
080     * Create a new optional command component
081     *
082     * @param name Component name
083     * @param <C>  Command sender type
084     * @return Created component
085     */
086    public static <C> @NonNull CommandArgument<C, UUID> optional(final @NonNull String name) {
087        return UUIDArgument.<C>newBuilder(name).asOptional().build();
088    }
089
090    /**
091     * Create a new required command component with a default value
092     *
093     * @param name        Component name
094     * @param defaultUUID Default uuid
095     * @param <C>         Command sender type
096     * @return Created component
097     */
098    public static <C> @NonNull CommandArgument<C, UUID> optional(
099            final @NonNull String name,
100            final @NonNull UUID defaultUUID
101    ) {
102        return UUIDArgument.<C>newBuilder(name).asOptionalWithDefault(defaultUUID.toString()).build();
103    }
104
105
106    public static final class Builder<C> extends CommandArgument.Builder<C, UUID> {
107
108        private Builder(final @NonNull String name) {
109            super(UUID.class, name);
110        }
111
112        /**
113         * Builder a new example component
114         *
115         * @return Constructed component
116         */
117        @Override
118        public @NonNull UUIDArgument<C> build() {
119            return new UUIDArgument<>(
120                    this.isRequired(),
121                    this.getName(),
122                    this.getDefaultValue(),
123                    this.getSuggestionsProvider(),
124                    this.getDefaultDescription()
125            );
126        }
127
128    }
129
130
131    public static final class UUIDParser<C> implements ArgumentParser<C, UUID> {
132
133        @Override
134        public @NonNull ArgumentParseResult<UUID> parse(
135                final @NonNull CommandContext<C> commandContext,
136                final @NonNull Queue<@NonNull String> inputQueue
137        ) {
138            final String input = inputQueue.peek();
139            if (input == null) {
140                return ArgumentParseResult.failure(new NoInputProvidedException(
141                        UUIDParser.class,
142                        commandContext
143                ));
144            }
145
146            try {
147                UUID uuid = UUID.fromString(input);
148                inputQueue.remove();
149                return ArgumentParseResult.success(uuid);
150            } catch (IllegalArgumentException e) {
151                return ArgumentParseResult.failure(new UUIDParseException(input, commandContext));
152            }
153        }
154
155        @Override
156        public boolean isContextFree() {
157            return true;
158        }
159
160    }
161
162
163    public static final class UUIDParseException extends ParserException {
164
165        private static final long serialVersionUID = 6399602590976540023L;
166        private final String input;
167
168        /**
169         * Construct a new UUID parse exception
170         *
171         * @param input   String input
172         * @param context Command context
173         */
174        public UUIDParseException(
175                final @NonNull String input,
176                final @NonNull CommandContext<?> context
177        ) {
178            super(
179                    UUIDParser.class,
180                    context,
181                    StandardCaptionKeys.ARGUMENT_PARSE_FAILURE_UUID,
182                    CaptionVariable.of("input", input)
183            );
184            this.input = input;
185        }
186
187        /**
188         * Get the supplied input
189         *
190         * @return String value
191         */
192        public String getInput() {
193            return input;
194        }
195
196    }
197
198}