summaryrefslogtreecommitdiff
path: root/dicore3/command/src/main/java/io/dico/dicore/command/parameter/type/ParameterType.java
blob: d89fd104cc8d5e4473873b1bd726e8e9bb89395d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
package io.dico.dicore.command.parameter.type;

import io.dico.dicore.Reflection;
import io.dico.dicore.command.CommandException;
import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.annotation.Range;
import io.dico.dicore.command.parameter.ArgumentBuffer;
import io.dico.dicore.command.parameter.Parameter;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * A parameter type.
 * Takes care of parsing, default values as well as completions.
 *
 * @param <TReturn>    type of the parameter
 * @param <TParamInfo> the info object type for the parameter (Example: {@link Range.Memory}
 */
public abstract class ParameterType<TReturn, TParamInfo> {
    private final Class<TReturn> returnType;
    private final ParameterConfig<?, TParamInfo> parameterConfig;
    protected final ParameterType<TReturn, TParamInfo> otherType; // flag or non-flag, depending on current

    public ParameterType(Class<TReturn> returnType) {
        this(returnType, null);
    }

    public ParameterType(Class<TReturn> returnType, ParameterConfig<?, TParamInfo> paramConfig) {
        this.returnType = Objects.requireNonNull(returnType);
        this.parameterConfig = paramConfig;

        ParameterType<TReturn, TParamInfo> otherType = flagTypeParameter();
        this.otherType = otherType == null ? this : otherType;
    }

    protected ParameterType(Class<TReturn> returnType, ParameterConfig<?, TParamInfo> parameterConfig, ParameterType<TReturn, TParamInfo> otherType) {
        this.returnType = returnType;
        this.parameterConfig = parameterConfig;
        this.otherType = otherType;
    }

    public int getExpectedAmountOfConsumedArguments() {
        return 1;
    }

    public boolean canBeFlag() {
        return this == otherType;
    }

    public boolean isFlagExplicitly() {
        return this instanceof FlagParameterType;
    }

    /**
     * @return The return type
     */
    public final Class<TReturn> getReturnType() {
        return returnType;
    }

    public final Class<?> getAnnotationClass() {
        return parameterConfig == null ? null : parameterConfig.getAnnotationClass();
    }

    public final ParameterConfig<?, TParamInfo> getParameterConfig() {
        return parameterConfig;
    }

    public ParameterKey getTypeKey() {
        return new ParameterKey(returnType, parameterConfig != null ? parameterConfig.getAnnotationClass() : null);
    }

    public ParameterKey getInfolessTypeKey() {
        return new ParameterKey(returnType, null);
    }

    protected FlagParameterType<TReturn, TParamInfo> flagTypeParameter() {
        return null;
    }

    public ParameterType<TReturn, TParamInfo> asFlagParameter() {
        return canBeFlag() ? this : otherType;
    }

    public ParameterType<TReturn, TParamInfo> asNormalParameter() {
        return isFlagExplicitly() ? otherType : this;
    }

    public abstract TReturn parse(Parameter<TReturn, TParamInfo> parameter, CommandSender sender, ArgumentBuffer buffer) throws CommandException;

    public TReturn parseForContext(Parameter<TReturn, TParamInfo> parameter, ExecutionContext context, ArgumentBuffer buffer) throws CommandException {
        return parse(parameter, context.getSender(), buffer);
    }

    public TReturn getDefaultValue(Parameter<TReturn, TParamInfo> parameter, CommandSender sender, ArgumentBuffer buffer) throws CommandException {
        return null;
    }

    public TReturn getDefaultValueForContext(Parameter<TReturn, TParamInfo> parameter, ExecutionContext context, ArgumentBuffer buffer) throws CommandException {
        return getDefaultValue(parameter, context.getSender(), buffer);
    }

    public List<String> complete(Parameter<TReturn, TParamInfo> parameter, CommandSender sender, Location location, ArgumentBuffer buffer) {
        return Collections.emptyList();
    }

    public List<String> completeForContext(Parameter<TReturn, TParamInfo> parameter, ExecutionContext context, Location location, ArgumentBuffer buffer) {
        return complete(parameter, context.getSender(), location, buffer);
    }

    protected static abstract class FlagParameterType<TResult, TParamInfo> extends ParameterType<TResult, TParamInfo> {

        protected FlagParameterType(ParameterType<TResult, TParamInfo> otherType) {
            super(otherType.returnType, otherType.parameterConfig, otherType);
        }

        @Override
        public int getExpectedAmountOfConsumedArguments() {
            return otherType.getExpectedAmountOfConsumedArguments();
        }

        @Override
        public boolean canBeFlag() {
            return true;
        }

        @Override
        protected final FlagParameterType<TResult, TParamInfo> flagTypeParameter() {
            return this;
        }

        @Override
        public ParameterType<TResult, TParamInfo> asFlagParameter() {
            return this;
        }

        @Override
        public ParameterType<TResult, TParamInfo> asNormalParameter() {
            return otherType;
        }

    }

    public @interface Reference {

        /**
         * The path to the static field holding the parameter type referred.
         *
         * @return The path
         */
        String value();
    }

    public static class ReferenceUtil {

        private ReferenceUtil() {

        }


        /**
         * Get the ParameterType with the associated Reference
         *
         * @param ref the reference
         * @return the parameter type object
         * @throws IllegalArgumentException if the class is found, but the field doesn't exist.
         * @throws IllegalStateException    if this method fails to find the object for any other reason
         */
        public static Object getReference(Reference ref) {
            String[] path = ref.value().split("\\.");
            if (path.length < 2) {
                throw new IllegalStateException();
            }

            String fieldName = path[path.length - 1];
            String className = String.join(".", Arrays.copyOfRange(path, 0, path.length - 1));

            Class<?> clazz;
            try {
                clazz = Class.forName(className);
            } catch (ClassNotFoundException ex) {
                throw new IllegalArgumentException(ex);
            }

            Object result = Reflection.getStaticFieldValue(clazz, fieldName);

            if (result == null) {
                throw new IllegalStateException();
            }

            return result;
        }

    }

}