001package jmri.jmrit.logixng.implementation;
002
003import java.util.ArrayList;
004import java.util.List;
005import java.util.Map;
006import java.util.HashMap;
007import java.util.ServiceLoader;
008
009import javax.annotation.Nonnull;
010
011import jmri.InstanceManager;
012import jmri.InvokeOnGuiThread;
013import jmri.jmrit.logixng.*;
014import jmri.util.LoggingUtil;
015import jmri.util.ThreadingUtil;
016
017/**
018 * Class providing the basic logic of the DigitalBooleanActionManager interface.
019 * 
020 * @author Dave Duchamp       Copyright (C) 2007
021 * @author Daniel Bergqvist   Copyright (C) 2018
022 */
023public class DefaultDigitalBooleanActionManager extends AbstractBaseManager<MaleDigitalBooleanActionSocket>
024        implements DigitalBooleanActionManager {
025
026    private final Map<Category, List<Class<? extends Base>>> actionClassList = new HashMap<>();
027    private MaleSocket _lastRegisteredBean;
028
029    
030    public DefaultDigitalBooleanActionManager() {
031        InstanceManager.getDefault(LogixNG_Manager.class).registerManager(this);
032        
033        for (DigitalBooleanActionFactory actionFactory : ServiceLoader.load(DigitalBooleanActionFactory.class)) {
034            actionFactory.init();
035        }
036        
037        for (Category category : Category.values()) {
038            actionClassList.put(category, new ArrayList<>());
039        }
040        
041        for (DigitalBooleanActionFactory actionFactory : ServiceLoader.load(DigitalBooleanActionFactory.class)) {
042            actionFactory.getClasses().forEach((entry) -> {
043//                System.out.format("Add action: %s, %s%n", entry.getKey().name(), entry.getValue().getName());
044                actionClassList.get(entry.getKey()).add(entry.getValue());
045            });
046        }
047        
048        for (MaleDigitalBooleanActionSocketFactory maleSocketFactory : ServiceLoader.load(MaleDigitalBooleanActionSocketFactory.class)) {
049            _maleSocketFactories.add(maleSocketFactory);
050        }
051    }
052
053    /** {@inheritDoc} */
054    @Override
055    public Class<? extends MaleSocket> getMaleSocketClass() {
056        return DefaultMaleDigitalBooleanActionSocket.class;
057    }
058
059    protected MaleDigitalBooleanActionSocket createMaleActionSocket(DigitalBooleanActionBean action) {
060        MaleDigitalBooleanActionSocket socket = new DefaultMaleDigitalBooleanActionSocket(this, action);
061        action.setParent(socket);
062        return socket;
063    }
064
065    /** {@inheritDoc} */
066    @Override
067    public MaleSocket getLastRegisteredMaleSocket() {
068        return _lastRegisteredBean;
069    }
070    
071    /** {@inheritDoc} */
072    @Override
073    public MaleDigitalBooleanActionSocket registerBean(MaleDigitalBooleanActionSocket maleSocket) {
074        MaleDigitalBooleanActionSocket bean = super.registerBean(maleSocket);
075        _lastRegisteredBean = maleSocket;
076        return bean;
077    }
078    
079    /**
080     * Remember a NamedBean Object created outside the manager.
081     * This method creates a MaleDigitalBooleanActionSocket for the action.
082     *
083     * @param action the bean
084     */
085    @Override
086    public MaleDigitalBooleanActionSocket registerAction(@Nonnull DigitalBooleanActionBean action)
087            throws IllegalArgumentException {
088        
089        if (action instanceof MaleDigitalBooleanActionSocket) {
090            throw new IllegalArgumentException("registerAction() cannot register a MaleDigitalBooleanActionSocket. Use the method register() instead.");
091        }
092        
093        // Check if system name is valid
094        if (this.validSystemNameFormat(action.getSystemName()) != NameValidity.VALID) {
095            log.warn("SystemName {} is not in the correct format", action.getSystemName() );
096            throw new IllegalArgumentException(String.format("System name is invalid: %s", action.getSystemName()));
097        }
098        
099        // Keep track of the last created auto system name
100        updateAutoNumber(action.getSystemName());
101        
102        // save in the maps
103        MaleDigitalBooleanActionSocket maleSocket = createMaleActionSocket(action);
104        return registerBean(maleSocket);
105    }
106    
107    @Override
108    public int getXMLOrder() {
109        return LOGIXNG_DIGITAL_BOOLEAN_ACTIONS;
110    }
111
112    @Override
113    public char typeLetter() {
114        return 'Q';
115    }
116
117    /*.*
118     * Test if parameter is a properly formatted system name.
119     *
120     * @param systemName the system name
121     * @return enum indicating current validity, which might be just as a prefix
122     *./
123    @Override
124    public NameValidity validSystemNameFormat(String systemName) {
125        return LogixNG_Manager.validSystemNameFormat(
126                getSubSystemNamePrefix(), systemName);
127    }
128*/
129    @Override
130    public FemaleDigitalBooleanActionSocket createFemaleSocket(
131            Base parent, FemaleSocketListener listener, String socketName) {
132        return new DefaultFemaleDigitalBooleanActionSocket(parent, listener, socketName);
133    }
134
135    @Override
136    public Map<Category, List<Class<? extends Base>>> getActionClasses() {
137        return actionClassList;
138    }
139
140    /** {@inheritDoc} */
141    @Override
142    public String getBeanTypeHandled(boolean plural) {
143        return Bundle.getMessage(plural ? "BeanNameDigitalBooleanActions" : "BeanNameDigitalBooleanAction");
144    }
145
146    /** {@inheritDoc} */
147    @Override
148    public void deleteDigitalBooleanAction(MaleDigitalBooleanActionSocket x) {
149        // delete the MaleDigitalBooleanActionSocket
150        deregister(x);
151        x.dispose();
152    }
153    
154    static volatile DefaultDigitalBooleanActionManager _instance = null;
155
156    @InvokeOnGuiThread  // this method is not thread safe
157    static public DefaultDigitalBooleanActionManager instance() {
158        if (!ThreadingUtil.isGUIThread()) {
159            LoggingUtil.warnOnce(log, "instance() called on wrong thread");
160        }
161        
162        if (_instance == null) {
163            _instance = new DefaultDigitalBooleanActionManager();
164        }
165        return (_instance);
166    }
167
168    @Override
169    public Class<MaleDigitalBooleanActionSocket> getNamedBeanClass() {
170        return MaleDigitalBooleanActionSocket.class;
171    }
172
173    @Override
174    protected MaleDigitalBooleanActionSocket castBean(MaleSocket maleSocket) {
175        return (MaleDigitalBooleanActionSocket)maleSocket;
176    }
177
178
179    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultDigitalBooleanActionManager.class);
180
181}