001package jmri.jmrix.dcc4pc;
002
003import java.util.Comparator;
004import java.util.ResourceBundle;
005import java.util.function.Supplier;
006
007import jmri.*;
008import jmri.jmrix.ConfiguringSystemConnectionMemo;
009import jmri.jmrix.DefaultSystemConnectionMemo;
010import jmri.jmrix.SystemConnectionMemoManager;
011import jmri.util.NamedBeanComparator;
012
013/**
014 * Lightweight class to denote that a system is active, and provide general
015 * information.
016 * <p>
017 * Objects of specific subtypes are registered in the instance manager to
018 * activate their particular system.
019 *
020 * @author Kevin Dickerson Copyright (C) 2012
021 */
022public class Dcc4PcSystemConnectionMemo extends DefaultSystemConnectionMemo implements ConfiguringSystemConnectionMemo {
023
024    public Dcc4PcSystemConnectionMemo(Dcc4PcTrafficController tc) {
025        super("D", "Dcc4Pc");
026        this.tc = tc;
027        tc.setAdapterMemo(this);
028    }
029
030    public Dcc4PcSystemConnectionMemo() {
031        super("D", "Dcc4Pc");
032        InstanceManager.store(this, Dcc4PcSystemConnectionMemo.class);
033        //Needs to be implemented
034        InstanceManager.store(cf = new jmri.jmrix.dcc4pc.swing.Dcc4PcComponentFactory(this),
035                jmri.jmrix.swing.ComponentFactory.class);
036    }
037
038    jmri.jmrix.swing.ComponentFactory cf = null;
039
040    /**
041     * Provides access to the TrafficController for this particular connection.
042     * @return traffic controller.
043     */
044    public Dcc4PcTrafficController getDcc4PcTrafficController() {
045        return tc;
046    }
047
048    public void setDcc4PcTrafficController(Dcc4PcTrafficController tc) {
049        this.tc = tc;
050    }
051    private Dcc4PcTrafficController tc;
052
053    /**
054     * Configure the common managers for Dcc4Pc connections. This puts the
055     * common manager config in one place. This method is static so that it can
056     * be referenced from classes that don't inherit, including
057     * hexfile.HexFileFrame and locormi.LnMessageClient
058     */
059    @Override
060    public void configureManagers() {
061
062        InstanceManager.setReporterManager(
063                getReporterManager());
064
065        InstanceManager.setSensorManager(
066                getSensorManager());
067
068        register();
069    }
070
071    public Dcc4PcReporterManager getReporterManager() {
072        if (getDisabled()) {
073            return null;
074        }
075        return (Dcc4PcReporterManager) classObjectMap.computeIfAbsent((ReporterManager.class), (Class<?> c) ->
076            new Dcc4PcReporterManager(getDcc4PcTrafficController(), this));
077    }
078
079    public Dcc4PcSensorManager getSensorManager() {
080        if (getDisabled()) {
081            return null;
082        }
083        return (Dcc4PcSensorManager) classObjectMap.computeIfAbsent(SensorManager.class,
084                (Class<?> c) -> new Dcc4PcSensorManager(getDcc4PcTrafficController(), this));
085    }
086
087    @Override
088    protected ResourceBundle getActionModelResourceBundle() {
089        return ResourceBundle.getBundle("jmri.jmrix.dcc4pc.Dcc4PcActionListBundle");
090    }
091
092    @Override
093    public <B extends NamedBean> Comparator<B> getNamedBeanComparator(Class<B> type) {
094        return new NamedBeanComparator<>();
095    }
096
097    @Override
098    public void dispose() {
099        tc = null;
100        InstanceManager.deregister(this, Dcc4PcSystemConnectionMemo.class);
101        if (cf != null) {
102            InstanceManager.deregister(cf, jmri.jmrix.swing.ComponentFactory.class);
103        }
104        Dcc4PcSensorManager sm = (Dcc4PcSensorManager) classObjectMap.get(SensorManager.class);
105        if (sm != null) {
106            sm.dispose();
107        }
108        super.dispose();
109    }
110
111    /**
112     * Provide Programming on Main through another connection's ops-mode
113     * programmer: it sends the packets, and the readback arrives as RailCom
114     * through this connection. Service mode stays with the other connection.
115     *
116     * @param <T> a manager for both modes
117     * @param dpm the other connection's programmer manager
118     */
119    public <T extends AddressedProgrammerManager & GlobalProgrammerManager> void setRealProgramManager(T dpm) {
120        provideProgrammer(new Dcc4PcProgrammerManager(dpm, this));
121        log.info("{} reads CVs on the main through {}", getUserName(), dpm.getUserName());
122    }
123
124    private void provideProgrammer(Dcc4PcProgrammerManager pm) {
125        store(pm, AddressedProgrammerManager.class);
126        InstanceManager.store(pm, AddressedProgrammerManager.class);
127    }
128
129    /**
130     * {@inheritDoc}
131     * <p>
132     * No consist manager, although this connection provides an ops-mode
133     * programmer: that only forwards to another connection, which provides
134     * its own consists.
135     */
136    @Override
137    public boolean provides(Class<?> c) {
138        boolean provided = super.provides(c);
139        return provided && !c.equals(ConsistManager.class);
140    }
141
142    /**
143     * Use another connection's ops-mode programmer for Programming on Main
144     * (the connection's "Programmer" option): that connection's command
145     * station sends the packets, and the RailCom reply comes back through
146     * this one. With no connection named, the default Command Station's
147     * connection (Preferences, Defaults) is used.
148     * <p>
149     * This connection offers its ops-mode programmer straight away, so it can
150     * be chosen as the default whichever connection starts first; the other
151     * connection is looked up each time a programmer is needed.
152     *
153     * @param userName the other connection's name, or empty to use the
154     *                 default command station
155     */
156    public void useProgrammerFrom(String userName) {
157        boolean useDefault = userName == null || userName.isEmpty();
158        Supplier<SystemConnectionMemo> other = () -> connectionNamed(useDefault ? defaultCommandStation() : userName);
159        provideProgrammer(new Dcc4PcProgrammerManager(
160                () -> managerOf(other.get(), AddressedProgrammerManager.class),
161                () -> managerOf(other.get(), CommandStation.class),
162                this));
163        log.info("{} reads CVs on the main through {}", getUserName(), useDefault ? "the default command station" : userName);
164    }
165
166    /** @return the name of the connection set as the default Command Station, or null if none */
167    private static String defaultCommandStation() {
168        jmri.managers.ManagerDefaultSelector defaults = InstanceManager.getNullableDefault(jmri.managers.ManagerDefaultSelector.class);
169        return defaults == null ? null : defaults.getDefault(CommandStation.class);
170    }
171
172    /** @return the named connection other than this one, or null if it isn't running */
173    private SystemConnectionMemo connectionNamed(String userName) {
174        if (userName == null) {
175            return null;
176        }
177        SystemConnectionMemo other = SystemConnectionMemoManager.getDefault().getSystemConnectionMemoForUserName(userName);
178        return other == this ? null : other;
179    }
180
181    private static <T> T managerOf(SystemConnectionMemo memo, Class<T> type) {
182        return memo == null ? null : memo.get(type);
183    }
184
185    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Dcc4PcSystemConnectionMemo.class);
186}