001/*
002 * Copyright (c) 2016-2017 Daniel Ennis (Aikar) - MIT License
003 *
004 *  Permission is hereby granted, free of charge, to any person obtaining
005 *  a copy of this software and associated documentation files (the
006 *  "Software"), to deal in the Software without restriction, including
007 *  without limitation the rights to use, copy, modify, merge, publish,
008 *  distribute, sublicense, and/or sell copies of the Software, and to
009 *  permit persons to whom the Software is furnished to do so, subject to
010 *  the following conditions:
011 *
012 *  The above copyright notice and this permission notice shall be
013 *  included in all copies or substantial portions of the Software.
014 *
015 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
016 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
017 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
018 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
019 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
020 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
021 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
022 */
023
024package co.aikar.commands;
025
026import co.aikar.commands.contexts.ContextResolver;
027
028import java.lang.annotation.Annotation;
029import java.lang.reflect.Parameter;
030import java.util.List;
031import java.util.Map;
032
033@SuppressWarnings({"WeakerAccess", "unused"})
034public class CommandExecutionContext <CEC extends CommandExecutionContext, I extends CommandIssuer> {
035    private final RegisteredCommand cmd;
036    private final CommandParameter param;
037    protected final I issuer;
038    private final List<String> args;
039    private final int index;
040    private final Map<String, Object> passedArgs;
041    private final Map<String, String> flags;
042    private final CommandManager manager;
043
044    CommandExecutionContext(RegisteredCommand cmd, CommandParameter param, I sender, List<String> args,
045                            int index, Map<String, Object> passedArgs) {
046        this.cmd = cmd;
047        this.manager = cmd.scope.manager;
048        this.param = param;
049        this.issuer = sender;
050        this.args = args;
051        this.index = index;
052        this.passedArgs = passedArgs;
053        this.flags = param.getFlags();
054
055    }
056
057    public String popFirstArg() {
058        return !args.isEmpty() ? args.remove(0) : null;
059    }
060
061    public String popLastArg() {
062        return !args.isEmpty() ? args.remove(args.size() - 1) : null;
063    }
064
065    public String getFirstArg() {
066        return !args.isEmpty() ? args.get(0) : null;
067    }
068
069    public String getLastArg() {
070        return !args.isEmpty() ? args.get(args.size() - 1) : null;
071    }
072
073    public boolean isLastArg() {
074        return cmd.parameters.length -1 == index;
075    }
076
077    public int getNumParams() {
078        return cmd.parameters.length;
079    }
080
081    public boolean canOverridePlayerContext() {
082        return cmd.requiredResolvers >= args.size();
083    }
084
085    public Object getResolvedArg(String arg) {
086        return passedArgs.get(arg);
087    }
088
089    public Object getResolvedArg(Class<?>... classes) {
090        for (Class<?> clazz : classes) {
091            for (Object passedArg : passedArgs.values()) {
092                if (clazz.isInstance(passedArg)) {
093                    return passedArg;
094                }
095            }
096        }
097
098        return null;
099    }
100
101    public <T> T getResolvedArg(String key, Class<?>... classes) {
102        final Object o = passedArgs.get(key);
103        for (Class<?> clazz : classes) {
104            if (clazz.isInstance(o)) {
105                //noinspection unchecked
106                return (T) o;
107            }
108        }
109
110        return null;
111    }
112
113    public boolean isOptional() {
114        return param.isOptional();
115    }
116
117    public boolean hasFlag(String flag) {
118        return flags.containsKey(flag);
119    }
120
121    public String getFlagValue(String flag, String def) {
122        return flags.getOrDefault(flag, def);
123    }
124
125    public Integer getFlagValue(String flag, Integer def) {
126        return ACFUtil.parseInt(this.flags.get(flag), def);
127    }
128
129    public Long getFlagValue(String flag, Long def) {
130        return ACFUtil.parseLong(this.flags.get(flag), def);
131    }
132
133    public Float getFlagValue(String flag, Float def) {
134        return ACFUtil.parseFloat(this.flags.get(flag), def);
135    }
136
137    public Double getFlagValue(String flag, Double def) {
138        return ACFUtil.parseDouble(this.flags.get(flag), def);
139    }
140
141    public Integer getIntFlagValue(String flag, Number def) {
142        return ACFUtil.parseInt(this.flags.get(flag), def != null ? def.intValue() : null);
143    }
144
145    public Long getLongFlagValue(String flag, Number def) {
146        return ACFUtil.parseLong(this.flags.get(flag), def != null ? def.longValue() : null);
147    }
148
149    public Float getFloatFlagValue(String flag, Number def) {
150        return ACFUtil.parseFloat(this.flags.get(flag), def != null ? def.floatValue() : null);
151    }
152
153    public Double getDoubleFlagValue(String flag, Number def) {
154        return ACFUtil.parseDouble(this.flags.get(flag), def != null ? def.doubleValue() : null);
155    }
156
157    public Boolean getBooleanFlagValue(String flag) {
158        return getBooleanFlagValue(flag, false);
159    }
160
161    public Boolean getBooleanFlagValue(String flag, Boolean def) {
162        String val = this.flags.get(flag);
163        if (val == null) {
164            return def;
165        }
166        return ACFUtil.isTruthy(val);
167    }
168
169    public Double getFlagValue(String flag, Number def) {
170        return ACFUtil.parseDouble(this.flags.get(flag), def != null ? def.doubleValue() : null);
171    }
172
173    /**
174     * This method will not support annotation processors!! use getAnnotationValue or hasAnnotation
175     * @deprecated Use {@link #getAnnotationValue(Class)}
176     */
177    @Deprecated
178    public <T extends Annotation> T getAnnotation(Class<T> cls) {
179        return param.getParameter().getAnnotation(cls);
180    }
181
182    public <T extends Annotation> String getAnnotationValue(Class<T> cls) {
183        return manager.getAnnotations().getAnnotationValue(param.getParameter(), cls);
184    }
185
186    public <T extends Annotation> String getAnnotationValue(Class<T> cls, int options) {
187        return manager.getAnnotations().getAnnotationValue(param.getParameter(), cls, options);
188    }
189
190    public <T extends Annotation> boolean hasAnnotation(Class<T> cls) {
191        return manager.getAnnotations().hasAnnotation(param.getParameter(), cls);
192    }
193
194    public RegisteredCommand getCmd() {
195        return this.cmd;
196    }
197
198    @UnstableAPI
199    CommandParameter getCommandParameter() {
200        return this.param;
201    }
202
203    @Deprecated
204    public Parameter getParam() {
205        return this.param.getParameter();
206    }
207
208    public I getIssuer() {
209        return this.issuer;
210    }
211
212    public List<String> getArgs() {
213        return this.args;
214    }
215
216    public int getIndex() {
217        return this.index;
218    }
219
220    public Map<String, Object> getPassedArgs() {
221        return this.passedArgs;
222    }
223
224    public Map<String, String> getFlags() {
225        return this.flags;
226    }
227
228    public String joinArgs() {
229        return ACFUtil.join(args, " ");
230    }
231    public String joinArgs(String sep) {
232        return ACFUtil.join(args, sep);
233    }
234}