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    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    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 (litValue instanceof Keyword && "none".equals(((Keyword) litValue).val)) {
041                    this.val = null;
042                } else if (TEXT.equals(key)) {
043                    /* Special case for declaration 'text: ...'
044                     *
045                     * - Treat the value 'auto' as keyword.
046                     * - Treat any other literal value 'litval' as as reference to tag with key 'litval'
047                     *
048                     * - Accept function expressions as is. This allows for
049                     *     tag(a_tag_name)                 value of a tag
050                     *     eval("a static text")           a static text
051                     *     parent_tag(a_tag_name)          value of a tag of a parent relation
052                     */
053                    if (litValue.equals(Keyword.AUTO)) {
054                        this.val = Keyword.AUTO;
055                    } else {
056                        String s = Cascade.convertTo(litValue, String.class);
057                        if (s != null) {
058                            this.val = new MapPaintStyles.TagKeyReference(s);
059                        } else {
060                            this.val = litValue;
061                        }
062                    }
063                } else {
064                    this.val = litValue;
065                }
066            } else {
067                this.val = val;
068            }
069        }
070
071        @Override
072        public void execute(Environment env) {
073            Object value = null;
074            if (val instanceof Expression) {
075                value = ((Expression) val).evaluate(env);
076            } else {
077                value = val;
078            }
079            if (ICON_IMAGE.equals(key) || FILL_IMAGE.equals(key) || REPEAT_IMAGE.equals(key)) {
080                if (value instanceof String) {
081                    value = new IconReference((String) value, env.source);
082                }
083            }
084            env.mc.getOrCreateCascade(env.layer).putOrClear(key, value);
085        }
086
087        @Override
088        public String toString() {
089            return key + ": " + (val instanceof float[] ? Arrays.toString((float[]) val) :
090                val instanceof String ? "String<"+val+'>' : val) + ';';
091        }
092    }
093}