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