001package jmri.jmrix.roco.z21;
002
003import java.util.Locale;
004import jmri.Manager;
005import jmri.Manager.NameValidity;
006import jmri.NamedBean;
007import org.slf4j.Logger;
008import org.slf4j.LoggerFactory;
009
010import javax.annotation.Nonnull;
011
012/**
013 * Utility Class supporting parsing and testing of addresses for Z21 RMBus
014 * <p>
015 * One address format are supported:
016 * <ul>
017 * <li>
018 * ZSxxxx where: 'S' for sensors,
019 * </li>
020 * </ul>
021 *
022 * @author Dave Duchamp, Copyright (C) 2004 - 2006
023 * @author Bob Coleman Copyright (C) 2007, 2008, 2009
024 * @author Egbert Broerse (C) 2017 Based on Acela example, modified for XpressNet.
025 */
026public class Z21RMBusAddress {
027
028    private Z21RMBusAddress() {
029        // class of static functions
030    }
031
032    static final int MINSENSORADDRESS = 1;
033    static final int MAXSENSORADDRESS = 160; // 20 RM bus modules with 8 contacts each.
034
035    /**
036     * Public static method to parse a Z21RMBus system name.Note: Bits are numbered from 1.
037     *
038     * @param systemName system name.
039     * @param prefix system prefix.
040     * @return the hardware address number, return -1 if an error is found
041     */
042    public static int getBitFromSystemName(String systemName, String prefix) {
043        // validate the system Name leader characters
044        if (!systemName.startsWith(prefix)) {
045            // here if an invalid Z21 RM Bus system name
046            log.error("invalid character in header field of Z21 RM Bus system name: {}", systemName);
047            return (-1);
048        }
049        int num;
050        try {
051            String curAddress = systemName.substring(prefix.length() + 1);
052            num = Integer.parseInt(curAddress);
053        } catch (NumberFormatException e) {
054            log.warn("invalid character in number field of system name: {}", systemName);
055            return (-1);
056        }
057        if ((num >= MINSENSORADDRESS) && (num <= MAXSENSORADDRESS)) {
058            return (num);
059        }
060        log.warn("Z21 RM Bus hardware address out of range in system name {}", systemName);
061        return (-1);
062    }
063
064    /**
065     * Validate a system name format.
066     *
067     * @param name    the name to validate
068     * @param manager the manager requesting validation
069     * @param locale  the locale for user messages
070     * @return name, unchanged
071     * @see jmri.Manager#validateSystemNameFormat(java.lang.String,
072     * java.util.Locale)
073     */
074    public static String validateSystemNameFormat(String name, Manager<?> manager, Locale locale) {
075        try {
076            return manager.validateIntegerSystemNameFormat(name, 1, 160, locale);
077        } catch (NumberFormatException ex) {
078            throw new NamedBean.BadSystemNameException(
079                    Bundle.getMessage(Locale.ENGLISH, "SystemNameInvalidRMAddress", name),
080                    Bundle.getMessage(locale, "SystemNameInvalidRMAddress", name));
081        }
082    }
083
084    /**
085     * Public static method to validate system name format.
086     * Logging of handled cases no higher than WARN.
087     *
088     * @param systemName system name.
089     * @param type bean type, S for Sensor, T for Turnout.
090     * @param prefix system prefix.
091     * @return VALID if system name has a valid format, else return INVALID
092     */
093    public static NameValidity validSystemNameFormat(@Nonnull String systemName, char type, String prefix) {
094        // validate the system Name leader characters
095        if (!(systemName.startsWith(prefix + type))) {
096            // here if an illegal format
097            log.error("invalid character in header field of system name: {}", systemName);
098            return NameValidity.INVALID;
099        }
100        int address = getBitFromSystemName(systemName,prefix);
101        if (address >= 0 && address <= 160 ) {
102            return NameValidity.VALID;
103        } else {
104            return NameValidity.INVALID;
105        }
106    }
107
108    /**
109     * Public static method to check the user name for a valid system name.
110     *
111     * @param systemName system name.
112     * @param prefix system prefix.
113     * @return "" (null string) if the system name is not valid or does not exist
114     */
115    public static String getUserNameFromSystemName(String systemName, String prefix) {
116        // check for a valid system name
117        if ((systemName.length() < (prefix.length() + 2)) || (!systemName.startsWith(prefix))) {
118            // not a valid system name for Z21 RM Bus
119            return ("");
120        }
121        // check for a sensor
122        if (systemName.charAt(prefix.length() + 1) == 'S') {
123            jmri.Sensor s;
124            s = jmri.InstanceManager.sensorManagerInstance().getBySystemName(systemName);
125            if (s != null) {
126                return s.getUserName();
127            } else {
128                return ("");
129            }
130        }
131        // not any known sensor
132        return ("");
133    }
134
135    private static final Logger log = LoggerFactory.getLogger(Z21RMBusAddress.class);
136
137}