001package jmri.jmrix.roco.z21.swing.mon;
002
003import jmri.jmrix.Message;
004import jmri.jmrix.roco.z21.*;
005import org.reflections.Reflections;
006import org.slf4j.Logger;
007import org.slf4j.LoggerFactory;
008
009import java.lang.reflect.Constructor;
010import java.lang.reflect.InvocationTargetException;
011import java.util.ArrayList;
012import java.util.List;
013import java.util.Set;
014
015/**
016 * Panel displaying (and logging) Z21 messages derived from Z21MonFrame.
017 *
018 * @author Bob Jacobsen Copyright (C) 2002
019 * @author Paul Bender Copyright (C) 2004-2024
020 * @author Giorgio Terdina Copyright (C) 2007
021 */
022public class Z21MonPane extends jmri.jmrix.AbstractMonPane implements Z21Listener {
023
024    protected Z21SystemConnectionMemo memo = null;
025
026    private List<Z21MessageFormatter> formatterList;
027
028    @Override
029    public String getTitle() {
030        return (Bundle.getMessage("Z21TrafficTitle"));
031    }
032
033    @Override
034    public void initContext(Object context) {
035        if (context instanceof Z21SystemConnectionMemo) {
036            memo = (Z21SystemConnectionMemo) context;
037            // connect to the TrafficController
038            memo.getTrafficController().addz21Listener(this);
039            try {
040                formatterList = new ArrayList<>();
041
042                Reflections reflections = new Reflections("jmri.jmrix.roco.z21");
043                Set<Class<? extends Z21MessageFormatter>> f = reflections.getSubTypesOf(Z21MessageFormatter.class);
044                for(Class<?> c : f){
045                    log.debug("Found formatter: {}", f.getClass().getName());
046                    Constructor<?> ctor = c.getConstructor();
047                    formatterList.add((Z21MessageFormatter) ctor.newInstance());
048                }
049            } catch (NoSuchMethodException | SecurityException | InstantiationException |
050                     IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
051                log.error("Error instantiating formatter", e);
052            }
053        }
054    }
055
056    /**
057     * Initialize the data source.
058     */
059    @Override
060    protected void init() {
061    }
062
063    @Override
064    public void dispose() {
065        // disconnect from the TrafficController
066        memo.getTrafficController().removez21Listener(this);
067        // and unwind swing
068        super.dispose();
069    }
070
071    @Override
072    public void logMessage(String messagePrefix, String rawPrefix, Message message){
073        // display the raw data if requested
074        StringBuilder raw = new StringBuilder(rawPrefix);
075        if (rawCheckBox.isSelected()) {
076            raw.append(message.toString());
077        }
078
079        // display the decoded data
080        String text = formatterList.stream()
081                .filter(f -> f.handlesMessage(message))
082                .findFirst().map(f -> f.formatMessage(message))
083                .orElse(message.toString());
084        nextLine(messagePrefix + " " + text + "\n", raw.toString());
085    }
086
087    @Override
088    public synchronized void reply(Z21Reply l) { // receive an XpressNet message and log it
089        logMessage(l);
090    }
091
092    /**
093     * Listen for the messages to the LI100/LI101
094     */
095    @Override
096    public synchronized void message(Z21Message l) {
097        logMessage(l);
098    }
099
100    /**
101     * Nested class to create one of these using old-style defaults
102     */
103    static public class Default extends jmri.util.swing.JmriNamedPaneAction {
104
105        public Default() {
106            super(Bundle.getMessage("Z21TrafficTitle"),
107                    Z21MonPane.class.getName());
108            setContext(jmri.InstanceManager.
109                    getDefault(Z21SystemConnectionMemo.class));
110        }
111    }
112    private static final Logger log = LoggerFactory.getLogger(Z21MonPane.class);
113
114}