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