001package jmri.managers;
002
003import java.time.LocalDateTime;
004import java.util.Arrays;
005import java.util.LinkedList;
006import java.util.List;
007import javax.annotation.Nonnull;
008
009import jmri.*;
010
011/**
012 * Implementation of a TurnoutManager that can serve as a proxy for multiple
013 * system-specific implementations.
014 *
015 * @author Bob Jacobsen Copyright (C) 2003, 2010
016 */
017public class ProxyTurnoutManager extends AbstractProvidingProxyManager<Turnout> implements TurnoutManager {
018
019    public ProxyTurnoutManager() {
020        super();
021    }
022
023    @Override
024    protected AbstractManager<Turnout> makeInternalManager() {
025        return jmri.InstanceManager.getDefault(jmri.jmrix.internal.InternalSystemConnectionMemo.class).getTurnoutManager();
026    }
027
028    /**
029     * {@inheritDoc}
030     */
031    @Override
032    public void addManager(@Nonnull Manager<Turnout> m) {
033        super.addManager(m);
034        InstanceManager.getDefault(TurnoutOperationManager.class).loadOperationTypes();
035    }
036
037    /**
038     * Locate via user name, then system name if needed.
039     *
040     * @return Null if nothing by that name exists
041     */
042    @Override
043    public Turnout getTurnout(@Nonnull String name) {
044        return super.getNamedBean(name);
045    }
046
047    /**
048     * {@inheritDoc}
049     */
050    @Override
051    @Nonnull
052    protected Turnout makeBean(Manager<Turnout> manager, String systemName, String userName) throws IllegalArgumentException {
053        return ((TurnoutManager) manager).newTurnout(systemName, userName);
054    }
055
056    /**
057     * {@inheritDoc}
058     */
059    @Override
060    @Nonnull
061    public Turnout provideTurnout(@Nonnull String name) throws IllegalArgumentException {
062        return super.provideNamedBean(name);
063    }
064
065
066    /** {@inheritDoc} */
067    @Override
068    @Nonnull
069    public Turnout provide(@Nonnull String name) throws IllegalArgumentException { return provideTurnout(name); }
070
071    /**
072     * Get an instance with the specified system and user names. Note that
073     * two calls with the same arguments will get the same instance; there is
074     * only one Sensor object representing a given physical turnout and
075     * therefore only one with a specific system or user name.
076     * <p>
077     * This will always return a valid object reference for a valid request; a
078     * new object will be created if necessary. In that case:
079     * <ul>
080     * <li>If a null reference is given for user name, no user name will be
081     * associated with the Turnout object created; a valid system name must be
082     * provided
083     * <li>If a null reference is given for the system name, a system name will
084     * _somehow_ be inferred from the user name. How this is done is system
085     * specific. Note: a future extension of this interface will add an
086     * exception to signal that this was not possible.
087     * <li>If both names are provided, the system name defines the hardware
088     * access of the desired turnout, and the user address is associated with
089     * it.
090     * </ul>
091     * Note that it is possible to make an inconsistent request if both
092     * addresses are provided, but the given values are associated with
093     * different objects. This is a problem, and we don't have a good solution
094     * except to issue warnings. This will mostly happen if you're creating
095     * Sensors when you should be looking them up.
096     *
097     * @return requested Turnout object (never null)
098     */
099    @Override
100    @Nonnull
101    public Turnout newTurnout(@Nonnull String systemName, String userName) throws IllegalArgumentException {
102        return newNamedBean(systemName, userName);
103    }
104
105    /**
106     * Get text to be used for the Turnout.CLOSED state in user communication.
107     * Allows text other than "CLOSED" to be use with certain hardware system to
108     * represent the Turnout.CLOSED state. Defaults to the primary manager. This
109     * means that the primary manager sets the terminology used. Note: the
110     * primary manager need not override the method in AbstractTurnoutManager if
111     * "CLOSED" is the desired terminology.
112     */
113    @Override
114    @Nonnull
115    public String getClosedText() {
116        return ((TurnoutManager) getDefaultManager()).getClosedText();
117    }
118
119    /**
120     * Get text to be used for the Turnout.THROWN state in user communication.
121     * Allows text other than "THROWN" to be use with certain hardware system to
122     * represent the Turnout.THROWN state. Defaults to the primary manager. This
123     * means that the primary manager sets the terminology used. Note: the
124     * primary manager need not override the method in AbstractTurnoutManager if
125     * "THROWN" is the desired terminology.
126     */
127    @Override
128    @Nonnull
129    public String getThrownText() {
130        return ((TurnoutManager) getDefaultManager()).getThrownText();
131    }
132
133    /**
134     * Get from the user, the number of addressed bits used to control a
135     * turnout. Normally this is 1, and the default routine returns 1
136     * automatically. Turnout Managers for systems that can handle multiple
137     * control bits should override this method with one which asks the user to
138     * specify the number of control bits. If the user specifies more than one
139     * control bit, this method should check if the additional bits are
140     * available (not assigned to another object). If the bits are not
141     * available, this method should return 0 for number of control bits, after
142     * informing the user of the problem.
143     */
144    @Override
145    public int askNumControlBits(@Nonnull String systemName) {
146        return ((TurnoutManager) getManagerOrDefault(systemName)).askNumControlBits(systemName);
147    }
148
149    /**
150     * Get from the user, the type of output to be used bits to control a
151     * turnout. Normally this is 0 for 'steady state' control, and the default
152     * routine returns 0 automatically. Turnout Managers for systems that can
153     * handle pulsed control as well as steady state control should override
154     * this method with one which asks the user to specify the type of control
155     * to be used. The routine should return 0 for 'steady state' control, or n
156     * for 'pulsed' control, where n specifies the duration of the pulse
157     * (normally in seconds).
158     */
159    @Override
160    public int askControlType(@Nonnull String systemName) {
161        return ((TurnoutManager) getManagerOrDefault(systemName)).askControlType(systemName);
162    }
163
164    /**
165     * {@inheritDoc}
166     */
167    @Override
168    public boolean isControlTypeSupported(@Nonnull String systemName) {
169        return ((TurnoutManager) getManagerOrDefault(systemName)).isControlTypeSupported(systemName);
170    }
171
172    /**
173     * {@inheritDoc}
174     */
175    @Override
176    public boolean isNumControlBitsSupported(@Nonnull String systemName) {
177        return ((TurnoutManager) getManagerOrDefault(systemName)).isNumControlBitsSupported(systemName);
178    }
179
180    /** {@inheritDoc} */
181    @Override
182    @Nonnull
183    public String[] getValidOperationTypes() {
184        List<String> typeList = new LinkedList<>();
185        getManagerList().forEach(m -> typeList.addAll(Arrays.asList(((TurnoutManager) m).getValidOperationTypes())));
186        return TurnoutOperationManager.concatenateTypeLists(typeList.toArray(String[]::new));
187    }
188
189    /**
190     * {@inheritDoc}
191     */
192    @Override
193    public boolean allowMultipleAdditions(@Nonnull String systemName) {
194        return ((TurnoutManager) getManagerOrDefault(systemName)).allowMultipleAdditions(systemName);
195    }
196
197    /**
198     * {@inheritDoc}
199     */
200    @Override
201    public void setDefaultClosedSpeed(@Nonnull String speed) throws jmri.JmriException {
202        for (Manager<Turnout> m : getManagerList()) {
203            try {
204                ((TurnoutManager) m).setDefaultClosedSpeed(speed);
205            } catch (jmri.JmriException ex) {
206                log.error("JmriException {}", ex.getMessage() );
207                throw ex;
208            }
209        }
210    }
211
212    /**
213     * {@inheritDoc}
214     */
215    @Override
216    public void setDefaultThrownSpeed(@Nonnull String speed) throws jmri.JmriException {
217        for (Manager<Turnout> m : getManagerList()) {
218            try {
219                ((TurnoutManager) m).setDefaultThrownSpeed(speed);
220            } catch (jmri.JmriException ex) {
221                log.error("JmriException {}", ex.getMessage() );
222                throw ex;
223            }
224        }
225    }
226
227    /**
228     * {@inheritDoc}
229     */
230    @Override
231    public String getDefaultThrownSpeed() {
232        return ((TurnoutManager) getDefaultManager()).getDefaultThrownSpeed();
233    }
234
235    /**
236     * {@inheritDoc}
237     */
238    @Override
239    public String getDefaultClosedSpeed() {
240        return ((TurnoutManager) getDefaultManager()).getDefaultClosedSpeed();
241    }
242
243    /** {@inheritDoc}
244     * @return outputInterval from default TurnoutManager
245     */
246    @Override
247    public int getOutputInterval() {
248        return ((TurnoutManager) getDefaultManager()).getOutputInterval();
249    }
250
251    /**
252     * {@inheritDoc}
253     * This method is only used in jmri.jmrix.internal.InternalTurnoutManagerTest and should not be
254     * used in actual code, as it can overwrite individual per connection values set by the user.
255     */
256    @Override
257    public void setOutputInterval(int newInterval) {
258        log.debug("setOutputInterval called in ProxyTurnoutManager");
259        // only intended for testing; do not set interval via ProxyTurnoutManager in actual code
260        for (Manager<Turnout> manager : getManagerList()) {
261            ((TurnoutManager) manager).setOutputInterval(newInterval);
262        }
263    }
264
265    /**
266     * {@inheritDoc}
267     * @return end time of latest OutputInterval as LocalDateTime from default TurnoutManager
268     */
269    @Nonnull
270    @Override
271    public LocalDateTime outputIntervalEnds() {
272        log.debug("outputIntervalEnds called in ProxyTurnoutManager");
273        return ((TurnoutManager) getDefaultManager()).outputIntervalEnds();
274    }
275
276    /**
277     * {@inheritDoc}
278     */
279    @Override
280    public int getXMLOrder() {
281        return jmri.Manager.TURNOUTS;
282    }
283
284    /**
285     * {@inheritDoc}
286     */
287    @Override
288    @Nonnull
289    public String getBeanTypeHandled(boolean plural) {
290        return Bundle.getMessage(plural ? "BeanNameTurnouts" : "BeanNameTurnout");
291    }
292
293    /**
294     * {@inheritDoc}
295     */
296    @Override
297    public Class<Turnout> getNamedBeanClass() {
298        return Turnout.class;
299    }
300
301    // initialize logging
302    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ProxyTurnoutManager.class);
303
304}