001package jmri.managers;
002
003import java.beans.PropertyChangeEvent;
004import java.util.ArrayList;
005import java.util.List;
006
007import javax.annotation.CheckForNull;
008import javax.annotation.CheckReturnValue;
009import javax.annotation.Nonnull;
010
011import jmri.*;
012import jmri.jmrix.internal.InternalAnalogIOManager;
013import jmri.jmrix.internal.InternalSystemConnectionMemo;
014
015/**
016 * Implementation of a AnalogIOManager that can serve as a proxy for multiple
017 * system-specific implementations.
018 *
019 * @author  Bob Jacobsen      Copyright (C) 2010, 2018
020 * @author  Dave Duchamp      Copyright (C) 2004
021 * @author  Daniel Bergqvist  Copyright (C) 2020
022 */
023public class ProxyAnalogIOManager extends AbstractProxyManager<AnalogIO>
024        implements AnalogIOManager {
025    
026    private final InternalAnalogIOManager internalAnalogIOManager;
027    private boolean muteUpdates = false;
028    private final List<Class<? extends AnalogIO>> registerBeans = new ArrayList<>();
029    private final List<Manager<? extends NamedBean>> registerBeanManagers = new ArrayList<>();
030
031    public ProxyAnalogIOManager() {
032        internalAnalogIOManager = new InternalAnalogIOManager(InstanceManager.getDefault(
033                InternalSystemConnectionMemo.class));
034        addManager(internalAnalogIOManager);
035    }
036
037    @Nonnull
038    public ProxyAnalogIOManager init() {
039        // Note that not all lights in LightManager are VariableLight.
040        addBeanType(Meter.class, InstanceManager.getDefault(MeterManager.class));
041        addBeanType(VariableLight.class, InstanceManager.getDefault(LightManager.class));
042        return this;
043    }
044
045    @Override
046    public int getXMLOrder() {
047        return jmri.Manager.ANALOGIOS;
048    }
049
050    @Override
051    protected AbstractManager<AnalogIO> makeInternalManager() {
052        return internalAnalogIOManager;
053    }
054
055    @Override
056    @Nonnull
057    public String getBeanTypeHandled(boolean plural) {
058        return Bundle.getMessage(plural ? "BeanNameAnalogIOs" : "BeanNameAnalogIO");
059    }
060
061    /**
062     * {@inheritDoc}
063     */
064    @Override
065    public Class<AnalogIO> getNamedBeanClass() {
066        return AnalogIO.class;
067    }
068
069    /* {@inheritDoc} */
070    @Override
071    @CheckReturnValue
072    @CheckForNull
073    public AnalogIO getBySystemName(@Nonnull String systemName) {
074        AnalogIO analogIO = super.getBySystemName(systemName);
075        if (analogIO == null) {
076            analogIO = initInternal().getBySystemName(systemName);
077        }
078        return analogIO;
079    }
080
081    /** {@inheritDoc} */
082    @Override
083    @CheckForNull
084    public AnalogIO getByUserName(@Nonnull String userName) {
085        AnalogIO analogIO = super.getByUserName(userName);
086        if (analogIO == null) {
087            analogIO = initInternal().getByUserName(userName);
088        }
089        return analogIO;
090    }
091
092    @Override
093    public void propertyChange(PropertyChangeEvent e) {
094        super.propertyChange(e);
095        
096        // When we add or remove the Light to the internal AnalogIO manager,
097        // we get a propertyChange for that.
098        if (muteUpdates) return;
099        
100        if ("beans".equals(e.getPropertyName())) {
101            
102            for (Class<? extends AnalogIO> clazz : registerBeans) {
103                // A NamedBean is added
104                if ((e.getNewValue() != null)
105                        && clazz.isAssignableFrom(e.getNewValue().getClass())) {
106                    Manager<AnalogIO> internalManager = initInternal();
107                    muteUpdates = true;
108                    internalManager.register((AnalogIO) e.getNewValue());
109                    muteUpdates = false;
110                }
111                
112                // A NamedBean is removed
113                if ((e.getOldValue() != null)
114                        && clazz.isAssignableFrom(e.getOldValue().getClass())) {
115                    Manager<AnalogIO> internalManager = initInternal();
116                    muteUpdates = true;
117                    internalManager.deregister((AnalogIO) e.getOldValue());
118                    muteUpdates = false;
119                }
120            }
121        }
122    }
123
124    /** {@inheritDoc} */
125    @Override
126    public void dispose() {
127        super.dispose();
128        for (Manager<? extends NamedBean> manager : registerBeanManagers) {
129            manager.removePropertyChangeListener("beans", this);
130        }
131    }
132
133    /**
134     * Add a type of NamedBean, for example VariableLight, that should be also registred in AnalogIOManager.
135     * @param clazz the NamedBean class that should be registered in this manager
136     * @param manager the manager that managers the NamedBeans of type clazz
137     */
138    @Override
139    public void addBeanType(Class<? extends AnalogIO> clazz, Manager<? extends NamedBean> manager) {
140        registerBeans.add(clazz);
141        manager.addPropertyChangeListener("beans", this);
142        
143        // Add all the existing beans to the manager
144        Manager<AnalogIO> internalManager = initInternal();
145        muteUpdates = true;
146        for (NamedBean bean : manager.getNamedBeanSet()) {
147            internalManager.register((AnalogIO) bean);
148        }
149        muteUpdates = false;
150    }
151
152    /**
153     * Remove a type of NamedBean, for example VariableLight, from beeing registred in AnalogIOManager.
154     * @param clazz the NamedBean class that should be registered in this manager
155     * @param manager the manager that managers the NamedBeans of type clazz
156     */
157    @Override
158    public void removeBeanType(Class<? extends AnalogIO> clazz, Manager<? extends NamedBean> manager) {
159        manager.removePropertyChangeListener("beans", this);
160        registerBeans.remove(clazz);
161    }
162
163//    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ProxyAnalogIOManager.class);
164
165}