001package jmri.jmrix.loconet;
002
003import java.util.Comparator;
004import java.util.ResourceBundle;
005import javax.annotation.Nonnull;
006
007import jmri.*;
008import jmri.jmrix.ConfiguringSystemConnectionMemo;
009import jmri.jmrix.DefaultSystemConnectionMemo;
010import jmri.jmrix.debugthrottle.DebugThrottleManager;
011import jmri.jmrix.loconet.swing.LnComponentFactory;
012import jmri.jmrix.swing.ComponentFactory;
013import jmri.managers.DefaultProgrammerManager;
014import jmri.util.NamedBeanComparator;
015
016import org.slf4j.Logger;
017import org.slf4j.LoggerFactory;
018
019/**
020 * Lightweight class to denote that a system is active, and provide general
021 * information.
022 * <p>
023 * Objects of specific subtypes are registered in the instance manager to
024 * activate their particular system.
025 *
026 * @author Bob Jacobsen Copyright (C) 2010
027 */
028public class LocoNetSystemConnectionMemo extends DefaultSystemConnectionMemo implements ConfiguringSystemConnectionMemo {
029
030    /**
031     * Must manually register() after construction is complete.
032     * @param lt Traffic controller to be used
033     * @param sm Slot Manager to be used
034     */
035    public LocoNetSystemConnectionMemo(LnTrafficController lt, SlotManager sm) {
036        super("L", "LocoNet"); // NOI18N
037        this.lt = lt;
038
039        this.sm = sm; // doesn't full register, but fine for this purpose.
040
041        // self-registration is deferred until the command station type is set below
042
043        // create and register the ComponentFactory for the GUI
044        InstanceManager.store(cf = new LnComponentFactory(this),
045                ComponentFactory.class);
046    }
047
048    /**
049     * Must manually register() after construction is complete.
050     */
051    public LocoNetSystemConnectionMemo() {
052        this("L", "LocoNet"); // NOI18N
053    }
054
055    public LocoNetSystemConnectionMemo(@Nonnull String prefix, @Nonnull String name) {
056        super(prefix, name); // NOI18N
057
058        // create and register the ComponentFactory for the GUI
059        InstanceManager.store(cf = new LnComponentFactory(this),
060                ComponentFactory.class);
061    }
062
063    /**
064     * Do both the default parent
065     * {@link jmri.SystemConnectionMemo} registration,
066     * and register this specific type.
067     */
068    @Override
069    public void register() {
070        super.register(); // registers general type
071        InstanceManager.store(this, LocoNetSystemConnectionMemo.class); // also register as specific type
072    }
073
074    ComponentFactory cf = null;
075    private LnTrafficController lt;
076    protected LocoNetThrottledTransmitter tm;
077    private SlotManager sm;
078    private LncvDevicesManager lncvdm = null;
079    private LnMessageManager lnm = null;
080
081    /**
082     * Provide access to the SlotManager for this particular connection.
083     *
084     * @return the slot manager or null if no valid slot manager is available
085     */
086    public SlotManager getSlotManager() {
087        if (sm == null) {
088            log.debug("slot manager is null, but there should always be a valid SlotManager", new Exception("Traceback"));
089        }
090        return sm;
091    }
092
093    /**
094     * Provide access to the TrafficController for this particular connection.
095     *
096     * @return the LocoNet-specific TrafficController
097     */
098    public LnTrafficController getLnTrafficController() {
099        if (lt == null) {
100            setLnTrafficController(new LnPacketizer(this)); // default to Packetizer TrafficController
101            log.debug("Auto create of LnTrafficController for initial configuration");
102        }
103        return lt;
104    }
105
106    public void setLnTrafficController(LnTrafficController lt) {
107        this.lt = lt;
108    }
109
110    public LnMessageManager getLnMessageManager() {
111        // create when needed
112        if (lnm == null) {
113            lnm = new LnMessageManager(getLnTrafficController());
114        }
115        return lnm;
116    }
117
118    public DefaultProgrammerManager getProgrammerManager() {
119        return (DefaultProgrammerManager) classObjectMap.computeIfAbsent(DefaultProgrammerManager.class,(Class c) -> new LnProgrammerManager(this));
120    }
121
122    public void setProgrammerManager(DefaultProgrammerManager p) {
123        store(p,DefaultProgrammerManager.class);
124    }
125
126    public void setLncvDevicesManager(LncvDevicesManager lncvdm) {
127        this.lncvdm = lncvdm;
128    }
129
130    protected boolean mTurnoutNoRetry = false;
131    protected boolean mTurnoutExtraSpace = false;
132
133    /**
134     * Configure the programming manager and "command station" objects.
135     *
136     * @param type               Command station type, used to configure various
137     *                           operations
138     * @param mTurnoutNoRetry    Is the user configuration set for no turnout
139     *                           operation retries?
140     * @param mTurnoutExtraSpace Is the user configuration set for extra time
141     *                           between turnout operations?
142     * @param mTranspondingAvailable    Is the layout configured to provide
143     *                                  transopnding reports
144     */
145    public void configureCommandStation(LnCommandStationType type, boolean mTurnoutNoRetry,
146                                            boolean mTurnoutExtraSpace, boolean mTranspondingAvailable) {
147
148        // store arguments
149        this.mTurnoutNoRetry = mTurnoutNoRetry;
150        this.mTurnoutExtraSpace = mTurnoutExtraSpace;
151
152        // create and install SlotManager
153        if (sm != null) {
154            log.error("Installing SlotManager twice", new Exception("TraceBack"));
155        }
156        sm = type.getSlotManager(lt);
157        if (sm != null) {
158            sm.setThrottledTransmitter(tm, mTurnoutNoRetry);
159
160            sm.setCommandStationType(type);
161            sm.setSystemConnectionMemo(this);
162            sm.setTranspondingAvailable(mTranspondingAvailable);
163
164            // store as CommandStation object
165            InstanceManager.store(sm, jmri.CommandStation.class);
166            store(sm, jmri.CommandStation.class);
167        }
168
169    }
170
171    /**
172     * Configure the common managers for LocoNet connections. This puts the
173     * common manager config in one place.
174     */
175    @Override
176    public void configureManagers() {
177
178        tm = new LocoNetThrottledTransmitter(getLnTrafficController(), mTurnoutExtraSpace);
179        log.debug("ThrottleTransmitted configured with: {}", mTurnoutExtraSpace);
180        if (sm != null) {
181            sm.setThrottledTransmitter(tm, mTurnoutNoRetry);
182            log.debug("set turnout retry: {}", mTurnoutNoRetry);
183        }
184
185        InstanceManager.store(getPowerManager(), PowerManager.class);
186
187        InstanceManager.setSensorManager(
188                getSensorManager());
189
190        InstanceManager.setTurnoutManager(
191                getTurnoutManager());
192
193        InstanceManager.setLightManager(
194                getLightManager());
195
196        InstanceManager.setThrottleManager(
197                getThrottleManager());
198
199        DefaultProgrammerManager programmerManager = getProgrammerManager();
200
201        if (programmerManager.isAddressedModePossible()) {
202            store(programmerManager, AddressedProgrammerManager.class);
203            InstanceManager.store(programmerManager, AddressedProgrammerManager.class);
204        }
205        if (programmerManager.isGlobalProgrammerAvailable()) {
206            store(getProgrammerManager(), GlobalProgrammerManager.class);
207            InstanceManager.store(getProgrammerManager(), GlobalProgrammerManager.class);
208        }
209
210        InstanceManager.setReporterManager(getReporterManager());
211
212        InstanceManager.setDefault(CabSignalManager.class,getCabSignalManager());
213
214        setConsistManager(new LocoNetConsistManager(this));
215
216        setLncvDevicesManager(new jmri.jmrix.loconet.LncvDevicesManager(this));
217
218        ClockControl cc = getClockControl();
219
220        InstanceManager.setDefault(ClockControl.class, cc);
221
222        getIdTagManager();
223
224        // register this SystemConnectionMemo to connect to rest of system
225        register();
226
227        // This must be done after the memo is registered
228        getPredefinedMeters();
229    }
230
231    public LnPowerManager getPowerManager() {
232        if (getDisabled()) {
233            return null;
234        }
235        return (LnPowerManager) classObjectMap.computeIfAbsent(PowerManager.class,(Class c) -> new LnPowerManager(this));
236    }
237
238    public ThrottleManager getThrottleManager() {
239        if (getSlotManager() != null) {
240            log.debug("GetThrottleManager for {}", getSlotManager().getCommandStationType());
241        }
242        if (getDisabled()) {
243            return null;
244        }
245        ThrottleManager throttleManager = get(ThrottleManager.class);
246        if (throttleManager == null && getSlotManager() != null) {
247            // ask command station type for specific throttle manager
248            LnCommandStationType cmdstation = getSlotManager().getCommandStationType();
249            log.debug("getThrottleManager constructs for {}", cmdstation.getName());
250            throttleManager = cmdstation.getThrottleManager(this);
251            log.debug("result was type {}", throttleManager.getClass());
252            store(throttleManager,ThrottleManager.class);
253        }
254        return throttleManager;
255    }
256
257    public void setThrottleManager(ThrottleManager t) {
258        store(t,ThrottleManager.class);
259    }
260
261    public LnTurnoutManager getTurnoutManager() {
262        if (getDisabled()) {
263            return null;
264        }
265        return (LnTurnoutManager) classObjectMap.computeIfAbsent(TurnoutManager.class,(Class c) -> new LnTurnoutManager(this, tm, mTurnoutNoRetry));
266    }
267
268    public LnClockControl getClockControl() {
269        if (getDisabled()) {
270            return null;
271        }
272        return (LnClockControl) classObjectMap.computeIfAbsent(ClockControl.class,(Class c) -> new LnClockControl(this));
273    }
274
275    public LnReporterManager getReporterManager() {
276        if (getDisabled()) {
277            return null;
278        }
279        return (LnReporterManager) classObjectMap.computeIfAbsent(ReporterManager.class, (Class c) -> new LnReporterManager(this));
280    }
281
282    public LnSensorManager getSensorManager() {
283        if (getDisabled()) {
284            return null;
285        }
286        return (LnSensorManager) classObjectMap.computeIfAbsent(SensorManager.class, (Class c) -> new LnSensorManager(this));
287    }
288
289    public LnLightManager getLightManager() {
290        if (getDisabled()) {
291            return null;
292        }
293        return (LnLightManager) classObjectMap.computeIfAbsent(LightManager.class, (Class c) -> new LnLightManager(this));
294    }
295
296    public LncvDevicesManager getLncvDevicesManager() {
297        if (getDisabled()) {
298            return null;
299        }
300        if (lncvdm == null) {
301            setLncvDevicesManager(new LncvDevicesManager(this));
302            log.debug("Auto create of LncvDevicesManager for initial configuration");
303        }
304        return lncvdm;
305    }
306
307    protected LnPredefinedMeters predefinedMeters;
308
309    public LnPredefinedMeters getPredefinedMeters() {
310        if (getDisabled()) {
311            log.warn("Aborting getPredefinedMeters account is disabled!");
312            return null;
313        }
314//        switch (getSlotManager().commandStationType) {
315//            case COMMAND_STATION_USB_DCS240_ALONE:
316//            case COMMAND_STATION_DCS240:
317//            case COMMAND_STATION_DCS210:
318//            case COMMAND_STATION_USB_DCS52_ALONE:
319//            case COMMAND_STATION_DCS052:
320//                break;
321//            default:
322//                // The command station does not support these meters
323//                return null;
324//        }
325        if (predefinedMeters == null) {
326            predefinedMeters = new LnPredefinedMeters(this);
327        }
328        return predefinedMeters;
329    }
330
331    @Override
332    protected ResourceBundle getActionModelResourceBundle() {
333        return ResourceBundle.getBundle("jmri.jmrix.loconet.LocoNetActionListBundle");
334    }
335
336    @Override
337    public <B extends NamedBean> Comparator<B> getNamedBeanComparator(Class<B> type) {
338        return new NamedBeanComparator<>();
339    }
340
341    // yes, tagManager is static.  Tags can move between system connections.
342    // when readers are not all on the same LocoNet
343    // this manager is loaded on demand.
344    protected static TranspondingTagManager tagManager;
345
346    static public TranspondingTagManager getIdTagManager() {
347        synchronized (LocoNetSystemConnectionMemo.class) { // since tagManager can be null, can't synch on that
348            if (tagManager == null) {
349                tagManager = new TranspondingTagManager();
350                InstanceManager.setIdTagManager(tagManager);
351            }
352            return tagManager;
353        }
354    }
355
356    public LnCabSignalManager getCabSignalManager() {
357        return (LnCabSignalManager) classObjectMap.computeIfAbsent(CabSignalManager.class,(Class c) -> new LnCabSignalManager(this));
358    }
359
360    @Override
361    public void dispose() {
362        InstanceManager.deregister(this, LocoNetSystemConnectionMemo.class);
363        if (cf != null) {
364            InstanceManager.deregister(cf, ComponentFactory.class);
365            cf = null;
366        }
367        ThrottleManager throttleManager = get(ThrottleManager.class);
368        if (throttleManager != null) {
369            if (throttleManager instanceof LnThrottleManager) {
370                InstanceManager.deregister(((LnThrottleManager) throttleManager), LnThrottleManager.class);
371            } else if (throttleManager instanceof DebugThrottleManager) {
372                InstanceManager.deregister(((DebugThrottleManager) throttleManager), DebugThrottleManager.class);
373            }
374            deregister(throttleManager,ThrottleManager.class);
375        }
376
377        if (tm != null){
378            tm.dispose();
379            tm = null;
380        }
381        if (sm != null){
382            sm.dispose();
383            sm = null;
384        }
385        if (lt != null){
386            lt.dispose();
387            lt = null;
388        }
389        if (predefinedMeters != null) {
390            predefinedMeters.dispose();
391        }
392        super.dispose();
393    }
394
395    private final static Logger log = LoggerFactory.getLogger(LocoNetSystemConnectionMemo.class);
396
397}