001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.mappaint;
003
004import org.openstreetmap.josm.data.osm.OsmPrimitive;
005import org.openstreetmap.josm.data.osm.Relation;
006import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context;
007import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.LinkSelector;
008import org.openstreetmap.josm.tools.CheckParameterUtil;
009
010/**
011 * Environment is a data object to provide access to various "global" parameters.
012 * It is used during processing of MapCSS rules and for the generation of
013 * style elements.
014 */
015public class Environment {
016
017    public OsmPrimitive osm;
018
019    public MultiCascade mc;
020    public String layer;
021    public StyleSource source;
022    private Context context = Context.PRIMITIVE;
023    public static final String DEFAULT_LAYER = "default";
024
025    /**
026     * If not null, this is the matching parent object if a condition or an expression
027     * is evaluated in a {@link LinkSelector} (within a child selector)
028     */
029    public OsmPrimitive parent;
030
031    /**
032     * The same for parent selector. Only one of the 2 fields (parent or child) is not null in any environment.
033     */
034    public OsmPrimitive child;
035
036    /**
037     * index of node in parent way or member in parent relation. Must be != null in LINK context.
038     */
039    public Integer index = null;
040
041    /**
042     * Creates a new uninitialized environment.
043     */
044    public Environment() {}
045
046    /**
047     * Creates a new environment.
048     */
049    public Environment(OsmPrimitive osm, MultiCascade mc, String layer, StyleSource source) {
050        this.osm = osm;
051        this.mc = mc;
052        this.layer = layer;
053        this.source = source;
054    }
055
056    /**
057     * Creates a clone of the environment {@code other}.
058     *
059     * @param other the other environment. Must not be null.
060     * @throws IllegalArgumentException if {@code param} is {@code null}
061     */
062    public Environment(Environment other) throws IllegalArgumentException {
063        CheckParameterUtil.ensureParameterNotNull(other);
064        this.osm = other.osm;
065        this.mc = other.mc;
066        this.layer = other.layer;
067        this.parent = other.parent;
068        this.child = other.child;
069        this.source = other.source;
070        this.index = other.index;
071        this.context = other.getContext();
072    }
073
074    /**
075     * Creates a clone of this environment, with the specified primitive.
076     * @return A clone of this environment, with the specified primitive
077     * @see #osm
078     */
079    public Environment withPrimitive(OsmPrimitive osm) {
080        Environment e = new Environment(this);
081        e.osm = osm;
082        return e;
083    }
084
085    /**
086     * Creates a clone of this environment, with the specified parent.
087     * @param parent the matching parent object
088     * @return A clone of this environment, with the specified parent
089     * @see #parent
090     */
091    public Environment withParent(OsmPrimitive parent) {
092        Environment e = new Environment(this);
093        e.parent = parent;
094        return e;
095    }
096
097    /**
098     * Creates a clone of this environment, with the specified parent, index, and context set to {@link Context#LINK}.
099     * @param parent the matching parent object
100     * @param index index of node in parent way or member in parent relation
101     * @return A clone of this environment, with the specified parent, index, and context set to {@link Context#LINK}
102     * @since 6175
103     * @see #parent
104     * @see #index
105     */
106    public Environment withParentAndIndexAndLinkContext(OsmPrimitive parent, int index) {
107        Environment e = new Environment(this);
108        e.parent = parent;
109        e.index = index;
110        e.context = Context.LINK;
111        return e;
112    }
113
114    /**
115     * Creates a clone of this environment, with the specified child.
116     * @param child the matching child object
117     * @return A clone of this environment, with the specified child
118     * @see #child
119     */
120    public Environment withChild(OsmPrimitive child) {
121        Environment e = new Environment(this);
122        e.child = child;
123        return e;
124    }
125
126    /**
127     * Creates a clone of this environment, with the specified child, index, and context set to {@link Context#LINK}.
128     * @param child the matching child object
129     * @param index index of node in parent way or member in parent relation
130     * @return A clone of this environment, with the specified child, index, and context set to {@code Context#LINK}
131     * @since 6175
132     * @see #child
133     * @see #index
134     */
135    public Environment withChildAndIndexAndLinkContext(OsmPrimitive child, int index) {
136        Environment e = new Environment(this);
137        e.child = child;
138        e.index = index;
139        e.context = Context.LINK;
140        return e;
141    }
142
143    /**
144     * Creates a clone of this environment, with the specified index.
145     * @param index index of node in parent way or member in parent relation
146     * @return A clone of this environment, with the specified index
147     * @see #index
148     */
149    public Environment withIndex(int index) {
150        Environment e = new Environment(this);
151        e.index = index;
152        return e;
153    }
154
155    /**
156     * Creates a clone of this environment, with the specified {@link Context}.
157     * @return A clone of this environment, with the specified {@code Context}
158     */
159    public Environment withContext(Context context) {
160        Environment e = new Environment(this);
161        e.context = context == null ? Context.PRIMITIVE : context;
162        return e;
163    }
164
165    /**
166     * Creates a clone of this environment, with context set to {@link Context#LINK}.
167     * @return A clone of this environment, with context set to {@code Context#LINK}
168     */
169    public Environment withLinkContext() {
170        Environment e = new Environment(this);
171        e.context = Context.LINK;
172        return e;
173    }
174
175    /**
176     * Determines if the context of this environment is {@link Context#LINK}.
177     * @return {@code true} if the context of this environment is {@code Context#LINK}, {@code false} otherwise
178     */
179    public boolean isLinkContext() {
180        return Context.LINK.equals(context);
181    }
182
183    /**
184     * Determines if this environment has a relation as parent.
185     * @return {@code true} if this environment has a relation as parent, {@code false} otherwise
186     * @see #parent
187     */
188    public boolean hasParentRelation() {
189        return parent instanceof Relation;
190    }
191
192    /**
193     * Replies the current context.
194     *
195     * @return the current context
196     */
197    public Context getContext() {
198        return context == null ? Context.PRIMITIVE : context;
199    }
200
201    public String getRole() {
202        if (getContext().equals(Context.PRIMITIVE))
203            return null;
204
205        if (parent instanceof Relation)
206            return ((Relation) parent).getMember(index).getRole();
207        if (child != null && osm instanceof Relation)
208            return ((Relation) osm).getMember(index).getRole();
209        return null;
210    }
211
212    public void clearSelectorMatchingInformation() {
213        parent = null;
214        child = null;
215        index = null;
216    }
217
218    public Cascade getCascade(String layer) {
219        return mc == null ? null : mc.getCascade(layer == null ? this.layer : layer);
220    }
221}