001package jmri.jmrix.loconet;
002
003import java.util.Locale;
004import javax.annotation.Nonnull;
005import jmri.Reporter;
006import org.slf4j.Logger;
007import org.slf4j.LoggerFactory;
008
009/**
010 * Manage the LocoNet-specific Reporter implementation.
011 * <p>
012 * System names are "LRnnn", where L is the user configurable system prefix,
013 * nnn is the Reporter number without padding.
014 * <p>
015 * Some of the message formats used in this class are Copyright Digitrax, Inc.
016 * and used with permission as part of the JMRI project. That permission does
017 * not extend to uses in other software products. If you wish to use this code,
018 * algorithm or these message formats outside of JMRI, please contact Digitrax
019 * Inc for separate permission.
020 *
021 * @author Bob Jacobsen Copyright (C) 2001
022 */
023public class LnReporterManager extends jmri.managers.AbstractReporterManager implements LocoNetListener {
024
025    protected final LnTrafficController tc;
026
027    // ctor has to register for LocoNet events
028    public LnReporterManager(LocoNetSystemConnectionMemo memo) {
029        super(memo);
030        tc = memo.getLnTrafficController();
031        if (tc != null) {
032            tc.addLocoNetListener(~0, this);
033        } else {
034            log.error("No layout connection, Reporter manager can't function");
035        }
036    }
037
038    /**
039     * {@inheritDoc}
040     */
041    @Override
042    @Nonnull
043    public LocoNetSystemConnectionMemo getMemo() {
044        return (LocoNetSystemConnectionMemo) memo;
045    }
046
047    @Override
048    public void dispose() {
049        if (tc != null) {
050            tc.removeLocoNetListener(~0, this);
051        }
052        super.dispose();
053    }
054
055    @Override
056    @Nonnull
057    protected Reporter createNewReporter(@Nonnull String systemName, String userName) throws IllegalArgumentException {
058        Reporter t;
059        int addr = Integer.parseInt(systemName.substring(getSystemNamePrefix().length()));
060        t = new LnReporter(addr, tc, getSystemPrefix());
061        t.setUserName(userName);
062        t.addPropertyChangeListener(this);
063
064        return t;
065    }
066
067    /**
068     * {@inheritDoc}
069     */
070    @Override
071    public NameValidity validSystemNameFormat(@Nonnull String systemName) {
072        return (getBitFromSystemName(systemName) != 0) ? NameValidity.VALID : NameValidity.INVALID;
073    }
074
075    /**
076     * {@inheritDoc}
077     */
078    @Override
079    @Nonnull
080    public String validateSystemNameFormat(@Nonnull String systemName, @Nonnull Locale locale) {
081        return validateIntegerSystemNameFormat(systemName, 1, 4096, locale);
082    }
083
084    /**
085     * Get the bit address from the system name.
086     * @param systemName a valid LocoNet-based Reporter System Name
087     * @return the turnout number extracted from the system name
088     */
089    public int getBitFromSystemName(String systemName) {
090        try {
091            validateSystemNameFormat(systemName, Locale.getDefault());
092        } catch (IllegalArgumentException ex) {
093            return 0;
094        }
095        return Integer.parseInt(systemName.substring(getSystemNamePrefix().length()));
096    }
097
098    /**
099     * {@inheritDoc}
100     */
101    @Override
102    public String getEntryToolTip() {
103        return Bundle.getMessage("AddInputEntryToolTip");
104    }
105
106    // listen for transponder messages, creating Reporters as needed
107    @Override
108    public void message(LocoNetMessage l) {
109        // check message type
110        int addr;
111        switch (l.getOpCode()) {
112            case LnConstants.OPC_MULTI_SENSE:
113                if ((l.getElement(1) & 0xC0) == 0) {
114                    addr = (l.getElement(1) & 0x1F) * 128 + l.getElement(2) + 1;
115                    break;
116                }
117                return;
118            case LnConstants.OPC_PEER_XFER:
119                if (l.getElement(1) == 0x09 && l.getElement(2) == 0x00) {
120                    addr = (l.getElement(5) & 0x1F) * 128 + l.getElement(6) + 1;
121                    break;
122                }
123                return;
124            case LnConstants.OPC_LISSY_UPDATE:
125                if (l.getElement(1) == 0x08) {
126                    addr =  (l.getElement(4) & 0x7F);
127                    break;
128                }
129                return;
130            default:
131                return;
132        }
133        log.debug("Message for Reporter[{}]", addr);
134        LnReporter r = (LnReporter) provideReporter(getSystemNamePrefix() + addr); // NOI18N
135        r.messageFromManager(l); // make sure it got the message
136    }
137
138    private final static Logger log = LoggerFactory.getLogger(LnReporterManager.class);
139
140}