001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.mappaint.mapcss;
003
004import java.util.Arrays;
005
006import org.openstreetmap.josm.gui.mappaint.Cascade;
007import org.openstreetmap.josm.gui.mappaint.Environment;
008import org.openstreetmap.josm.gui.mappaint.Keyword;
009import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
010import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.IconReference;
011import org.openstreetmap.josm.gui.mappaint.StyleKeys;
012
013public interface Instruction extends StyleKeys {
014
015    void execute(Environment env);
016
017    public static class RelativeFloat {
018        public final float val;
019
020        public RelativeFloat(float val) {
021            this.val = val;
022        }
023
024        @Override
025        public String toString() {
026            return "RelativeFloat{" + "val=" + val + '}';
027        }
028    }
029
030    public static class AssignmentInstruction implements Instruction {
031        public final String key;
032        public final Object val;
033        public final boolean isSetInstruction;
034
035        public AssignmentInstruction(String key, Object val, boolean isSetInstruction) {
036            this.key = key;
037            this.isSetInstruction = isSetInstruction;
038            if (val instanceof LiteralExpression) {
039                Object litValue = ((LiteralExpression) val).evaluate(null);
040                if (key.equals(TEXT)) {
041                    /* Special case for declaration 'text: ...'
042                     *
043                     * - Treat the value 'auto' as keyword.
044                     * - Treat any other literal value 'litval' as as reference to tag with key 'litval'
045                     *
046                     * - Accept function expressions as is. This allows for
047                     *     tag(a_tag_name)                 value of a tag
048                     *     eval("a static text")           a static text
049                     *     parent_tag(a_tag_name)          value of a tag of a parent relation
050                     */
051                    if (litValue.equals(Keyword.AUTO)) {
052                        this.val = Keyword.AUTO;
053                    } else {
054                        String s = Cascade.convertTo(litValue, String.class);
055                        if (s != null) {
056                            this.val = new MapPaintStyles.TagKeyReference(s);
057                        } else {
058                            this.val = litValue;
059                        }
060                    }
061                } else {
062                    this.val = litValue;
063                }
064            } else {
065                this.val = val;
066            }
067        }
068
069        @Override
070        public void execute(Environment env) {
071            Object value = null;
072            if (val instanceof Expression) {
073                value = ((Expression) val).evaluate(env);
074            } else {
075                value = val;
076            }
077            if (key.equals(ICON_IMAGE) || key.equals(FILL_IMAGE) || key.equals(REPEAT_IMAGE)) {
078                if (value instanceof String) {
079                    value = new IconReference((String) value, env.source);
080                }
081            }
082            env.mc.getOrCreateCascade(env.layer).putOrClear(key, value);
083        }
084
085        @Override
086        public String toString() {
087            return key + ": " + (val instanceof float[] ? Arrays.toString((float[]) val) : val instanceof String ? "String<"+val+">" : val) + ';';
088        }
089    }
090}