001package jmri;
002
003import java.time.LocalDateTime;
004import javax.annotation.Nonnull;
005import javax.annotation.CheckForNull;
006
007/**
008 * Locate a Turnout object representing some specific turnout on the layout.
009 * <p>
010 * Turnout objects are obtained from a TurnoutManager, which in turn is
011 * generally located from the InstanceManager. A typical call sequence might be:
012 * <pre>
013 * Turnout turnout = InstanceManager.turnoutManagerInstance().provideTurnout("23");
014 * </pre>
015 * <p>
016 * Each turnout has a two names. The "user" name is entirely free form, and can
017 * be used for any purpose. The "system" name is provided by the system-specific
018 * implementations, and provides a unique mapping to the layout control system
019 * (for example LocoNet or NCE) and address within that system.
020 * <p>
021 * Much of the book-keeping is implemented in the AbstractTurnoutManager class,
022 * which can form the basis for a system-specific implementation.
023 * <p>
024 * A sample use of the TurnoutManager interface can be seen in the
025 * jmri.jmrit.simpleturnoutctrl.SimpleTurnoutCtrlFrame class, which provides a
026 * simple GUI for controlling a single turnout.
027 *
028 * <p>
029 * This file is part of JMRI.
030 * <p>
031 * JMRI is free software; you can redistribute it and/or modify it under the
032 * terms of version 2 of the GNU General Public License as published by the Free
033 * Software Foundation. See the "COPYING" file for a copy of this license.
034 * <p>
035 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY
036 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
037 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
038 *
039 * @author Bob Jacobsen Copyright (C) 2001
040 * @see jmri.Turnout
041 * @see jmri.InstanceManager
042 * @see jmri.jmrit.simpleturnoutctrl.SimpleTurnoutCtrlFrame
043 */
044public interface TurnoutManager extends ProvidingManager<Turnout>, NameIncrementingManager {
045
046    /**
047     * Get the Turnout with the user name, then system name if needed; if that fails, create a
048     * new Turnout.
049     * If the name is a valid system name, it will be used for the new Turnout.
050     * Otherwise, the {@link Manager#makeSystemName} method will attempt to turn it
051     * into a valid system name.
052     * <p>
053     * This provides the same function as {@link ProvidingManager#provide}
054     * which has a more generic form.
055     *
056     * @param name User name, system name, or address which can be promoted to
057     *             system name
058     * @return Never null
059     * @throws IllegalArgumentException if Turnout doesn't already exist and the
060     *                                  manager cannot create the Turnout due to
061     *                                  an illegal name or name that can't
062     *                                  be parsed.
063     */
064    @Nonnull
065    Turnout provideTurnout(@Nonnull String name) throws IllegalArgumentException;
066
067    /** {@inheritDoc} */
068    @Override
069    @Nonnull
070    default Turnout provide(@Nonnull String name) throws IllegalArgumentException { return provideTurnout(name); }
071
072    /**
073     * Get an existing Turnout or return null if it doesn't exist.
074     *
075     * Locates via user name, then system name if needed.
076     *
077     * @param name User name or system name to match
078     * @return null if no match found
079     */
080    @CheckForNull
081    Turnout getTurnout(@Nonnull String name);
082
083    /**
084     * Get the Turnout with the given system name or null if no instance
085     * already exists.
086     *
087     * @param systemName the system name
088     * @return requested Turnout object or null if none exists
089     */
090    @CheckForNull
091    @Override
092    Turnout getBySystemName(@Nonnull String systemName);
093
094    /**
095     * Get the Turnout with the given user name or null if no instance
096     * already exists.
097     *
098     * @param userName the user name
099     * @return requested Turnout object or null if none exists
100     */
101    @CheckForNull
102    @Override
103    Turnout getByUserName(@Nonnull String userName);
104
105    /**
106     * Return a Turnout with the specified system and user names.
107     * Lookup by UserName then provide by System Name.
108     * <p>
109     * Note that
110     * two calls with the same arguments will get the same instance; there is
111     * only one Turnout object representing a given physical turnout and
112     * therefore only one with a specific system or user name.
113     * <p>
114     * This will always return a valid object reference; a new object will be
115     * created if necessary. In that case:
116     * <ul>
117     * <li>If a null reference is given for user name, no user name will be
118     * associated with the Turnout object created; a valid system name must be
119     * provided
120     * <li>If both names are provided, the system name defines the hardware
121     * access of the desired turnout, and the user address is associated with
122     * it. The system name must be valid.
123     * </ul>
124     * Note that it is possible to make an inconsistent request if both
125     * addresses are provided, but the given values are associated with
126     * different objects. This is a problem, and we don't have a good solution
127     * except to issue warnings. This will mostly happen if you're creating
128     * Turnouts when you should be looking them up.
129     *
130     * @param systemName the system name
131     * @param userName   the user name (optional)
132     * @return requested Turnout object, newly created if needed
133     * @throws IllegalArgumentException if cannot create the Turnout; likely due
134     *                                  to an illegal name or name that cannot
135     *                                  be parsed
136     */
137    @Nonnull
138    Turnout newTurnout(@Nonnull String systemName, @CheckForNull String userName) throws IllegalArgumentException;
139
140    /**
141     * Get text to be used for the Turnout.CLOSED state in user communication.
142     * Allows text other than "CLOSED" to be used with certain hardware system
143     * to represent the Turnout.CLOSED state.
144     *
145     * @return the textual representation of {@link jmri.Turnout#CLOSED}
146     */
147    @Nonnull
148    String getClosedText();
149
150    /**
151     * Get text to be used for the Turnout.THROWN state in user communication.
152     * Allows text other than "THROWN" to be use with certain hardware system to
153     * represent the Turnout.THROWN state.
154     *
155     * @return the textual representation of {@link jmri.Turnout#THROWN}
156     */
157    @Nonnull
158    String getThrownText();
159
160    /**
161     * Get a list of the valid TurnoutOperation subtypes for use with turnouts
162     * of this system.
163     *
164     * @return a list of subtypes or an empty list if turnout operations are not
165     *         supported
166     */
167    @Nonnull
168    String[] getValidOperationTypes();
169
170    /**
171     * Get, from the user, the number of addressed bits used to control a
172     * turnout. Normally this is 1, and the default routine returns one
173     * automatically. Turnout Managers for systems that can handle multiple
174     * control bits should override this method with one which asks the user to
175     * specify the number of control bits. If the user specifies more than one
176     * control bit, this method should check if the additional bits are
177     * available (not assigned to another object). If the bits are not
178     * available, this method should return 0 for number of control bits, after
179     * informing the user of the problem.
180     *
181     * @param systemName the turnout system name
182     * @return the bit length for turnout control
183     */
184    int askNumControlBits(@Nonnull String systemName);
185
186    /**
187     * Determine if the manager supports multiple control bits, as
188     * {@link #askNumControlBits(java.lang.String)} will always return a value
189     * even if it is not supported.
190     *
191     * @param systemName the turnout system name
192     * @return true if manager supports multiple control bits for the turnout;
193     *         false otherwise
194     */
195    boolean isNumControlBitsSupported(@Nonnull String systemName);
196
197    /**
198     * Get, from the user, the type of output to be used bits to control a
199     * turnout. Normally this is 0 for 'steady state' control, and the default
200     * routine returns 0 automatically. Turnout Managers for systems that can
201     * handle pulsed control as well as steady state control should override
202     * this method with one which asks the user to specify the type of control
203     * to be used. The routine should return 0 for 'steady state' control, or n
204     * for 'pulsed' control, where n specifies the duration of the pulse
205     * (normally in seconds).
206     *
207     * @param systemName the turnout system name
208     * @return 0 for steady state or the number of seconds for a pulse control
209     */
210    int askControlType(@Nonnull String systemName);
211
212    /**
213     * Determine if the manager supports the handling of pulsed and steady state
214     * control as the {@link #askControlType(java.lang.String)} will always
215     * return a value even if it is not supported.
216     *
217     * @param systemName the turnout system name
218     * @return true if manager supports the control type returned by
219     *         {@link #askControlType(java.lang.String)}; false otherwise
220     *
221     */
222    boolean isControlTypeSupported(@Nonnull String systemName);
223
224    /**
225     * Get a system name for a given hardware address and system prefix.
226     *
227     * @param curAddress desired hardware address
228     * @param prefix     system prefix used in system name
229     * @return the complete turnout system name for the prefix and current
230     *         address
231     * @throws jmri.JmriException if unable to create a system name for the
232     *                            given address, possibly due to invalid address
233     *                            format
234     */
235    String createSystemName(@Nonnull String curAddress, @Nonnull String prefix) throws JmriException;
236
237    void setDefaultClosedSpeed(@Nonnull String speed) throws JmriException;
238
239    void setDefaultThrownSpeed(@Nonnull String speed) throws JmriException;
240
241    String getDefaultThrownSpeed();
242
243    String getDefaultClosedSpeed();
244
245    /**
246     * Get the Interval (in ms) to wait between output commands.
247     * Configured in AdapterConfig, stored in memo.
248     *
249     * @return the (Turnout) Output Interval in milliseconds
250     */
251    int getOutputInterval();
252
253    /**
254     * Set the Interval (in ms) to wait between output commands.
255     *
256     * @param newInterval the new Output Interval in Milliseconds
257     */
258    void setOutputInterval(int newInterval);
259
260    /**
261     * Get end time of latest OutputInterval, calculated from the current time.
262     *
263     * @return end time in milliseconds or current time if no interval was set or timer has completed
264     */
265    @Nonnull
266    LocalDateTime outputIntervalEnds();
267
268}