001package jmri.jmrix.marklin;
002
003import javax.annotation.Nonnull;
004import jmri.JmriException;
005import jmri.Turnout;
006
007/**
008 * Implement turnout manager for Marklin systems.
009 * <p>
010 * System names use an optional protocol prefix followed by a 1-based address:
011 * <ul>
012 *   <li>{@code MTDCC45}  DCC accessory address 45</li>
013 *   <li>{@code MTMM123}  MM/MM2 accessory address 123</li>
014 *   <li>{@code MTCAN200} raw CAN wire address 200 (vendor/club range)</li>
015 *   <li>{@code MT45}     legacy unprefixed, treated as DCC</li>
016 * </ul>
017 * <p>
018 * Based on work by Bob Jacobsen
019 *
020 * @author Kevin Dickerson Copyright (C) 2012
021 * @author Ralf Lang
022 */
023public class MarklinTurnoutManager extends jmri.managers.AbstractTurnoutManager {
024
025    /** Regex for the address portion after stripping system-prefix + type letter. */
026    private static final java.util.regex.Pattern ADDRESS_PATTERN =
027            java.util.regex.Pattern.compile("^(MM|DCC|CAN)?(\\d+)$");
028
029    public MarklinTurnoutManager(MarklinSystemConnectionMemo memo) {
030        super(memo);
031        tc = memo.getTrafficController();
032    }
033
034    private final MarklinTrafficController tc;
035
036    /** {@inheritDoc} */
037    @Override
038    @Nonnull
039    public MarklinSystemConnectionMemo getMemo() {
040        return (MarklinSystemConnectionMemo) memo;
041    }
042
043    /**
044     * {@inheritDoc}
045     * <p>
046     * Accepts {@code MM123}, {@code DCC45}, {@code CAN200} or plain {@code 123}
047     * Unprefixed defaults to DCC for BC reasons.
048     * The prefix and number are passed through verbatim.
049     * The full system name becomes e.g. {@code MTDCC123}.
050     */
051    @Override
052    @Nonnull
053    public String createSystemName(@Nonnull String curAddress, @Nonnull String prefix) throws JmriException {
054        if (!ADDRESS_PATTERN.matcher(curAddress).matches()) {
055            throw new JmriException("Invalid Marklin turnout address '" + curAddress
056                    + "'. Use MM<n>, DCC<n>, CAN<n>, or plain <n> (defaults to DCC).");
057        }
058        return prefix + typeLetter() + curAddress;
059    }
060
061    /** {@inheritDoc} */
062    @Override
063    public jmri.Manager.NameValidity validSystemNameFormat(@Nonnull String systemName) {
064        String addr = systemName.substring(getSystemPrefix().length() + 1); // strip e.g. "MT"
065        return ADDRESS_PATTERN.matcher(addr).matches()
066                ? jmri.Manager.NameValidity.VALID : jmri.Manager.NameValidity.INVALID;
067    }
068
069    /** {@inheritDoc} */
070    @Override
071    @Nonnull
072    public String validateSystemNameFormat(@Nonnull String systemName, @Nonnull java.util.Locale locale)
073            throws jmri.NamedBean.BadSystemNameException {
074        systemName = validateSystemNamePrefix(systemName, locale);
075        if (validSystemNameFormat(systemName) != jmri.Manager.NameValidity.VALID) {
076            throw new jmri.NamedBean.BadSystemNameException(locale,
077                    "InvalidSystemNameNotInteger", systemName, getSystemNamePrefix());
078        }
079        return systemName;
080    }
081
082    /** {@inheritDoc} */
083    @Override
084    @Nonnull
085    protected Turnout createNewTurnout(@Nonnull String systemName, String userName) throws IllegalArgumentException {
086        Turnout t = new MarklinTurnout(systemName, getSystemPrefix(), tc);
087        t.setUserName(userName);
088        return t;
089    }
090
091    /** {@inheritDoc} */
092    @Override
093    public String getEntryToolTip() {
094        return Bundle.getMessage("TurnoutEntryToolTip");
095    }
096
097    /** {@inheritDoc} */
098    @Override
099    public boolean allowMultipleAdditions(@Nonnull String systemName) {
100        return true;
101    }
102
103}