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