001/*
002 * PermissionsEx
003 * Copyright (C) zml and PermissionsEx 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 ca.stellardrift.permissionsex.minecraft.command.argument;
018
019import ca.stellardrift.permissionsex.impl.util.PCollections;
020import cloud.commandframework.arguments.parser.ArgumentParseResult;
021import cloud.commandframework.arguments.parser.ArgumentParser;
022import cloud.commandframework.context.CommandContext;
023import cloud.commandframework.exceptions.parsing.NoInputProvidedException;
024import cloud.commandframework.exceptions.parsing.NumberParseException;
025import org.checkerframework.checker.nullness.qual.NonNull;
026import org.checkerframework.checker.nullness.qual.Nullable;
027
028import java.util.List;
029import java.util.Locale;
030import java.util.Map;
031import java.util.Queue;
032
033public final class PermissionValueParser<C> implements ArgumentParser<C, Integer> {
034    private static final Map<String, Integer> CONSTANTS = PCollections.map("true", 1)
035        .plus("yes", 1)
036        .plus("false", -1)
037        .plus("no", -1)
038        .plus("zero", 0)
039        .plus("none", 0)
040        .plus("null", 0)
041        .plus("unset", 0);
042
043    private static final List<String> KEYS = PCollections.asVector(CONSTANTS.keySet());
044
045    PermissionValueParser() {
046    }
047
048    @Override
049    public @NonNull ArgumentParseResult<@NonNull Integer> parse(
050        @NonNull final CommandContext<@NonNull C> commandContext,
051        @NonNull final Queue<@NonNull String> inputQueue
052    ) {
053        final @Nullable String input = inputQueue.peek();
054        if (input == null) {
055            return ArgumentParseResult.failure(new NoInputProvidedException(
056                PermissionValueParser.class,
057                commandContext
058            ));
059        }
060
061        Integer option = CONSTANTS.get(input.toLowerCase(Locale.ROOT));
062        if (option == null) {
063            try {
064                option = Integer.parseInt(input);
065            } catch (final IllegalArgumentException ex) {
066                return ArgumentParseResult.failure(new PermissionValueParseException(input, commandContext));
067            }
068        }
069
070        inputQueue.remove();
071        return ArgumentParseResult.success(option);
072    }
073
074    @Override
075    public @NonNull List<@NonNull String> suggestions(
076        @NonNull final CommandContext<C> commandContext,
077        @NonNull final String input
078    ) {
079        return KEYS; // only suggest the keys
080    }
081
082    @Override
083    public boolean isContextFree() {
084        return true;
085    }
086
087    public static final class PermissionValueParseException extends NumberParseException {
088
089        private static final long serialVersionUID = -3088598808176112429L;
090
091        /**
092         * Construct a new number parse exception
093         *
094         * @param input       Input
095         * @param context     Command context
096         */
097        PermissionValueParseException(
098            @NonNull final String input,
099            @NonNull final CommandContext<?> context
100        ) {
101            super(input, Integer.MIN_VALUE, Integer.MAX_VALUE, PermissionValueParser.class, context);
102        }
103
104        @Override
105        public @NonNull String getNumberType() {
106            return "permission value";
107        }
108
109        @Override
110        public boolean hasMax() {
111            return false;
112        }
113
114        @Override
115        public boolean hasMin() {
116            return false;
117        }
118
119    }
120
121}