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.selector;
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.CloudBukkitCapabilities;
031import cloud.commandframework.bukkit.arguments.selector.SingleEntitySelector;
032import cloud.commandframework.context.CommandContext;
033import cloud.commandframework.exceptions.parsing.NoInputProvidedException;
034import org.bukkit.Bukkit;
035import org.bukkit.entity.Entity;
036import org.checkerframework.checker.nullness.qual.NonNull;
037import org.checkerframework.checker.nullness.qual.Nullable;
038
039import java.util.List;
040import java.util.Queue;
041import java.util.Set;
042import java.util.function.BiFunction;
043
044public final class SingleEntitySelectorArgument<C> extends CommandArgument<C, SingleEntitySelector> {
045
046    private SingleEntitySelectorArgument(
047            final boolean required,
048            final @NonNull String name,
049            final @NonNull String defaultValue,
050            final @Nullable BiFunction<@NonNull CommandContext<C>, @NonNull String,
051                    @NonNull List<@NonNull String>> suggestionsProvider,
052            final @NonNull ArgumentDescription defaultDescription
053    ) {
054        super(
055                required,
056                name,
057                new SingleEntitySelectorParser<>(),
058                defaultValue,
059                SingleEntitySelector.class,
060                suggestionsProvider,
061                defaultDescription
062        );
063    }
064
065    /**
066     * Create a new builder
067     *
068     * @param name Name of the argument
069     * @param <C>  Command sender type
070     * @return Created builder
071     */
072    public static <C> SingleEntitySelectorArgument.@NonNull Builder<C> newBuilder(final @NonNull String name) {
073        return new SingleEntitySelectorArgument.Builder<>(name);
074    }
075
076    /**
077     * Create a new required command argument
078     *
079     * @param name Argument name
080     * @param <C>  Command sender type
081     * @return Created argument
082     */
083    public static <C> @NonNull CommandArgument<C, SingleEntitySelector> of(final @NonNull String name) {
084        return SingleEntitySelectorArgument.<C>newBuilder(name).asRequired().build();
085    }
086
087    /**
088     * Create a new optional command argument
089     *
090     * @param name Argument name
091     * @param <C>  Command sender type
092     * @return Created argument
093     */
094    public static <C> @NonNull CommandArgument<C, SingleEntitySelector> optional(final @NonNull String name) {
095        return SingleEntitySelectorArgument.<C>newBuilder(name).asOptional().build();
096    }
097
098    /**
099     * Create a new required command argument with a default value
100     *
101     * @param name                  Argument name
102     * @param defaultEntitySelector Default player
103     * @param <C>                   Command sender type
104     * @return Created argument
105     */
106    public static <C> @NonNull CommandArgument<C, SingleEntitySelector> optional(
107            final @NonNull String name,
108            final @NonNull String defaultEntitySelector
109    ) {
110        return SingleEntitySelectorArgument.<C>newBuilder(name).asOptionalWithDefault(defaultEntitySelector).build();
111    }
112
113
114    public static final class Builder<C> extends CommandArgument.Builder<C, SingleEntitySelector> {
115
116        private Builder(final @NonNull String name) {
117            super(SingleEntitySelector.class, name);
118        }
119
120        /**
121         * Builder a new argument
122         *
123         * @return Constructed argument
124         */
125        @Override
126        public @NonNull SingleEntitySelectorArgument<C> build() {
127            return new SingleEntitySelectorArgument<>(this.isRequired(), this.getName(), this.getDefaultValue(),
128                    this.getSuggestionsProvider(), this.getDefaultDescription()
129            );
130        }
131
132    }
133
134
135    public static final class SingleEntitySelectorParser<C> implements ArgumentParser<C, SingleEntitySelector> {
136
137        @Override
138        public @NonNull ArgumentParseResult<SingleEntitySelector> parse(
139                final @NonNull CommandContext<C> commandContext,
140                final @NonNull Queue<@NonNull String> inputQueue
141        ) {
142            if (!commandContext.<Set<CloudBukkitCapabilities>>get("CloudBukkitCapabilities").contains(
143                    CloudBukkitCapabilities.BRIGADIER)) {
144                return ArgumentParseResult.failure(new SelectorParseException(
145                        "",
146                        commandContext,
147                        SelectorParseException.FailureReason.UNSUPPORTED_VERSION,
148                        SingleEntitySelectorParser.class
149                ));
150            }
151            final String input = inputQueue.peek();
152            if (input == null) {
153                return ArgumentParseResult.failure(new NoInputProvidedException(
154                        SingleEntitySelectorParser.class,
155                        commandContext
156                ));
157            }
158            inputQueue.remove();
159
160            List<Entity> entities;
161            try {
162                entities = Bukkit.selectEntities(commandContext.get("BukkitCommandSender"), input);
163            } catch (IllegalArgumentException e) {
164                return ArgumentParseResult.failure(new SelectorParseException(
165                        input,
166                        commandContext,
167                        SelectorParseException.FailureReason.MALFORMED_SELECTOR,
168                        SingleEntitySelectorParser.class
169                ));
170            }
171
172            if (entities.size() > 1) {
173                return ArgumentParseResult.failure(new SelectorParseException(
174                        input,
175                        commandContext,
176                        SelectorParseException.FailureReason.TOO_MANY_ENTITIES,
177                        SingleEntitySelectorParser.class
178                ));
179            }
180
181            return ArgumentParseResult.success(new SingleEntitySelector(input, entities));
182        }
183
184    }
185
186}