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     * String constant for the property allocatedTo, fired when the value
110     * returned by {@link #getAllocatedTo()} changes.
111     */
112    String PROPERTY_ALLOCATED_TO = "allocatedTo";
113
114    /**
115     * Provide generic access to internal state.
116     * <p>
117     * This generally shouldn't be used by Java code; use the class-specific
118     * form instead (e.g. setCommandedState in Turnout). This is provided to
119     * make scripts access easier to read.
120     * <p>
121     * This isn't an exact override because it doesn't throw JmriException
122     *
123     * @param newState the state
124     */
125    @Override
126    void setState(int newState);
127
128    /**
129     * Get the occupancy of a Section.
130     *
131     * @return {@link #OCCUPIED}, {@link #UNOCCUPIED}, or the state of the first
132     *         block that is neither occupied or unoccupied
133     */
134    int getOccupancy();
135
136    String getForwardBlockingSensorName();
137
138    @CheckForNull
139    Sensor getForwardBlockingSensor();
140
141    Sensor setForwardBlockingSensorName(String forwardSensor);
142
143    void delayedSetForwardBlockingSensorName(String forwardSensor);
144
145    String getReverseBlockingSensorName();
146
147    Sensor setReverseBlockingSensorName(String reverseSensor);
148
149    void delayedSetReverseBlockingSensorName(String reverseSensor);
150
151    @CheckForNull
152    Sensor getReverseBlockingSensor();
153
154    @CheckForNull
155    Block getLastBlock();
156
157    String getForwardStoppingSensorName();
158
159    @CheckForNull
160    Sensor getForwardStoppingSensor();
161
162    Sensor setForwardStoppingSensorName(String forwardSensor);
163
164    void delayedSetForwardStoppingSensorName(String forwardSensor);
165
166    String getReverseStoppingSensorName();
167
168    @CheckForNull
169    Sensor setReverseStoppingSensorName(String reverseSensor);
170
171    void delayedSetReverseStoppingSensorName(String reverseSensor);
172
173    @CheckForNull
174    Sensor getReverseStoppingSensor();
175
176    /**
177     * Add a Block to the Section. Block and sequence number must be unique
178     * within the Section. Block sequence numbers are set automatically as
179     * blocks are added.
180     *
181     * @param b the block to add
182     * @return true if Block was added or false if Block does not connect to the
183     *         current Block, or the Block is not unique.
184     */
185    boolean addBlock(Block b);
186
187    void delayedAddBlock(String blockName);
188
189    /**
190     * Get a list of blocks in this section
191     *
192     * @return a list of blocks
193     */
194    @Nonnull
195    List<Block> getBlockList();
196
197    /**
198     * Gets the number of Blocks in this Section
199     *
200     * @return the number of blocks
201     */
202    int getNumBlocks();
203
204    /**
205     * Get the scale length of Section. Length of the Section is calculated by
206     * summing the lengths of all Blocks in the section. If all Block lengths
207     * have not been entered, length will not be correct.
208     *
209     * @param meters true to return length in meters, false to use feet
210     * @param scale  the scale; one of {@link jmri.Scale}
211     * @return the scale length
212     */
213    float getLengthF(boolean meters, Scale scale);
214
215    int getLengthI(boolean meters, Scale scale);
216
217    /**
218     * Gets the actual length of the Section without any scaling
219     *
220     * @return the real length in millimeters
221     */
222    int getActualLength();
223
224    /**
225     * Get Block by its Sequence number in the Section.
226     *
227     * @param seqNumber the sequence number
228     * @return the block or null if the sequence number is invalid
229     */
230    @CheckForNull
231    Block getBlockBySequenceNumber(int seqNumber);
232
233    /**
234     * Get the sequence number of a Block.
235     *
236     * @param b the block to get the sequence of
237     * @return the sequence number of b or -1 if b is not in the Section
238     */
239    int getBlockSequenceNumber(Block b);
240
241    /**
242     * Remove all Blocks, Block Listeners, and Entry Points
243     */
244    void removeAllBlocksFromSection();
245
246    @CheckForNull
247    Block getEntryBlock();
248
249    @CheckForNull
250    Block getNextBlock();
251
252    @CheckForNull
253    Block getExitBlock();
254
255    boolean containsBlock(Block b);
256
257    boolean connectsToBlock(Block b);
258
259    String getBeginBlockName();
260
261    String getEndBlockName();
262
263    void addToForwardList(EntryPoint ep);
264
265    void addToReverseList(EntryPoint ep);
266
267    void removeEntryPoint(EntryPoint ep);
268
269    @Nonnull
270    List<EntryPoint> getForwardEntryPointList();
271
272    @Nonnull
273    List<EntryPoint> getReverseEntryPointList();
274
275    @Nonnull
276    List<EntryPoint> getEntryPointList();
277
278    boolean isForwardEntryPoint(EntryPoint ep);
279
280    boolean isReverseEntryPoint(EntryPoint ep);
281
282    /**
283     * Get the EntryPoint for entry from the specified Section for travel in
284     * specified direction.
285     *
286     * @param s   the section
287     * @param dir the direction of travel; one of {@link #FORWARD} or
288     *            {@link #REVERSE}
289     * @return the entry point or null if not found
290     */
291    @CheckForNull
292    EntryPoint getEntryPointFromSection(Section s, int dir);
293
294    /**
295     * Get the EntryPoint for exit to specified Section for travel in the
296     * specified direction.
297     *
298     * @param s   the section
299     * @param dir the direction of travel; one of {@link #FORWARD} or
300     *            {@link #REVERSE}
301     * @return the entry point or null if not found
302     */
303    @CheckForNull
304    EntryPoint getExitPointToSection(Section s, int dir);
305
306    /**
307     * Get the EntryPoint for entry from the specified Block for travel in the
308     * specified direction.
309     *
310     * @param b   the block
311     * @param dir the direction of travel; one of {@link #FORWARD} or
312     *            {@link #REVERSE}
313     * @return the entry point or null if not found
314     */
315    @CheckForNull
316    EntryPoint getEntryPointFromBlock(Block b, int dir);
317
318    /**
319     * Get the EntryPoint for exit to the specified Block for travel in the
320     * specified direction.
321     *
322     * @param b   the block
323     * @param dir the direction of travel; one of {@link #FORWARD} or
324     *            {@link #REVERSE}
325     * @return the entry point or null if not found
326     */
327    @CheckForNull
328    EntryPoint getExitPointToBlock(Block b, int dir);
329
330    /**
331     * Place direction sensors in SSL for all Signal Heads in this Section if
332     * the Sensors are not already present in the SSL.
333     * <p>
334     * Only anchor point block boundaries that have assigned signals are
335     * considered. Only turnouts that have assigned signals are considered. Only
336     * level crossings that have assigned signals are considered. Turnouts and
337     * anchor points without signals are counted, and reported in warning
338     * messages during this procedure, if there are any missing signals.
339     * <p>
340     * If this method has trouble, an error message is placed in the log
341     * describing the trouble.
342     *
343     * @return the number or errors placing sensors; 1 is returned if no
344     *         direction sensor is defined for this section
345     */
346    int placeDirectionSensors();
347
348    /**
349     * Validate the Section. This checks block connectivity, warns of redundant
350     * EntryPoints, and otherwise checks internal consistency of the Section. An
351     * appropriate error message is logged if a problem is found. This method
352     * assumes that Block Paths are correctly initialized.
353     *
354     * @return an error description or empty string if there are no errors
355     */
356    String validate();
357
358    /**
359     * Set/reset the display to use alternate color for unoccupied blocks in
360     * this section. If Layout Editor panel is not present, Layout Blocks will
361     * not be present, and nothing will be set.
362     *
363     * @param set true to use alternate unoccupied color; false otherwise
364     */
365    void setAlternateColor(boolean set);
366
367    /**
368     * Set/reset the display to use alternate color for unoccupied blocks in
369     * this Section. If the Section already contains an active block, then the
370     * alternative color will be set from the active block, if no active block
371     * is found or we are clearing the alternative color then all the blocks in
372     * the Section will be set. If Layout Editor panel is not present, Layout
373     * Blocks will not be present, and nothing will be set.
374     *
375     * @param set true to use alternate unoccupied color; false otherwise
376     */
377    void setAlternateColorFromActiveBlock(boolean set);
378
379    /**
380     * Set the block values for blocks in this Section.
381     *
382     * @param name the value to set all blocks to
383     */
384    void setNameInBlocks(String name);
385
386    /**
387     * Set the block values for blocks in this Section.
388     *
389     * @param value the name to set block values to
390     */
391    void setNameInBlocks(Object value);
392
393    void setNameFromActiveBlock(Object value);
394
395    /**
396     * Clear the block values for blocks in this Section.
397     */
398    void clearNameInUnoccupiedBlocks();
399
400    /**
401     * Suppress the update of a memory variable when a block goes to unoccupied,
402     * so the text set above doesn't get wiped out.
403     *
404     * @param set true to suppress the update; false otherwise
405     */
406    void suppressNameUpdate(boolean set);
407
408    @SuppressWarnings("hiding")     // Field has same name as a field in the super class
409    enum SectionType {
410        DYNAMICADHOC,   // Created on an as required basis, not to be saved.
411        USERDEFINED,    // Default Save all the information
412        SIGNALMASTLOGIC // Save only the name, blocks will be added by the signalmast logic
413    }
414    SectionType USERDEFINED     = SectionType.USERDEFINED;
415    SectionType SIGNALMASTLOGIC = SectionType.SIGNALMASTLOGIC;
416    SectionType DYNAMICADHOC    = SectionType.DYNAMICADHOC;
417
418    /**
419     * Set Section Type.
420     * <ul>
421     * <li>USERDEFINED - Default Save all the information.
422     * <li>SIGNALMASTLOGIC - Save only the name, blocks will be added by the SignalMast logic.
423     * <li>DYNAMICADHOC - Created on an as required basis, not to be saved.
424     * </ul>
425     * @param type constant of section type.
426     */
427    void setSectionType(SectionType type);
428
429    /**
430     * Get Section Type.
431     * Defaults to USERDEFINED.
432     * @return constant of section type.
433     */
434    SectionType getSectionType();
435
436    /**
437     * Get who this Section is allocated to, for example the Dispatcher train
438     * holding it. Signal Mast Logic uses this to tell a block reserved for the
439     * train approaching a mast from one reserved for another train.
440     *
441     * @return the holder, or null if the Section is not allocated or the
442     *         holder is not known
443     */
444    default Object getAllocatedTo() {
445        return null;
446    }
447
448    /**
449     * Set who this Section is allocated to. Holders are compared by identity.
450     * The holder is cleared when the Section is set {@link #FREE}.
451     *
452     * @param holder the holder, or null when the Section is released
453     */
454    default void setAllocatedTo(Object holder) {
455    }
456
457}