001package jmri.jmrix.bidib;
002
003import java.util.Comparator;
004import java.util.ResourceBundle;
005import javax.annotation.Nonnull;
006import jmri.GlobalProgrammerManager;
007
008import jmri.InstanceManager;
009import jmri.LightManager;
010//import jmri.MultiMeter;
011import jmri.PowerManager;
012import jmri.SensorManager;
013import jmri.ThrottleManager;
014import jmri.TurnoutManager;
015import jmri.CommandStation;
016import jmri.NamedBean;
017import jmri.ReporterManager;
018//import jmri.jmrix.ConfiguringSystemConnectionMemo;
019import jmri.jmrix.DefaultSystemConnectionMemo;
020//import jmri.ConsistManager;
021import jmri.util.NamedBeanComparator;
022import org.slf4j.Logger;
023import org.slf4j.LoggerFactory;
024
025/**
026 * Lightweight class to denote that a system is active and provide general
027 * information.
028 * <p>
029 * Objects of specific subtypes are registered in the instance manager to
030 * activate their particular system.
031 *
032 * @author Paul Bender Copyright (C) 2010
033 * @author Mark Underwood Copyright (C) 2015
034 * @author Eckart Meyer Copyright (C) 2019-2023
035 *
036 * Based on DCCppSystemConnectionMemo by Paul Bender and Mark Underwood.
037 */
038public class BiDiBSystemConnectionMemo extends DefaultSystemConnectionMemo /* implements ConfiguringSystemConnectionMemo */  {
039
040//    @SuppressWarnings("OverridableMethodCallInConstructor")
041    public BiDiBSystemConnectionMemo(@Nonnull BiDiBTrafficController tc) {
042        super("B", "BiDiB");
043        log.trace("**** ctor 1 BiDiBSystemConnectionMemo");
044        this.tc = tc;
045        tc.setSystemConnectionMemo(this);
046        register(); // registers general type
047        InstanceManager.store(this, BiDiBSystemConnectionMemo.class); // also register as specific type
048
049        // create and register the BiDiBComponentFactory
050        InstanceManager.store(cf = new jmri.jmrix.bidib.swing.BiDiBComponentFactory(this),
051        jmri.jmrix.swing.ComponentFactory.class);
052
053        log.debug("Created BiDiBSystemConnectionMemo");
054    }
055
056//    @SuppressWarnings("OverridableMethodCallInConstructor")
057    public BiDiBSystemConnectionMemo() {
058        super("B", "BiDiB");
059        log.trace("**** ctor 2 BiDiBSystemConnectionMemo");
060        register(); // registers general type
061        InstanceManager.store(this, BiDiBSystemConnectionMemo.class); // also register as specific type
062
063        // create and register the BiDiBComponentFactory
064        InstanceManager.store(cf = new jmri.jmrix.bidib.swing.BiDiBComponentFactory(this),
065                jmri.jmrix.swing.ComponentFactory.class);
066
067        log.debug("Created BiDiBSystemConnectionMemo");
068    }
069
070    jmri.jmrix.swing.ComponentFactory cf = null;
071
072    /**
073     * Provide access to the TrafficController for this particular connection.
074     * 
075     * @return BiDiB Traffic Controller
076     */
077    public BiDiBTrafficController getBiDiBTrafficController() {
078        log.trace("getBiDiBTrafficController");
079        if (tc == null) {
080            setBiDiBTrafficController(new BiDiBTrafficController(null));
081            log.debug("Auto create of BiDiBTrafficController for initial configuration");
082        }
083        return tc;
084    }
085
086    private BiDiBTrafficController tc;
087
088    /**
089     * Set the traffic controller instance associated with this connection memo.
090     *
091     * @param tc the {@link jmri.jmrix.bidib.BiDiBTrafficController} object to use.
092     */
093    public void setBiDiBTrafficController(@Nonnull BiDiBTrafficController tc) {
094        this.tc = tc;
095        // in addition to setting the traffic controller in this object,
096        // set the systemConnectionMemo in the traffic controller
097        tc.setSystemConnectionMemo(this);
098    }
099
100    /**
101     * Configure the common managers for BiDiB connections. This puts the
102     * common manager config in one place. This method is static so that it can
103     * be referenced from classes that don't inherit.
104     */
105    public void configureManagers() {
106        if (tc.getCurrentGlobalProgrammerNode() != null) {
107            InstanceManager.store(getProgrammerManager(), GlobalProgrammerManager.class);
108        }
109        if (tc.getFirstCommandStationNode() != null) {
110            InstanceManager.store(getProgrammerManager(), jmri.AddressedProgrammerManager.class);
111            InstanceManager.setThrottleManager(getThrottleManager());
112            InstanceManager.store(getCommandStation(), jmri.CommandStation.class); //unsed??
113        }
114        if (tc.getFirstBoosterNode()!= null) {
115            InstanceManager.store(getPowerManager(), jmri.PowerManager.class);
116            // setup the PredefinedMeters
117            createPredefinedMeters();
118        }
119//        if (tc.getFirstOutputNode() != null  ||  tc.getFirstCommandStationNode() != null) {
120//        }
121
122        // always
123        InstanceManager.setTurnoutManager(getTurnoutManager());
124        InstanceManager.setSensorManager(getSensorManager());
125        InstanceManager.setReporterManager(getReporterManager());
126        InstanceManager.setLightManager(getLightManager());
127        
128//        InstanceManager.store(getConsistManager(), ConsistManager.class);
129
130
131    }
132    
133    /**
134     * Called after all components (Sensors, Lights, ...) have been loaded 
135     * Used to get some data from the device in one run
136     * 
137     * NOT USED ANYMORE
138     */
139    public void postConfigure() {
140//        log.info("+++++++++ {}: post configure starts ++++++++++++", tc.getSystemConnectionMemo().getUserName());
141//        log.debug("memo: {}, bidib: {}", this, tc.getBidib());
142//        // get all BiDiB Port Configuration data
143//        tc.allPortConfigX();
144//        // and then the status of all ports
145//        tc.allPortLcStat();
146//        // then the status of all accessories
147//        tc.allAccessoryState();
148//        // finally all feedback channels
149//        tc.allFeedback();
150//        log.info("--------- {}: post configure ends -------------", tc.getSystemConnectionMemo().getUserName());
151//        try {
152//            tc.getBidib().getRootNode().getMagic(1000);
153//            log.info("MAGIC received from root node: {}", tc.getBidib().getRootNode());
154//        }
155//        catch (ProtocolException ex) {
156//            log.error("post configure - no answer from root node: " + tc.getBidib().getRootNode()); // NOSONAR
157//        }
158    }
159
160
161    /**
162     * Provides access to the Programmer for this particular connection.
163     * 
164     * @return programmer manager
165     */
166    public BiDiBProgrammerManager getProgrammerManager() {
167        log.trace("getProgrammerManager");
168        //Do not want to return a programmer if the system is disabled
169        if (getDisabled()) {
170            return null;
171        }
172        return (BiDiBProgrammerManager) classObjectMap.computeIfAbsent(BiDiBProgrammerManager.class,(Class<?> c) ->  {
173            BiDiBProgrammerManager programmerManager = new BiDiBProgrammerManager(this);
174            log.debug("programmer manager created: {}", programmerManager);
175            return programmerManager;
176        });
177    }
178
179    public void setProgrammerManager(BiDiBProgrammerManager p) {
180        store(p,BiDiBProgrammerManager.class);
181    }
182
183    /*
184     * Provides access to the Throttle Manager for this particular connection.
185     */
186    public ThrottleManager getThrottleManager() {
187        log.trace("getThrottleManager");
188        if (getDisabled()) {
189            return null;
190        }
191        return (ThrottleManager) classObjectMap.computeIfAbsent(ThrottleManager.class, (Class<?> c) -> {
192            ThrottleManager throttleManager = new BiDiBThrottleManager(this);
193            log.debug("throttle manager created: {}", throttleManager);
194            return throttleManager;
195        });
196    }
197
198    public void setThrottleManager(ThrottleManager t) {
199        store(t,ThrottleManager.class);
200    }
201
202    /*
203     * Provides access to the Power Manager for this particular connection.
204     */
205//    @Nonnull
206    public PowerManager getPowerManager() {
207        log.trace("getPowerManager");
208        if (getDisabled()) {
209            return null;
210        }
211        return (PowerManager) classObjectMap.computeIfAbsent(PowerManager.class, (Class<?> c) -> {
212            PowerManager powerManager = new BiDiBPowerManager(this);
213            log.debug("power manager created: {}", powerManager);
214            return powerManager;
215        });
216    }
217
218    public void setPowerManager(@Nonnull PowerManager p) {
219        store(p,PowerManager.class);
220    }
221
222
223    
224    /*
225     * Provides access to the Sensor Manager for this particular connection.
226     */
227    public SensorManager getSensorManager() {
228        log.trace("getSensorManager");
229        if (getDisabled()) {
230            return null;
231        }
232        return (SensorManager) classObjectMap.computeIfAbsent(SensorManager.class, (Class<?> c) -> {
233            SensorManager sensorManager = new BiDiBSensorManager(this);
234            log.debug("sensor manager created: {}", sensorManager);
235            return sensorManager;
236        });
237    }
238
239    public void setSensorManager(@Nonnull SensorManager s) {
240        store(s,SensorManager.class);
241    }
242
243    /*
244     * Provides access to the Reporter Manager for this particular connection.
245     * BiDiB uses the reporter for RailCom
246     */
247    public ReporterManager getReporterManager() {
248        log.trace("getReporterManager");
249        if (getDisabled()) {
250            return null;
251        }
252        return (ReporterManager) classObjectMap.computeIfAbsent(ReporterManager.class, (Class<?> c) -> {
253            ReporterManager reporterManager = new BiDiBReporterManager(this);
254            log.debug("reporter manager created: {}", reporterManager);
255            return reporterManager;
256        });
257    }
258
259    public void setReporterManager(@Nonnull ReporterManager s) {
260        store(s,ReporterManager.class);
261    }
262
263    /*
264     * Provides access to the Turnout Manager for this particular connection.
265     */
266    public TurnoutManager getTurnoutManager() {
267        log.trace("getTurnoutManager");
268        if (getDisabled()) {
269            return null;
270        }
271        return (TurnoutManager) classObjectMap.computeIfAbsent(TurnoutManager.class, (Class<?> c) -> {
272            TurnoutManager turnoutManager = new BiDiBTurnoutManager(this);
273            log.debug("turnout manager created: {}", turnoutManager);
274            return turnoutManager;
275        });
276    }
277
278    public void setTurnoutManager(@Nonnull TurnoutManager t) {
279        store(t,TurnoutManager.class);
280    }
281
282    /*
283     * Provides access to the Light Manager for this particular connection.
284     */
285    public LightManager getLightManager() {
286        log.trace("getLightManager");
287        if (getDisabled()) {
288            return null;
289        }
290        return (LightManager) classObjectMap.computeIfAbsent(LightManager.class, (Class<?> c) -> {
291            LightManager lightManager = new BiDiBLightManager(this);
292            log.debug("light manager created: {}", lightManager);
293            return lightManager;
294        });
295    }
296
297    public void setLightManager(@Nonnull LightManager l) {
298        store(l,LightManager.class);
299    }
300
301    /*
302     * Provides access to the mulit meter for this particular connection.
303     */
304//    public void enableMultiMeter(){
305//        jmri.InstanceManager.store( getMultiMeter(), jmri.MultiMeter.class );
306//    }
307    
308    protected BiDiBPredefinedMeters predefinedMeters;
309    
310    public BiDiBPredefinedMeters createPredefinedMeters() {
311        if (getDisabled()) {
312            return null;
313        }
314        if (predefinedMeters == null) {
315            InstanceManager.setMeterManager(new jmri.managers.AbstractMeterManager(this));
316            predefinedMeters = new BiDiBPredefinedMeters(this);
317        }
318        return predefinedMeters;
319    }
320        
321    /*
322     * Provides access to the Command Station for this particular connection.
323     * NOTE: Command Station defaults to NULL
324     */
325    public CommandStation getCommandStation() {
326        log.trace("getCommandStation");
327        if (getDisabled()  ||  tc.getFirstCommandStationNode()== null) {
328            return null;
329        }
330        return (CommandStation) classObjectMap.computeIfAbsent(CommandStation.class, (Class<?> c) -> {
331            return tc;
332        });
333    }
334
335
336    /**
337     * {@inheritDoc}
338     */
339    @Override
340    public boolean provides(Class<?> type) {
341        log.trace("check for {}", type);
342        //log.trace("  this: {}, tc: {}", this, tc);
343//return (get(type) != null);
344//TODO: what if we finally support "lost node" and "new node"?
345        if (getDisabled() ||  tc == null) {
346            return false;
347        } else if (type.equals(jmri.GlobalProgrammerManager.class)) {
348            BiDiBProgrammerManager p = getProgrammerManager();
349            if (p == null) {
350                return false;
351            }
352            return p.isGlobalProgrammerAvailable();
353        } else if (type.equals(jmri.AddressedProgrammerManager.class)) {
354            BiDiBProgrammerManager p = getProgrammerManager();
355            if (p == null) {
356                return false;
357            }
358            return p.isAddressedModePossible();
359            //TODO: Update return value of the following as Managers are brought online.
360        } else if (type.equals(jmri.ThrottleManager.class)) {
361//            return true;
362            return (tc.getFirstCommandStationNode() != null);
363        } else if (type.equals(jmri.PowerManager.class)) {
364//            return true;
365            return (tc.getFirstBoosterNode() != null);
366        } else if (type.equals(jmri.ReporterManager.class)) {
367            return true;
368//            return (tc.getFirstCommandStationNode() != null);
369        } else if (type.equals(jmri.SensorManager.class)) {
370            return true;
371//            return (tc.getFirstOutputNode() != null  ||  tc.getFirstCommandStationNode() != null);
372        } else if (type.equals(jmri.TurnoutManager.class)) {
373            return true;
374//            return (tc.getFirstOutputNode() != null  ||  tc.getFirstCommandStationNode() != null);
375        } else if (type.equals(jmri.LightManager.class)) {
376            return true;
377        } else if (type.equals(jmri.ConsistManager.class)) {
378            return false; //for now, we do not provide a consist manager - TODO!
379        } else if (type.equals(jmri.CommandStation.class)) {
380//            return true;
381//            return false;
382            return (tc.getFirstCommandStationNode() != null);
383//        } else if (type.equals(jmri.MultiMeter.class)) {
384////            return true;
385//            return (tc.getFirstBoosterNode() != null);
386        } else {
387            return super.provides(type);
388        }
389    }
390
391    /**
392     * {@inheritDoc}
393     */
394    @SuppressWarnings("unchecked")
395    @Override
396//    public <T> T get(Class<?> T) { //v5.2
397    public <T> T get(Class<T> T) {
398        if (getDisabled()) {
399            return null;
400        }
401        log.trace("get {}", T);
402        if (T.equals(jmri.GlobalProgrammerManager.class)) {
403            return (T) getProgrammerManager();
404        }
405        if (T.equals(jmri.AddressedProgrammerManager.class)) {
406            return (T) getProgrammerManager();
407        }
408        if (T.equals(jmri.ThrottleManager.class)) {
409            return (T) getThrottleManager();
410        }
411        if (T.equals(jmri.PowerManager.class)) {
412            return (T) getPowerManager();
413        }
414        if (T.equals(jmri.SensorManager.class)) {
415            return (T) getSensorManager();
416        }
417        if (T.equals(jmri.ReporterManager.class)) {
418            return (T) getReporterManager();
419        }
420        if (T.equals(jmri.TurnoutManager.class)) {
421            return (T) getTurnoutManager();
422        }
423        if (T.equals(jmri.LightManager.class)) {
424            return (T) getLightManager();
425        }
426        if (T.equals(jmri.ConsistManager.class)) {
427            return null;//for now, we do not provide a consist manager - TODO!
428        }
429        if (T.equals(jmri.CommandStation.class)) {
430            return (T) getCommandStation();
431        }
432//        if (T.equals(jmri.MultiMeter.class)) {
433//            return (T) getMultiMeter();
434//        }
435        return super.get(T);
436    }
437
438    /**
439     * {@inheritDoc}
440     */
441    @Override
442    @Nonnull
443    protected ResourceBundle getActionModelResourceBundle() {
444        log.debug("getActionModelResourceBundle");
445        return ResourceBundle.getBundle("jmri.jmrix.bidib.BiDiBActionListBundle");
446    }
447
448    /**
449     * {@inheritDoc}
450     */
451    @Override
452    public <B extends NamedBean> Comparator<B> getNamedBeanComparator(Class<B> type) {
453        return new NamedBeanComparator<>();
454    }
455
456    /**
457     * {@inheritDoc}
458     */
459    @Override
460    public void dispose() {
461        log.info("---- dispose -----");
462        InstanceManager.deregister(this, BiDiBSystemConnectionMemo.class);
463        if (predefinedMeters != null) {
464            predefinedMeters.dispose();
465        }
466        if (cf != null) {
467            InstanceManager.deregister(cf, jmri.jmrix.swing.ComponentFactory.class);
468        }
469        super.dispose();
470        tc = null;
471    }
472
473    private final static Logger log = LoggerFactory.getLogger(BiDiBSystemConnectionMemo.class);
474
475}
476