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