001package jmri.jmrix.dccpp;
002
003import static jmri.jmrix.dccpp.DCCppConstants.MAX_TURNOUT_ADDRESS;
004import java.util.ArrayList;
005import java.util.List;
006import javax.annotation.Nonnull;
007import java.util.Locale;
008import jmri.Light;
009import jmri.NamedBean;
010import jmri.NamedBeanPropertyDescriptor;
011import jmri.SelectionPropertyDescriptor;
012import jmri.managers.AbstractLightManager;
013
014/**
015 * Implement LightManager for DCC-EX systems.
016 * <p>
017 * System names are "DxppSnnn", where Dx is the system prefix and nnn is the sensor number without padding.
018 * <p>
019 * Based in part on SerialLightManager.java
020 *
021 * @author Paul Bender Copyright (C) 2008
022 * @author Mark Underwood Copyright (C) 2015
023 */
024public class DCCppLightManager extends AbstractLightManager {
025
026    private DCCppTrafficController tc = null;
027
028    /**
029     * Create an new DCC-EX LightManager.
030     * Has to register for DCC-EX events.
031     *
032     * @param memo the supporting system connection memo
033     */
034    public DCCppLightManager(DCCppSystemConnectionMemo memo) {
035        super(memo);
036        this.tc = memo.getDCCppTrafficController();
037    }
038
039    /**
040     * {@inheritDoc}
041     */
042    @Override
043    @Nonnull
044    public DCCppSystemConnectionMemo getMemo() {
045        return (DCCppSystemConnectionMemo) memo;
046    }
047
048    /**
049     * Create a new Light based on the system name.
050     * Assumes calling method has checked that a Light with this
051     * system name does not already exist.
052     *
053     * @return null if the system name is not in a valid format
054     */
055    @Override
056    @Nonnull
057    protected Light createNewLight(String systemName, String userName) throws IllegalArgumentException {
058        // check if the output bit is available
059        int bitNum = getBitFromSystemName(systemName);
060        if (bitNum == 0) {
061            throw new IllegalArgumentException("Invalid Bit from System Name: " + systemName);
062        }
063        // Normalize the systemName
064        String sName = getSystemNamePrefix() + bitNum;   // removes any leading zeros
065        // make the new Light object
066        return new DCCppLight(tc, this, sName, userName);
067    }
068
069    /**
070     * {@inheritDoc}
071     */
072    @Override
073    public NameValidity validSystemNameFormat(@Nonnull String systemName) {
074        return (getBitFromSystemName(systemName) != 0) ? NameValidity.VALID : NameValidity.INVALID;
075    }
076
077    /**
078     * {@inheritDoc}
079     */
080    @Override
081    @Nonnull
082    public String validateSystemNameFormat(@Nonnull String systemName, @Nonnull Locale locale) {
083        return validateIntegerSystemNameFormat(systemName, 1, MAX_TURNOUT_ADDRESS, locale);
084    }
085
086    /**
087     * Get the bit address from the system name.
088     * @param systemName a valid Light System Name
089     * @return the light number extracted from the system name
090     */
091    public int getBitFromSystemName(String systemName) {
092        try {
093            validateSystemNameFormat(systemName, Locale.getDefault());
094        } catch (IllegalArgumentException ex) {
095            return 0;
096        }
097        return Integer.parseInt(systemName.substring(getSystemNamePrefix().length()));
098    }
099
100    /**
101     * {@inheritDoc}
102     */
103    @Override
104    public boolean allowMultipleAdditions(@Nonnull String systemName) {
105        return true;
106    }
107
108    /**
109     * {@inheritDoc}
110     */
111    @Override
112    public String getEntryToolTip() {
113        return Bundle.getMessage("AddOutputEntryToolTip");
114    }
115
116    public static final String DCCPP_LIGHT_MODE_KEY = "LightMode"; // NOI18N
117
118    private static final String[] DCCPP_LIGHT_MODE_TIPS = {
119        "Standard DCC accessory decoder command <a>",       // NOI18N
120        "CS VPIN pin control <z> (DCC-EX v4.2.35+)"        // NOI18N
121    };
122
123    @Override
124    @Nonnull
125    public List<NamedBeanPropertyDescriptor<?>> getKnownBeanProperties() {
126        List<NamedBeanPropertyDescriptor<?>> l = new ArrayList<>();
127        l.add(new SelectionPropertyDescriptor(
128                DCCPP_LIGHT_MODE_KEY, DCCppLight.MODE_NAMES, DCCPP_LIGHT_MODE_TIPS,
129                DCCppLight.MODE_NAMES[0]) {
130            @Override
131            public String getColumnHeaderText() {
132                return "Mode";
133            }
134            @Override
135            public boolean isEditable(NamedBean bean) {
136                return (bean instanceof DCCppLight);
137            }
138        });
139        return l;
140    }
141
142}