001package jmri;
002
003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
004
005import java.beans.*;
006import java.util.ArrayList;
007import java.util.List;
008
009import javax.annotation.CheckForNull;
010import javax.annotation.Nonnull;
011
012import jmri.jmrit.display.layoutEditor.LayoutEditor;
013
014/**
015 * Sections represent a group of one or more connected Blocks that may be
016 * allocated to a train traveling in a given direction.
017 * <p>
018 * A Block may be in multiple Sections. All Blocks contained in a given section
019 * must be unique. Blocks are kept in order--the first block is connected to the
020 * second, the second is connected to the third, etc.
021 * <p>
022 * A Block in a Section must be connected to the Block before it (if there is
023 * one) and to the Block after it (if there is one), but may not be connected to
024 * any other Block in the Section. This restriction is enforced when a Section
025 * is created, and checked when a Section is loaded from disk.
026 * <p>
027 * A Section has a "direction" defined by the sequence in which Blocks are added
028 * to the Section. A train may run through a Section in either the forward
029 * direction (from first block to last block) or reverse direction (from last
030 * block to first block).
031 * <p>
032 * A Section has one or more EntryPoints. Each EntryPoint is a Path of one of
033 * the Blocks in the Section that defines a connection to a Block outside of the
034 * Section. EntryPoints are grouped into two lists: "forwardEntryPoints" - entry
035 * through which will result in a train traveling in the "forward" direction
036 * "reverseEntryPoints" - entry through which will result in a train traveling
037 * in the "reverse" direction Note that "forwardEntryPoints" are also reverse
038 * exit points, and vice versa.
039 * <p>
040 * A Section has one of the following states" FREE - available for allocation by
041 * a dispatcher FORWARD - allocated for travel in the forward direction REVERSE
042 * - allocated for travel in the reverse direction
043 * <p>
044 * A Section has an occupancy. A Section is OCCUPIED if any of its Blocks is
045 * OCCUPIED. A Section is UNOCCUPIED if all of its Blocks are UNOCCUPIED
046 * <p>
047 * A Section of may be allocated to only one train at a time, even if the trains
048 * are travelling in the same direction. If a Section has sufficient space for
049 * multiple trains travelling in the same direction it should be broken up into
050 * multiple Sections so the trains can follow each other through the original
051 * Section.
052 * <p>
053 * A Section may not contain any reverse loops. The track that is reversed in a
054 * reverse loop must be in a separate Section.
055 * <p>
056 * Each Section optionally carries two direction sensors, one for the forward
057 * direction and one for the reverse direction. These sensors force signals for
058 * travel in their respective directions to "RED" when they are active. When the
059 * Section is free, both the sensors are Active. These internal sensors follow
060 * the state of the Section, permitting signals to function normally in the
061 * direction of allocation.
062 * <p>
063 * Each Section optionally carries two stopping sensors, one for the forward
064 * direction and one for the reverse direction. These sensors change to active
065 * when a train traversing the Section triggers its sensing device. Stopping
066 * sensors are physical layout sensors, and may be either point sensors or
067 * occupancy sensors for short blocks at the end of the Section. A stopping
068 * sensor is used during automatic running to stop a train that has reached the
069 * end of its allocated Section. This is needed, for example, to allow a train
070 * to enter a passing siding and clear the track behind it. When not running
071 * automatically, these sensors may be used to light panel lights to notify the
072 * dispatcher that the train has reached the end of the Section.
073 * <p>
074 * This Section implementation provides for delayed initialization of blocks and
075 * direction sensors to be independent of order of items in panel files.
076 *
077 * @author Dave Duchamp  Copyright (C) 2008,2010
078 * @author Bob Jacobsen  Copyright (C) 2022
079 */
080public interface Section extends NamedBean {
081
082    /**
083     * The value of {@link #getState()} if section is available for allocation.
084     */
085    public static final int FREE = 0x02;
086
087    /**
088     * The value of {@link #getState()} if section is allocated for travel in
089     * the forward direction.
090     */
091    public static final int FORWARD = 0x04;
092
093    /**
094     * The value of {@link #getState()} if section is allocated for travel in
095     * the reverse direction.
096     */
097    public static final int REVERSE = 0X08;
098
099    /**
100     * Value representing an occupied section.
101     */
102    public static final int OCCUPIED = Block.OCCUPIED;
103
104    /**
105     * Value representing an unoccupied section.
106     */
107    public static final int UNOCCUPIED = Block.UNOCCUPIED;
108
109    /**
110     * Provide generic access to internal state.
111     * <p>
112     * This generally shouldn't be used by Java code; use the class-specific
113     * form instead (e.g. setCommandedState in Turnout). This is provided to
114     * make scripts access easier to read.
115     * <p>
116     * This isn't an exact override because it doesn't throw JmriException
117     *
118     * @param newState the state
119     */
120    @Override
121    public void setState(int newState);
122
123    /**
124     * Get the occupancy of a Section.
125     *
126     * @return {@link #OCCUPIED}, {@link #UNOCCUPIED}, or the state of the first
127     *         block that is neither occupied or unoccupied
128     */
129    public int getOccupancy();
130
131    public String getForwardBlockingSensorName();
132
133    public Sensor getForwardBlockingSensor();
134
135    public Sensor setForwardBlockingSensorName(String forwardSensor);
136
137    public void delayedSetForwardBlockingSensorName(String forwardSensor);
138
139    public String getReverseBlockingSensorName();
140
141    public Sensor setReverseBlockingSensorName(String reverseSensor);
142
143    public void delayedSetReverseBlockingSensorName(String reverseSensor);
144
145    public Sensor getReverseBlockingSensor();
146
147    public Block getLastBlock();
148
149    public String getForwardStoppingSensorName();
150
151    @CheckForNull
152    public Sensor getForwardStoppingSensor();
153
154    public Sensor setForwardStoppingSensorName(String forwardSensor);
155
156    public void delayedSetForwardStoppingSensorName(String forwardSensor);
157
158    public String getReverseStoppingSensorName();
159
160    @CheckForNull
161    public Sensor setReverseStoppingSensorName(String reverseSensor);
162
163    public void delayedSetReverseStoppingSensorName(String reverseSensor);
164
165    @CheckForNull
166    public Sensor getReverseStoppingSensor();
167
168    /**
169     * Add a Block to the Section. Block and sequence number must be unique
170     * within the Section. Block sequence numbers are set automatically as
171     * blocks are added.
172     *
173     * @param b the block to add
174     * @return true if Block was added or false if Block does not connect to the
175     *         current Block, or the Block is not unique.
176     */
177    public boolean addBlock(Block b);
178
179    public void delayedAddBlock(String blockName);
180
181    /**
182     * Get a list of blocks in this section
183     *
184     * @return a list of blocks
185     */
186    @Nonnull
187    public List<Block> getBlockList();
188
189    /**
190     * Gets the number of Blocks in this Section
191     *
192     * @return the number of blocks
193     */
194    public int getNumBlocks();
195
196    /**
197     * Get the scale length of Section. Length of the Section is calculated by
198     * summing the lengths of all Blocks in the section. If all Block lengths
199     * have not been entered, length will not be correct.
200     *
201     * @param meters true to return length in meters, false to use feet
202     * @param scale  the scale; one of {@link jmri.Scale}
203     * @return the scale length
204     */
205    public float getLengthF(boolean meters, Scale scale);
206
207    public int getLengthI(boolean meters, Scale scale);
208
209    /**
210     * Gets the actual length of the Section without any scaling
211     *
212     * @return the real length in millimeters
213     */
214    public int getActualLength();
215
216    /**
217     * Get Block by its Sequence number in the Section.
218     *
219     * @param seqNumber the sequence number
220     * @return the block or null if the sequence number is invalid
221     */
222    @CheckForNull
223    public Block getBlockBySequenceNumber(int seqNumber);
224
225    /**
226     * Get the sequence number of a Block.
227     *
228     * @param b the block to get the sequence of
229     * @return the sequence number of b or -1 if b is not in the Section
230     */
231    public int getBlockSequenceNumber(Block b);
232
233    /**
234     * Remove all Blocks, Block Listeners, and Entry Points
235     */
236    public void removeAllBlocksFromSection();
237
238    @CheckForNull
239    public Block getEntryBlock();
240
241    @CheckForNull
242    public Block getNextBlock();
243
244    @CheckForNull
245    public Block getExitBlock();
246
247    public boolean containsBlock(Block b);
248
249    public boolean connectsToBlock(Block b);
250
251    public String getBeginBlockName();
252
253    public String getEndBlockName();
254
255    public void addToForwardList(EntryPoint ep);
256
257    public void addToReverseList(EntryPoint ep);
258
259    public void removeEntryPoint(EntryPoint ep);
260
261    public List<EntryPoint> getForwardEntryPointList();
262
263    public List<EntryPoint> getReverseEntryPointList();
264
265    public List<EntryPoint> getEntryPointList();
266
267    public boolean isForwardEntryPoint(EntryPoint ep);
268
269    public boolean isReverseEntryPoint(EntryPoint ep);
270
271    /**
272     * Get the EntryPoint for entry from the specified Section for travel in
273     * specified direction.
274     *
275     * @param s   the section
276     * @param dir the direction of travel; one of {@link #FORWARD} or
277     *            {@link #REVERSE}
278     * @return the entry point or null if not found
279     */
280    @CheckForNull
281    public EntryPoint getEntryPointFromSection(Section s, int dir);
282
283    /**
284     * Get the EntryPoint for exit to specified Section for travel in the
285     * specified direction.
286     *
287     * @param s   the section
288     * @param dir the direction of travel; one of {@link #FORWARD} or
289     *            {@link #REVERSE}
290     * @return the entry point or null if not found
291     */
292    @CheckForNull
293    public EntryPoint getExitPointToSection(Section s, int dir);
294
295    /**
296     * Get the EntryPoint for entry from the specified Block for travel in the
297     * specified direction.
298     *
299     * @param b   the block
300     * @param dir the direction of travel; one of {@link #FORWARD} or
301     *            {@link #REVERSE}
302     * @return the entry point or null if not found
303     */
304    @CheckForNull
305    public EntryPoint getEntryPointFromBlock(Block b, int dir);
306
307    /**
308     * Get the EntryPoint for exit to the specified Block for travel in the
309     * specified direction.
310     *
311     * @param b   the block
312     * @param dir the direction of travel; one of {@link #FORWARD} or
313     *            {@link #REVERSE}
314     * @return the entry point or null if not found
315     */
316    @CheckForNull
317    public EntryPoint getExitPointToBlock(Block b, int dir);
318
319    /**
320     * Place direction sensors in SSL for all Signal Heads in this Section if
321     * the Sensors are not already present in the SSL.
322     * <p>
323     * Only anchor point block boundaries that have assigned signals are
324     * considered. Only turnouts that have assigned signals are considered. Only
325     * level crossings that have assigned signals are considered. Turnouts and
326     * anchor points without signals are counted, and reported in warning
327     * messages during this procedure, if there are any missing signals.
328     * <p>
329     * If this method has trouble, an error message is placed in the log
330     * describing the trouble.
331     *
332     * @return the number or errors placing sensors; 1 is returned if no
333     *         direction sensor is defined for this section
334     */
335    public int placeDirectionSensors();
336
337    /**
338     * Validate the Section. This checks block connectivity, warns of redundant
339     * EntryPoints, and otherwise checks internal consistency of the Section. An
340     * appropriate error message is logged if a problem is found. This method
341     * assumes that Block Paths are correctly initialized.
342     *
343     * @return an error description or empty string if there are no errors
344     */
345    public String validate();
346
347    /**
348     * Set/reset the display to use alternate color for unoccupied blocks in
349     * this section. If Layout Editor panel is not present, Layout Blocks will
350     * not be present, and nothing will be set.
351     *
352     * @param set true to use alternate unoccupied color; false otherwise
353     */
354    public void setAlternateColor(boolean set);
355
356    /**
357     * Set/reset the display to use alternate color for unoccupied blocks in
358     * this Section. If the Section already contains an active block, then the
359     * alternative color will be set from the active block, if no active block
360     * is found or we are clearing the alternative color then all the blocks in
361     * the Section will be set. If Layout Editor panel is not present, Layout
362     * Blocks will not be present, and nothing will be set.
363     *
364     * @param set true to use alternate unoccupied color; false otherwise
365     */
366    public void setAlternateColorFromActiveBlock(boolean set);
367
368    /**
369     * Set the block values for blocks in this Section.
370     *
371     * @param name the value to set all blocks to
372     */
373    public void setNameInBlocks(String name);
374
375    /**
376     * Set the block values for blocks in this Section.
377     *
378     * @param value the name to set block values to
379     */
380    public void setNameInBlocks(Object value);
381
382    public void setNameFromActiveBlock(Object value);
383
384    /**
385     * Clear the block values for blocks in this Section.
386     */
387    public void clearNameInUnoccupiedBlocks();
388
389    /**
390     * Suppress the update of a memory variable when a block goes to unoccupied,
391     * so the text set above doesn't get wiped out.
392     *
393     * @param set true to suppress the update; false otherwise
394     */
395    public void suppressNameUpdate(boolean set);
396
397    enum SectionType {
398        DYNAMICADHOC,   // Created on an as required basis, not to be saved.
399        USERDEFINED,    // Default Save all the information
400        SIGNALMASTLOGIC // Save only the name, blocks will be added by the signalmast logic
401    }
402    final public static SectionType USERDEFINED     = SectionType.USERDEFINED;
403    final public static SectionType SIGNALMASTLOGIC = SectionType.SIGNALMASTLOGIC;
404    final public static SectionType DYNAMICADHOC    = SectionType.DYNAMICADHOC;
405
406    /**
407     * Set Section Type.
408     * <ul>
409     * <li>USERDEFINED - Default Save all the information.
410     * <li>SIGNALMASTLOGIC - Save only the name, blocks will be added by the SignalMast logic.
411     * <li>DYNAMICADHOC - Created on an as required basis, not to be saved.
412     * </ul>
413     * @param type constant of section type.
414     */
415    public void setSectionType(SectionType type);
416
417    /**
418     * Get Section Type.
419     * Defaults to USERDEFINED.
420     * @return constant of section type.
421     */
422    public SectionType getSectionType();
423
424}