001package jmri.jmrix.pricom.pockettester;
002
003import java.util.Hashtable;
004import javax.swing.JLabel;
005import javax.swing.JPanel;
006import javax.swing.JTabbedPane;
007import org.slf4j.Logger;
008import org.slf4j.LoggerFactory;
009
010/**
011 * Simple to display DCC status from Pocket Tester.
012 * <p>
013 * For more info on the product, see http://www.pricom.com
014 *
015 * @author Bob Jacobsen Copyright (C) 2005
016 */
017public class StatusFrame extends jmri.util.JmriJFrame implements DataListener {
018
019    javax.swing.Timer timer = new javax.swing.Timer(500, new java.awt.event.ActionListener() {
020        @Override
021        public void actionPerformed(java.awt.event.ActionEvent e) {
022            sendRequest();
023        }
024    });
025
026    JTabbedPane tabPane = new JTabbedPane();
027    Hashtable<String, JLabel> displayHash = new Hashtable<String, JLabel>();
028    Hashtable<String, String> formatHash = new Hashtable<String, String>();
029    DataSource source = null;
030
031    public StatusFrame() {
032        super(Bundle.getMessage("TitleStatus"));
033    }
034
035    /**
036     * Add GUI elements
037     */
038    @Override
039    public void initComponents() {
040        getContentPane().add(tabPane);
041
042        // loop over the auto definitions from the properties file, adding panes
043        // get pane count
044        int numAutoPane = Integer.parseInt(Bundle.getMessage("CSNumAutoPanes"));
045
046        for (int i = 0; i < numAutoPane; i++) {
047            // create and install tabbed pane
048            JPanel p = new JPanel();
049            p.setLayout(new java.awt.GridLayout(0, 2));  // 0 rows is a dummy value
050            tabPane.addTab(Bundle.getMessage("CS" + i + "Title"), p);
051
052            // install variables
053            int numVars = Integer.parseInt(Bundle.getMessage("CS" + i + "NumVars"));
054            for (int j = 0; j < numVars; j++) {
055                p.add(new JLabel(Bundle.getMessage("CS" + i + "Var" + j + "Name")));
056                JLabel val = new JLabel("-----");
057                // record the label and format for later
058                displayHash.put(Bundle.getMessage("CS" + i + "Var" + j + "ID"), val);
059                formatHash.put(Bundle.getMessage("CS" + i + "Var" + j + "ID"), Bundle.getMessage("CS" + i + "Var" + j + "Format"));
060                p.add(val);
061            }
062        }
063
064        // add a listener to hear about selections
065        tabPane.addChangeListener(new javax.swing.event.ChangeListener() {
066            @Override
067            public void stateChanged(javax.swing.event.ChangeEvent e) {
068                sendRequest();  // to get a fast update
069            }
070        }
071        );
072
073        // get ready to display
074        pack();
075
076    }
077
078    protected String title() {
079        return Bundle.getMessage("TitleStatus");
080    }
081
082    // note that the message coming from the unit has
083    // an invisible null character after the "=" in version 1.5.1
084    // but not in later versions
085    @Override
086    public void asciiFormattedMessage(String input) {
087        String m = input + " ";  // extra space to make stripping easier
088        // check if interesting
089        if (!m.substring(0, 1).equals(" ")) {
090            return;
091        }
092        if (!m.substring(3, 4).equals("=")) {
093            return;
094        }
095        int addOne = 0;
096        if (m.substring(4, 5).equals("\000")) {
097            addOne = 1;
098        }
099        // basically OK. Break into tokens, store if match, quit when done.
100        while (m.length() >= 14 + addOne) {
101            String id = m.substring(1, 3);
102            String value = m.substring(4 + addOne, 14 + addOne);
103            if (log.isDebugEnabled()) {
104                log.debug("set var {}:{}", id, value);
105            }
106            JLabel label = displayHash.get(id);
107            String format = formatHash.get(id);
108            if (label != null) {
109                label.setText(convertValue(value, format));
110            }
111            m = m.substring(14 + addOne);
112        }
113    }
114
115    protected String convertValue(String val, String format) {
116        if (format.equals("address")) {
117            // long or short address format
118            int address = Integer.parseInt(val);
119            if (address >= 0x8000) {
120                return "" + (address - 0x8000) + " (long)";
121            } else {
122                return "" + address + " (short)";
123            }
124
125        } else if (format.equals("msec")) {
126            // value is in 10's of nsec, add decimal point for msec
127            return val.substring(0, 5) + "." + val.substring(5) + " msec";
128
129        } else if (format.equals("none")) {
130            // no formatting, used for counts, etc
131            return val; // don't change the content
132
133        } else // didn't find matching format name, warn
134        {
135            return val + " (bad format)";
136        }
137    }
138
139    /**
140     * Time to send the next request
141     */
142    private void sendRequest() {
143        int i = tabPane.getSelectedIndex();
144        String prompt = Bundle.getMessage("CS" + i + "PromptChar");
145        log.debug("send {} for pane {}", prompt, i);
146
147        if (source == null) {
148            log.error("DataSource should not be null in sendRequest");
149            timer.stop();
150            return;
151        }
152
153        source.sendBytes(prompt.getBytes());
154
155    }
156
157    public void setSource(DataSource s) {
158        source = s;
159        // start the timer for updates
160        timer.setRepeats(true);     // in case we run by
161        timer.start();
162    }
163
164    @Override
165    public void dispose() {
166        // stop timer
167        timer.stop();
168        // and clean up parent
169        super.dispose();
170    }
171
172    private final static Logger log = LoggerFactory.getLogger(StatusFrame.class);
173
174}