001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.mappaint.mapcss;
003
004import java.awt.Color;
005import java.lang.annotation.ElementType;
006import java.lang.annotation.Retention;
007import java.lang.annotation.RetentionPolicy;
008import java.lang.annotation.Target;
009import java.util.Collection;
010import java.util.Collections;
011import java.util.HashMap;
012import java.util.List;
013import java.util.Map;
014import java.util.Objects;
015import java.util.function.BiFunction;
016import java.util.function.DoubleBinaryOperator;
017import java.util.function.DoubleUnaryOperator;
018import java.util.function.Function;
019
020import org.openstreetmap.josm.gui.mappaint.Cascade;
021import org.openstreetmap.josm.gui.mappaint.Environment;
022import org.openstreetmap.josm.tools.SubclassFilteredCollection;
023import org.openstreetmap.josm.tools.Utils;
024
025/**
026 * Factory to generate {@link Expression}s.
027 * <p>
028 * See {@link #createFunctionExpression}.
029 */
030public final class ExpressionFactory {
031
032    /**
033     * Marks functions which should be executed also when one or more arguments are null.
034     */
035    @Target(ElementType.METHOD)
036    @Retention(RetentionPolicy.RUNTIME)
037    @interface NullableArguments {}
038
039    @FunctionalInterface
040    public interface TriFunction<T, U, V, R> {
041        R apply(T t, U u, V v);
042    }
043
044    @FunctionalInterface
045    public interface QuadFunction<T, U, V, W, R> {
046        R apply(T t, U u, V v, W w);
047    }
048
049    @FunctionalInterface
050    interface Factory {
051        Expression createExpression(List<Expression> args);
052
053        static Factory of(DoubleUnaryOperator operator) {
054            return of(Double.class, operator::applyAsDouble);
055        }
056
057        static Factory ofNumberVarArgs(double identity, DoubleUnaryOperator unaryOperator, DoubleBinaryOperator operator) {
058            return args -> env -> {
059                if (args.isEmpty()) {
060                    return identity;
061                } else if (args.size() == 1) {
062                    Double arg = Cascade.convertTo(args.get(0).evaluate(env), Double.class);
063                    return arg == null ? null : unaryOperator.applyAsDouble(arg);
064                } else {
065                    return args.stream()
066                            .map(arg -> Cascade.convertTo(arg.evaluate(env), Double.class))
067                            .filter(Objects::nonNull)
068                            .reduce(operator::applyAsDouble).orElse(null);
069                }
070            };
071        }
072
073        static Factory ofStringVarargs(BiFunction<Environment, String[], ?> function) {
074            return args -> env -> function.apply(env, args.stream()
075                    .map(arg -> Cascade.convertTo(arg.evaluate(env), String.class))
076                    .toArray(String[]::new));
077        }
078
079        static Factory ofObjectVarargs(BiFunction<Environment, Object[], ?> function) {
080            return args -> env -> function.apply(env, args.stream()
081                    .map(arg -> arg.evaluate(env))
082                    .toArray(Object[]::new));
083        }
084
085        static <T> Factory of(Class<T> type, Function<T, ?> function) {
086            return args -> env -> {
087                T v = Cascade.convertTo(args.get(0).evaluate(env), type);
088                return v == null ? null : function.apply(v);
089            };
090        }
091
092        static <T, U> Factory of(Class<T> type1, Class<U> type2, BiFunction<T, U, ?> function) {
093            return args -> env -> {
094                T v1 = Cascade.convertTo(args.get(0).evaluate(env), type1);
095                U v2 = Cascade.convertTo(args.get(1).evaluate(env), type2);
096                return v1 == null || v2 == null ? null : function.apply(v1, v2);
097            };
098        }
099
100        static <T, U, V> Factory of(Class<T> type1, Class<U> type2, Class<V> type3,
101                                    BiFunction<T, U, ?> biFunction, TriFunction<T, U, V, ?> triFunction) {
102            return args -> env -> {
103                T v1 = args.size() >= 1 ? Cascade.convertTo(args.get(0).evaluate(env), type1) : null;
104                U v2 = args.size() >= 2 ? Cascade.convertTo(args.get(1).evaluate(env), type2) : null;
105                V v3 = args.size() >= 3 ? Cascade.convertTo(args.get(2).evaluate(env), type3) : null;
106                return v1 == null || v2 == null ? null : v3 == null ? biFunction.apply(v1, v2) : triFunction.apply(v1, v2, v3);
107            };
108        }
109
110        static <T, U, V, W> Factory of(Class<T> type1, Class<U> type2, Class<V> type3, Class<W> type4,
111                                       QuadFunction<T, U, V, W, ?> function) {
112            return args -> env -> {
113                T v1 = args.size() >= 1 ? Cascade.convertTo(args.get(0).evaluate(env), type1) : null;
114                U v2 = args.size() >= 2 ? Cascade.convertTo(args.get(1).evaluate(env), type2) : null;
115                V v3 = args.size() >= 3 ? Cascade.convertTo(args.get(2).evaluate(env), type3) : null;
116                W v4 = args.size() >= 4 ? Cascade.convertTo(args.get(3).evaluate(env), type4) : null;
117                return v1 == null || v2 == null || v3 == null || v4 == null ? null : function.apply(v1, v2, v3, v4);
118            };
119        }
120
121        static <T> Factory ofEnv(Function<Environment, ?> function) {
122            return args -> function::apply;
123        }
124
125        static <T> Factory ofEnv(Class<T> type, BiFunction<Environment, T, ?> function) {
126            return args -> env -> {
127                T v = Cascade.convertTo(args.get(0).evaluate(env), type);
128                return v == null ? null : function.apply(env, v);
129            };
130        }
131
132        static <T, U> Factory ofEnv(Class<T> type1, Class<U> type2,
133                                    BiFunction<Environment, T, ?> biFunction, TriFunction<Environment, T, U, ?> triFunction) {
134            return args -> env -> {
135                T v1 = args.size() >= 1 ? Cascade.convertTo(args.get(0).evaluate(env), type1) : null;
136                U v2 = args.size() >= 2 ? Cascade.convertTo(args.get(1).evaluate(env), type2) : null;
137                return v1 == null ? null : v2 == null ? biFunction.apply(env, v1) : triFunction.apply(env, v1, v2);
138            };
139        }
140    }
141
142    static final Map<String, Factory> FACTORY_MAP = new HashMap<>();
143
144    static {
145        initFactories();
146    }
147
148    @SuppressWarnings("unchecked")
149    private static void initFactories() {
150        FACTORY_MAP.put("CRC32_checksum", Factory.of(String.class, Functions::CRC32_checksum));
151        FACTORY_MAP.put("JOSM_pref", Factory.ofEnv(String.class, String.class, null, Functions::JOSM_pref));
152        FACTORY_MAP.put("JOSM_search", Factory.ofEnv(String.class, Functions::JOSM_search));
153        FACTORY_MAP.put("URL_decode", Factory.of(String.class, Functions::URL_decode));
154        FACTORY_MAP.put("URL_encode", Factory.of(String.class, Functions::URL_encode));
155        FACTORY_MAP.put("XML_encode", Factory.of(String.class, Functions::XML_encode));
156        FACTORY_MAP.put("abs", Factory.of(Math::acos));
157        FACTORY_MAP.put("acos", Factory.of(Math::acos));
158        FACTORY_MAP.put("alpha", Factory.of(Color.class, Functions::alpha));
159        FACTORY_MAP.put("any", Factory.ofObjectVarargs(Functions::any));
160        FACTORY_MAP.put("areasize", Factory.ofEnv(Functions::areasize));
161        FACTORY_MAP.put("asin", Factory.of(Math::asin));
162        FACTORY_MAP.put("at", Factory.ofEnv(double.class, double.class, null, Functions::at));
163        FACTORY_MAP.put("atan", Factory.of(Math::atan));
164        FACTORY_MAP.put("atan2", Factory.of(Double.class, Double.class, Math::atan2));
165        FACTORY_MAP.put("blue", Factory.of(Color.class, Functions::blue));
166        FACTORY_MAP.put("cardinal_to_radians", Factory.of(String.class, Functions::cardinal_to_radians));
167        FACTORY_MAP.put("ceil", Factory.of(Math::ceil));
168        FACTORY_MAP.put("center", Factory.ofEnv(Functions::center));
169        FACTORY_MAP.put("child_tag", Factory.ofEnv(String.class, Functions::child_tag));
170        FACTORY_MAP.put("color2html", Factory.of(Color.class, Functions::color2html));
171        FACTORY_MAP.put("concat", Factory.ofObjectVarargs(Functions::concat));
172        FACTORY_MAP.put("cos", Factory.of(Math::cos));
173        FACTORY_MAP.put("cosh", Factory.of(Math::cosh));
174        FACTORY_MAP.put("count", Factory.of(List.class, Functions::count));
175        FACTORY_MAP.put("count_roles", Factory.ofStringVarargs(Functions::count_roles));
176        FACTORY_MAP.put("degree_to_radians", Factory.of(Functions::degree_to_radians));
177        FACTORY_MAP.put("divided_by", Factory.ofNumberVarArgs(1.0, DoubleUnaryOperator.identity(), Functions::divided_by));
178        FACTORY_MAP.put("equal", Factory.of(Object.class, Object.class, Functions::equal));
179        FACTORY_MAP.put("eval", Factory.of(Object.class, Functions::eval));
180        FACTORY_MAP.put("exp", Factory.of(Math::exp));
181        FACTORY_MAP.put("floor", Factory.of(Math::floor));
182        FACTORY_MAP.put("get", Factory.of(List.class, float.class, Functions::get));
183        FACTORY_MAP.put("gpx_distance", Factory.ofEnv(Functions::gpx_distance));
184        FACTORY_MAP.put("greater", Factory.of(float.class, float.class, Functions::greater));
185        FACTORY_MAP.put("greater_equal", Factory.of(float.class, float.class, Functions::greater_equal));
186        FACTORY_MAP.put("green", Factory.of(Color.class, Functions::green));
187        FACTORY_MAP.put("has_tag_key", Factory.ofEnv(String.class, Functions::has_tag_key));
188        FACTORY_MAP.put("hsb_color", Factory.of(float.class, float.class, float.class, null, Functions::hsb_color));
189        FACTORY_MAP.put("html2color", Factory.of(String.class, Functions::html2color));
190        FACTORY_MAP.put("index", Factory.ofEnv(Functions::index));
191        FACTORY_MAP.put("inside", Factory.ofEnv(String.class, Functions::inside));
192        FACTORY_MAP.put("is_anticlockwise", Factory.ofEnv(Functions::is_anticlockwise));
193        FACTORY_MAP.put("is_clockwise", Factory.ofEnv(Functions::is_clockwise));
194        FACTORY_MAP.put("is_prop_set", Factory.ofEnv(String.class, String.class, Functions::is_prop_set, Functions::is_prop_set));
195        FACTORY_MAP.put("is_right_hand_traffic", Factory.ofEnv(Functions::is_right_hand_traffic));
196        FACTORY_MAP.put("is_similar", Factory.of(String.class, String.class, Functions::is_similar));
197        FACTORY_MAP.put("join", Factory.ofStringVarargs(Functions::join));
198        FACTORY_MAP.put("join_list", Factory.of(String.class, List.class, Functions::join_list));
199        FACTORY_MAP.put("less", Factory.of(float.class, float.class, Functions::less));
200        FACTORY_MAP.put("less_equal", Factory.of(float.class, float.class, Functions::less_equal));
201        FACTORY_MAP.put("list", Factory.ofObjectVarargs(Functions::list));
202        FACTORY_MAP.put("log", Factory.of(Math::log));
203        FACTORY_MAP.put("lower", Factory.of(String.class, Functions::lower));
204        FACTORY_MAP.put("minus", Factory.ofNumberVarArgs(0.0, v -> -v, Functions::minus));
205        FACTORY_MAP.put("mod", Factory.of(float.class, float.class, Functions::mod));
206        FACTORY_MAP.put("not", Factory.of(boolean.class, Functions::not));
207        FACTORY_MAP.put("not_equal", Factory.of(Object.class, Object.class, Functions::not_equal));
208        FACTORY_MAP.put("number_of_tags", Factory.ofEnv(Functions::number_of_tags));
209        FACTORY_MAP.put("osm_changeset_id", Factory.ofEnv(Functions::osm_changeset_id));
210        FACTORY_MAP.put("osm_id", Factory.ofEnv(Functions::osm_id));
211        FACTORY_MAP.put("osm_timestamp", Factory.ofEnv(Functions::osm_timestamp));
212        FACTORY_MAP.put("osm_user_id", Factory.ofEnv(Functions::osm_user_id));
213        FACTORY_MAP.put("osm_user_name", Factory.ofEnv(Functions::osm_user_name));
214        FACTORY_MAP.put("osm_version", Factory.ofEnv(Functions::osm_version));
215        FACTORY_MAP.put("outside", Factory.ofEnv(String.class, Functions::outside));
216        FACTORY_MAP.put("parent_osm_id", Factory.ofEnv(Functions::parent_osm_id));
217        FACTORY_MAP.put("parent_tag", Factory.ofEnv(String.class, Functions::parent_tag));
218        FACTORY_MAP.put("parent_tags", Factory.ofEnv(String.class, Functions::parent_tags));
219        FACTORY_MAP.put("plus", Factory.ofNumberVarArgs(0.0, DoubleUnaryOperator.identity(), Functions::plus));
220        FACTORY_MAP.put("print", Factory.of(Object.class, Functions::print));
221        FACTORY_MAP.put("println", Factory.of(Object.class, Functions::println));
222        FACTORY_MAP.put("prop", Factory.ofEnv(String.class, String.class, Functions::prop, Functions::prop));
223        FACTORY_MAP.put("red", Factory.of(Color.class, Functions::red));
224        FACTORY_MAP.put("regexp_match", Factory.of(String.class, String.class, String.class, Functions::regexp_match, Functions::regexp_match));
225        FACTORY_MAP.put("regexp_test", Factory.of(String.class, String.class, String.class, Functions::regexp_test, Functions::regexp_test));
226        FACTORY_MAP.put("replace", Factory.of(String.class, String.class, String.class, null, Functions::replace));
227        FACTORY_MAP.put("rgb", Factory.of(float.class, float.class, float.class, null, Functions::rgb));
228        FACTORY_MAP.put("rgba", Factory.of(float.class, float.class, float.class, float.class, Functions::rgba));
229        FACTORY_MAP.put("role", Factory.ofEnv(Functions::role));
230        FACTORY_MAP.put("round", Factory.of(Math::round));
231        FACTORY_MAP.put("setting", Factory.ofEnv(String.class, Functions::setting));
232        FACTORY_MAP.put("signum", Factory.of(Math::signum));
233        FACTORY_MAP.put("sin", Factory.of(Math::sin));
234        FACTORY_MAP.put("sinh", Factory.of(Math::sinh));
235        FACTORY_MAP.put("sort", Factory.ofStringVarargs(Functions::sort));
236        FACTORY_MAP.put("sort_list", Factory.of(List.class, Functions::sort_list));
237        FACTORY_MAP.put("split", Factory.of(String.class, String.class, Functions::split));
238        FACTORY_MAP.put("sqrt", Factory.of(Math::sqrt));
239        FACTORY_MAP.put("substring", Factory.of(String.class, float.class, float.class, Functions::substring, Functions::substring));
240        FACTORY_MAP.put("tag", Factory.ofEnv(String.class, Functions::tag));
241        FACTORY_MAP.put("tag_regex", Factory.ofEnv(String.class, String.class, Functions::tag_regex, Functions::tag_regex));
242        FACTORY_MAP.put("tan", Factory.of(Math::tan));
243        FACTORY_MAP.put("tanh", Factory.of(Math::tanh));
244        FACTORY_MAP.put("times", Factory.ofNumberVarArgs(1.0, DoubleUnaryOperator.identity(), Functions::times));
245        FACTORY_MAP.put("title", Factory.of(String.class, Functions::title));
246        FACTORY_MAP.put("to_boolean", Factory.of(String.class, Functions::to_boolean));
247        FACTORY_MAP.put("to_byte", Factory.of(String.class, Functions::to_byte));
248        FACTORY_MAP.put("to_double", Factory.of(String.class, Functions::to_double));
249        FACTORY_MAP.put("to_float", Factory.of(String.class, Functions::to_float));
250        FACTORY_MAP.put("to_int", Factory.of(String.class, Functions::to_int));
251        FACTORY_MAP.put("to_long", Factory.of(String.class, Functions::to_long));
252        FACTORY_MAP.put("to_short", Factory.of(String.class, Functions::to_short));
253        FACTORY_MAP.put("tr", Factory.ofStringVarargs(Functions::tr));
254        FACTORY_MAP.put("trim", Factory.of(String.class, Functions::trim));
255        FACTORY_MAP.put("trim_list", Factory.of(List.class, Functions::trim_list));
256        FACTORY_MAP.put("uniq", Factory.ofStringVarargs(Functions::uniq));
257        FACTORY_MAP.put("uniq_list", Factory.of(List.class, Functions::uniq_list));
258        FACTORY_MAP.put("upper", Factory.of(String.class, Functions::upper));
259        FACTORY_MAP.put("waylength", Factory.ofEnv(Functions::waylength));
260    }
261
262    private ExpressionFactory() {
263        // Hide default constructor for utils classes
264    }
265
266    /**
267     * Main method to create an function-like expression.
268     *
269     * @param name the name of the function or operator
270     * @param args the list of arguments (as expressions)
271     * @return the generated Expression. If no suitable function can be found,
272     * returns {@link NullExpression#INSTANCE}.
273     */
274    public static Expression createFunctionExpression(String name, List<Expression> args) {
275        if ("cond".equals(name) && args.size() == 3)
276            return new CondOperator(args.get(0), args.get(1), args.get(2));
277        else if ("and".equals(name))
278            return new AndOperator(args);
279        else if ("or".equals(name))
280            return new OrOperator(args);
281        else if ("length".equals(name) && args.size() == 1)
282            return new LengthFunction(args.get(0));
283        else if ("max".equals(name) && !args.isEmpty())
284            return new MinMaxFunction(args, true);
285        else if ("min".equals(name) && !args.isEmpty())
286            return new MinMaxFunction(args, false);
287        else if ("inside".equals(name) && args.size() == 1)
288            return new IsInsideFunction(args.get(0));
289        else if ("random".equals(name))
290            return env -> Math.random();
291
292        Factory factory = FACTORY_MAP.get(name);
293        if (factory != null) {
294            return factory.createExpression(args);
295        }
296        return NullExpression.INSTANCE;
297    }
298
299    /**
300     * Expression that always evaluates to null.
301     */
302    public static class NullExpression implements Expression {
303
304        /**
305         * The unique instance.
306         */
307        public static final NullExpression INSTANCE = new NullExpression();
308
309        @Override
310        public Object evaluate(Environment env) {
311            return null;
312        }
313    }
314
315    /**
316     * Conditional operator.
317     */
318    public static class CondOperator implements Expression {
319
320        private final Expression condition, firstOption, secondOption;
321
322        /**
323         * Constructs a new {@code CondOperator}.
324         * @param condition condition
325         * @param firstOption first option
326         * @param secondOption second option
327         */
328        public CondOperator(Expression condition, Expression firstOption, Expression secondOption) {
329            this.condition = condition;
330            this.firstOption = firstOption;
331            this.secondOption = secondOption;
332        }
333
334        @Override
335        public Object evaluate(Environment env) {
336            Boolean b = Cascade.convertTo(condition.evaluate(env), boolean.class);
337            if (b != null && b)
338                return firstOption.evaluate(env);
339            else
340                return secondOption.evaluate(env);
341        }
342    }
343
344    /**
345     * "And" logical operator.
346     */
347    public static class AndOperator implements Expression {
348
349        private final List<Expression> args;
350
351        /**
352         * Constructs a new {@code AndOperator}.
353         * @param args arguments
354         */
355        public AndOperator(List<Expression> args) {
356            this.args = args;
357        }
358
359        @Override
360        public Object evaluate(Environment env) {
361            return args.stream()
362                    .map(arg -> Cascade.convertTo(arg.evaluate(env), boolean.class))
363                    .allMatch(Boolean.TRUE::equals);
364        }
365    }
366
367    /**
368     * "Or" logical operator.
369     */
370    public static class OrOperator implements Expression {
371
372        private final List<Expression> args;
373
374        /**
375         * Constructs a new {@code OrOperator}.
376         * @param args arguments
377         */
378        public OrOperator(List<Expression> args) {
379            this.args = args;
380        }
381
382        @Override
383        public Object evaluate(Environment env) {
384            return args.stream()
385                    .map(arg -> Cascade.convertTo(arg.evaluate(env), boolean.class))
386                    .anyMatch(Boolean.TRUE::equals);
387        }
388    }
389
390    /**
391     * Function to calculate the length of a string or list in a MapCSS eval expression.
392     *
393     * Separate implementation to support overloading for different argument types.
394     *
395     * The use for calculating the length of a list is deprecated, use
396     * {@link Functions#count(java.util.List)} instead (see #10061).
397     */
398    public static class LengthFunction implements Expression {
399
400        private final Expression arg;
401
402        /**
403         * Constructs a new {@code LengthFunction}.
404         * @param args arguments
405         */
406        public LengthFunction(Expression args) {
407            this.arg = args;
408        }
409
410        @Override
411        public Object evaluate(Environment env) {
412            List<?> l = Cascade.convertTo(arg.evaluate(env), List.class);
413            if (l != null)
414                return l.size();
415            String s = Cascade.convertTo(arg.evaluate(env), String.class);
416            if (s != null)
417                return s.length();
418            return null;
419        }
420    }
421
422    /**
423     * Computes the maximum/minimum value an arbitrary number of floats, or a list of floats.
424     */
425    public static class MinMaxFunction implements Expression {
426
427        private final List<Expression> args;
428        private final boolean computeMax;
429
430        /**
431         * Constructs a new {@code MinMaxFunction}.
432         * @param args arguments
433         * @param computeMax if {@code true}, compute max. If {@code false}, compute min
434         */
435        public MinMaxFunction(final List<Expression> args, final boolean computeMax) {
436            this.args = args;
437            this.computeMax = computeMax;
438        }
439
440        /**
441         * Compute the minimum / maximum over the list
442         * @param lst The list
443         * @return The minimum or maximum depending on {@link #computeMax}
444         */
445        public Float aggregateList(List<?> lst) {
446            final List<Float> floats = Utils.transform(lst, (Function<Object, Float>) x -> Cascade.convertTo(x, float.class));
447            final Collection<Float> nonNullList = SubclassFilteredCollection.filter(floats, Objects::nonNull);
448            return nonNullList.isEmpty() ? (Float) Float.NaN : computeMax ? Collections.max(nonNullList) : Collections.min(nonNullList);
449        }
450
451        @Override
452        public Object evaluate(final Environment env) {
453            List<?> l = Cascade.convertTo(args.get(0).evaluate(env), List.class);
454            if (args.size() != 1 || l == null)
455                l = Utils.transform(args, (Function<Expression, Object>) x -> x.evaluate(env));
456            return aggregateList(l);
457        }
458    }
459
460    /**
461     * {@code Functions#inside} implementation for use in {@link org.openstreetmap.josm.data.validation.tests.MapCSSTagChecker}
462     *
463     * @see Functions#inside
464     */
465    public static class IsInsideFunction implements Expression {
466        private final Expression arg;
467
468        /**
469         * Constructs a new {@code IsInsideFunction}.
470         * @param arg argument
471         */
472        public IsInsideFunction(Expression arg) {
473            this.arg = arg;
474        }
475
476        /**
477         * Returns the argument
478         * @return the argument
479         */
480        public Expression getArg() {
481            return arg;
482        }
483
484        @Override
485        public Object evaluate(Environment env) {
486            String codes = Cascade.convertTo(arg.evaluate(env), String.class);
487            return Functions.inside(env, codes);
488        }
489    }
490}