001package jmri;
002
003import java.beans.PropertyChangeListener;
004import java.util.EnumSet;
005
006/**
007 * Interface for allocating {@link Throttle} objects.
008 * <p>
009 * "Address" is interpreted in the context of the DCC implementation. Different
010 * systems will distinguish between short and long addresses in different ways.
011 * <p>
012 * When the allocated Throttle is no longer needed, it is told that it's
013 * released. If a specific ThrottleManager and/or Throttle implementation needs
014 * to keep track of that operation, it is handled internally.
015 *
016 * <hr>
017 * This file is part of JMRI.
018 * <p>
019 * JMRI is free software; you can redistribute it and/or modify it under the
020 * terms of version 2 of the GNU General Public License as published by the Free
021 * Software Foundation. See the "COPYING" file for a copy of this license.
022 * <p>
023 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY
024 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
025 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
026 *
027 * @author Glen Oberhauser
028 * @author Bob Jacobsen Copyright 2006
029 */
030public interface ThrottleManager {
031
032    /**
033     * Request a throttle from a given RosterEntry. When the decoder address is
034     * located, the ThrottleListener gets a callback via the
035     * ThrottleListener.notifyThrottleFound method.
036     *
037     * @param re desired RosterEntry
038     * @param l  ThrottleListener awaiting notification of a found throttle
039     * @param canHandleDecisions true if the ThrottleListener has a mechanism for dealing with
040     *        Share / Steal decisions, else false
041     * @return true if the request will continue, false if the request will not
042     *         be made; false may be returned if a the throttle is already in
043     *         use
044     */
045    boolean requestThrottle(BasicRosterEntry re, ThrottleListener l, boolean canHandleDecisions);
046
047
048    /**
049     * Request a throttle, given a decoder address. When the decoder address is
050     * located, the ThrottleListener gets a callback via the
051     * ThrottleListener.notifyThrottleFound method.
052     * <p>
053     * This is a convenience version of the call, which uses system-specific
054     * logic to tell whether the address is a short or long form,
055     * and assumes that the hardware makes and steal / share decisions.
056     *
057     * @param address desired decoder address
058     * @param l       ThrottleListener awaiting notification of a found throttle
059     * @return true if the request will continue, false if the request will not
060     *         be made; false may be returned if a the throttle is already in
061     *         use
062     */
063    boolean requestThrottle(int address, ThrottleListener l);
064
065    /**
066     * Request a throttle, given a decoder address. When the decoder address is
067     * located, the ThrottleListener gets a callback via the
068     * ThrottleListener.notifyThrottleFound method.
069     * <p>
070     * This is a convenience version of the call, which uses system-specific
071     * logic to tell whether the address is a short or long form,
072     * and assumes that the hardware makes and steal / share decisions.
073     * @param canHandleDecisions true if the ThrottleListener has a mechanism for dealing with
074     *        Share / Steal decisions, else false
075     * @param address desired decoder address
076     * @param l       ThrottleListener awaiting notification of a found throttle
077     
078     * @return true if the request will continue, false if the request will not
079     *         be made; false may be returned if a the throttle is already in
080     *         use
081     */
082    boolean requestThrottle(int address, ThrottleListener l, boolean canHandleDecisions);
083
084    /**
085     * Request a throttle, given a decoder address and whether it is a long or
086     * short DCC address. When the decoder address is located, the
087     * ThrottleListener gets a callback via the
088     * ThrottleListener.notifyThrottleFound method.
089     *
090     * @param address desired decoder address
091     * @param isLong  true if requesting a DCC long (extended) address
092     * @param l       ThrottleListener awaiting notification of a found throttle
093     * @param canHandleDecisions true if the ThrottleListener has a mechanism for dealing with
094     *                Share / Steal decisions, else false
095     * @return true if the request will continue, false if the request will not
096     *         be made; false may be returned if a the throttle is already in
097     *         use
098     */
099    boolean requestThrottle(int address, boolean isLong, ThrottleListener l, boolean canHandleDecisions);
100
101    /**
102     * Request a throttle, given a LocoAddress. When the address is
103     * located, the ThrottleListener gets a callback via the
104     * ThrottleListener.notifyThrottleFound method.
105     *
106     * @param address desired loco address
107     * @param l       ThrottleListener awaiting notification of a found throttle
108     * @param canHandleDecisions true if the ThrottleListener has a mechanism for dealing with
109     *        Share / Steal decisions, else false
110     * @return true if the request will continue, false if the request will not
111     *         be made; false may be returned if a the throttle is already in
112     *         use
113     */
114    boolean requestThrottle(LocoAddress address, ThrottleListener l, boolean canHandleDecisions);
115    
116    /**
117     * Cancel a request for a throttle.
118     * <p>
119     * This is a convenience version of the call, which uses system-specific
120     * logic to tell whether the address is a short or long form.
121     *
122     * @param re desired Roster Entry
123     * @param l  ThrottleListener canceling the request for a throttle
124     */
125    void cancelThrottleRequest(BasicRosterEntry re, ThrottleListener l);
126    
127    /**
128     * Cancel a request for a throttle.
129     * <p>
130     * This is a convenience version of the call, which uses system-specific
131     * logic to tell whether the address is a short or long form.
132     *
133     * @param address desired decoder address
134     * @param l       ThrottleListener canceling request for a throttle
135     */
136    void cancelThrottleRequest(int address, ThrottleListener l);
137    
138    /**
139     * Cancel a request for a throttle.
140     *
141     * @param address desired decoder address
142     * @param isLong  true if requesting a DCC long (extended) address
143     * @param l       ThrottleListener canceling request for a throttle
144     */
145    void cancelThrottleRequest(int address, boolean isLong, ThrottleListener l);
146    
147    /**
148     * Cancel a request for a throttle.
149     *
150     * @param address unwanted Loco address
151     * @param l       ThrottleListener canceling request for a throttle
152     */
153    void cancelThrottleRequest(LocoAddress address, ThrottleListener l);
154
155    /**
156     * Steal or Share a requested throttle.
157     * <p>
158     * This is a convenience version of the call, which uses system-specific
159     * logic to tell whether the address is a short or long form.
160     *
161     * @param address desired decoder address
162     * @param l  ThrottleListener requesting the throttle steal occur.
163     * @param decision from the ThrottleListener, STEAL or SHARE.
164     */
165    void responseThrottleDecision(int address, ThrottleListener l, ThrottleListener.DecisionType decision);
166    
167    /**
168     * Steal or Share a requested throttle.
169     * <p>
170     * This is a convenience version of the call, which uses system-specific
171     * logic to tell whether the address is a short or long form.
172     *
173     * @param address desired decoder address
174     * @param isLong  true if requesting a DCC long (extended) address
175     * @param l  ThrottleListener requesting the throttle steal occur.
176     * @param decision from the ThrottleListener, STEAL or SHARE.
177     */
178    void responseThrottleDecision(int address, boolean isLong, ThrottleListener l, ThrottleListener.DecisionType decision);
179    
180    /**
181     * Steal or Share a requested throttle.
182     *
183     * @param address desired LocoAddress
184     * @param l The ThrottleListener which has made the decision
185     * @param decision from the ThrottleListener, STEAL or SHARE.
186     * @since 4.9.2
187     */
188    void responseThrottleDecision(LocoAddress address, ThrottleListener l, ThrottleListener.DecisionType decision);
189    
190    /**
191     * Test if the Silent Steal Throttles preference option should be enabled.
192     *
193     * @return true if steal is possible; false otherwise
194     */
195    boolean enablePrefSilentStealOption();
196    
197    /**
198     * Test if the Silent Share Throttles preference option should be enabled.
199     *
200     * @return true if steal is possible; false otherwise
201     */
202    boolean enablePrefSilentShareOption();
203    
204    /**
205     * Test if the Dispatch Button should be enabled or not.
206     *
207     * @return true if dispatch is possible; false otherwise
208     */
209    boolean hasDispatchFunction();
210
211    /**
212     * Test if a specific number is a valid long address on this system.
213     *
214     * @param address address number to test
215     * @return true if address can be long; false otherwise
216     */
217    boolean canBeLongAddress(int address);
218
219    /**
220     * Test if a specific number is a valid short address on this system.
221     *
222     * @param address address number to test
223     * @return true if address can be short; false otherwise
224     */
225    boolean canBeShortAddress(int address);
226
227    /**
228     * Test if ambiguous addresses (short vs long) are not allowed on this
229     * system. Also indicates support for multi-protocol decoders.
230     *
231     * @return true if ambiguous addresses are not allowed; false otherwise
232     */
233    boolean addressTypeUnique();
234
235    /**
236     * This returns a list of the different protocols that are supported by the
237     * system, to include short vs long or DCC vs Selectrix vs Motorola.
238     *
239     * @return the list of supported address protocols
240     */
241    String[] getAddressTypes();
242
243    /**
244     * Get a string value for a given protocol value.
245     *
246     * @param prot the protocol
247     * @return a human-readable, possibly localized, description of the protocol
248     */
249    String getAddressTypeString(LocoAddress.Protocol prot);
250
251    /**
252     * Get a list of different protocols supported by the system, to include
253     * short vs long or DCC vs Selectrix vs Motorola.
254     *
255     * @return a list of supported address protocols
256     */
257    LocoAddress.Protocol[] getAddressProtocolTypes();
258
259    /**
260     * Get a protocol given a description.
261     *
262     * @param selection human-readable, possibly localized, description of the
263     *                  protocol
264     * @return the protocol
265     */
266    LocoAddress.Protocol getProtocolFromString(String selection);
267
268    /**
269     * Get the object representing a particular address.
270     *
271     * @param value    address in protocol-specific format
272     * @param protocol specific protocol string, see the specific throttle
273     *                 manager for values
274     * @return the address, possibly as a protocol-specific subclass
275     */
276    LocoAddress getAddress(String value, String protocol);
277
278    /**
279     * Get the object representing a particular address.
280     *
281     * @param value    address in protocol-specific format
282     * @param protocol the control protocol
283     * @return the address, possibly as a protocol-specific subclass
284     */
285    LocoAddress getAddress(String value, LocoAddress.Protocol protocol);
286
287    /**
288     * Get the supported speed modes.
289     *
290     * @return an XOR of the possible modes specified in the throttle interface
291     */
292    EnumSet<SpeedStepMode> supportedSpeedModes();
293
294    /**
295     * Provides a Proxy method to return the SpeedSetting, Direction, Function
296     * Settings, of a throttle, where the requesting code has used
297     * {@link #attachListener(LocoAddress, java.beans.PropertyChangeListener) attachListener}
298     * to only be notified of changes in the throttle and not control it.
299     * <p>
300     * Valid values for item are IsForward SpeedSetting SpeedIncrement
301     * SpeedStepMode F0-F28
302     *
303 * @param la   LocoAddress that we wish interrogate
304     * @param item A string of the item we wish to know the value of.
305     * @return the value as an object, if the loco address has not been assigned
306     *         to a throttle or the item value is not valid, null is returned.
307     */
308    Object getThrottleInfo(LocoAddress la, String item);
309
310    /**
311     * 
312     * @param la Loco address to test
313     * @return true, its still required, false its not.
314     */
315    boolean addressStillRequired(LocoAddress la);
316
317    /**
318     * 
319     * @param address Loco number to test.
320     * @param addressIsLong true if long address.
321     * @return true, its still required, false its not.
322     */
323    boolean addressStillRequired(int address, boolean addressIsLong);
324    
325    /**
326     * 
327     * @param address Loco number to test
328     * @return true, its still required, false its not.
329     */
330    boolean addressStillRequired(int address);
331
332    /**
333     * 
334     * @param re roster entry to test
335     * @return true, its still required, false its not.
336     */
337    boolean addressStillRequired(BasicRosterEntry re);
338    
339    /**
340     * The specified Throttle Listener has finished using a given throttle and
341     * no longer requires access to it.
342     * <p>
343     * After releasing the throttle, the manager will perform further checks to
344     * see if it is in use by any other listeners or if there are any
345     * PropertyChangeListeners attached. If there are no other uses of the
346     * throttle then it is disposed of.
347     * <p>
348     * Normally, release ends with a call to dispose.
349     *
350     * @param t Throttle being released
351     * @param l Throttle Listener releasing the throttle
352     */
353    void releaseThrottle(DccThrottle t, ThrottleListener l);
354
355    /**
356     * Not for general use, see
357     * {@link #releaseThrottle(DccThrottle, ThrottleListener) releaseThrottle}
358     * and
359     * {@link #dispatchThrottle(DccThrottle, ThrottleListener) dispatchThrottle}.
360     * <p>
361     * Dispose of object when finished it. This will free up hardware resource
362     * <p>
363     * Used for handling certain internal error conditions, where the object
364     * still exists but hardware is not associated with it.
365     * <p>
366     * After this, further usage of this Throttle object will result in a
367     * JmriException.
368     *
369     * @param t Throttle being released
370     * @param l Throttle Listener releasing the throttle
371     * @return true if the throttle has been disposed of.
372     */
373    boolean disposeThrottle(DccThrottle t, ThrottleListener l);
374
375    /**
376     * The throttle listener has finished with the specific Throttle and is is
377     * available for reuse/reallocation by somebody else. If possible, tell the
378     * layout that this locomotive has been dispatched to another user. Not all
379     * layouts will implement this, in which case it is synomous with release();
380     * <p>
381     * Normally, dispatch ends with a call to dispose.
382     *
383     * @param t Throttle being released
384     * @param l Throttle Listener releasing the throttle
385     */
386    void dispatchThrottle(DccThrottle t, ThrottleListener l);
387
388    /**
389     * Attach a PropertyChangeListener to a specific loco address, where the
390     * requesting code does not need or require control over the loco. If the
391     * loco address is not in the active in the list, then a new throttle will
392     * be created by the manager and the listener attached.
393     * <p>
394     * The PropertyChangeListener will be notified if it has been attached to a
395     * loco address or not, via a PropertyChange notification.
396     *
397     * @param la LocoAddress of the loco we wish to monitor
398     * @param p  PropertyChangeListener to attach to the throttle
399     */
400    void attachListener(LocoAddress la, PropertyChangeListener p);
401
402    /**
403     * Remove a PropertyChangeListener to a specific loco address, where the
404     * requesting code has used
405     * {@link #attachListener(LocoAddress, java.beans.PropertyChangeListener) attachListener}
406     * to get notification of changes in a throttle.
407     * <p>
408     * The PropertyChangeListener will be notified if it has been removed via a
409     * PropertyChange notification.
410     *
411     * @param la LocoAddress of the loco we wish to monitor
412     * @param p  PropertyChangeListener to remove from the throttle
413     */
414    void removeListener(LocoAddress la, PropertyChangeListener p);
415
416    /**
417     * Get the user name of the system that the programmer is associated with.
418     *
419     * @return the user name for the system
420     */
421    String getUserName();
422
423    /**
424     * Get the number of Throttles sharing the throttle for a ddcaddress.
425     *
426     * @param la LocoAddress of the loco you want the throttle usage count for.
427     * @return number of throttles for this address, or 0 if throttle does not exist
428     */
429    int getThrottleUsageCount(LocoAddress la);
430    
431     /**
432     * Get the number of Throttles sharing the throttle for a ddcaddress.
433     *
434     * @param address number of the loco you want the throttle usage count for.
435     * @param isLongAddress indicates whether the address is long or not.
436     * @return number of throttles for this address, or 0 if throttle does not exist
437     */
438     int getThrottleUsageCount(int address, boolean isLongAddress);
439
440    /**
441     * Get the number of Throttles sharing the throttle for a ddcaddress.
442     *
443     * @param address number of the loco you want the throttle usage count for.
444     * @return number of throttles for this address, or 0 if throttle does not exist
445     */
446    int getThrottleUsageCount(int address);
447
448    /**
449     * Get the number of Throttles sharing the throttle for a ddcaddress.
450     *
451     * @param re BasicRosterEntry of the loco you want the throttle usage count for.
452     * @return number of throttles for this address, or 0 if throttle does not exist
453     */
454    int getThrottleUsageCount(BasicRosterEntry re);
455
456    /**
457     * Allow to cleanly release the traffic controller in ThrottleManager Tests
458     * <ul>
459     *     <li>remove listeners, if any</li>
460     *     <li>stop timers, is any</li>
461     * </ul>
462     */
463    void dispose();
464
465}