001package jmri.jmrix.can.cbus.swing.console;
002
003import java.util.LinkedList;
004import java.util.TimerTask;
005
006import javax.swing.BorderFactory;
007import javax.swing.JButton;
008import javax.swing.JTextField;
009
010/**
011 * Panel for CBUS Console Stats
012 *
013 * @author Andrew Crosland Copyright (C) 2008
014 * @author Steve Young Copyright (C) 2018
015 */
016public class CbusConsoleStatsPane extends javax.swing.JPanel {
017
018    private JTextField sentCountField;
019    private JTextField rcvdCountField;
020    private JTextField eventsCountField;
021    private JTextField dccCountField;
022    private JTextField totalCountField;
023    private JTextField framesLastSecondField;
024    private JTextField meanFramesPerSecondField;
025    private JTextField maxFramesPerSecondField;
026    private JButton statsClearButton;
027
028    private int sentTotal = 0;
029    private int rcvdTotal = 0;
030    private int eventTotal = 0;
031    private int dccTotal = 0;
032    private int total = 0;
033    private int maxPerSecondCount = 0;
034    private long startTime;
035
036    private final LinkedList<Long> frameTimes;
037    private transient TimerTask keepAliveTimer = null;
038    private boolean disposed = false;
039
040    public CbusConsoleStatsPane(CbusConsolePane mainPane){
041        super();
042        frameTimes = new LinkedList<>();
043        initButtons();
044        addToPanel();
045        CbusConsoleStatsPane.this.setLayout(new jmri.util.swing.WrapLayout());
046    }
047
048    private void addToPanel() {
049
050        setBorder(BorderFactory.createTitledBorder(
051            BorderFactory.createEtchedBorder(), Bundle.getMessage("StatisticsTitle")));
052        add(sentCountField);
053        add(rcvdCountField);
054        add(totalCountField);
055        add(eventsCountField);
056        add(dccCountField);
057        add(framesLastSecondField);
058        add(meanFramesPerSecondField);
059        add(maxFramesPerSecondField);
060
061        add(statsClearButton);
062        statsClearButton.addActionListener(this::statsClearButtonActionPerformed);
063        startUpdateTimer();
064
065    }
066
067    protected void incremenetTotal(){
068        total++;
069        long currentTime = System.currentTimeMillis();
070        frameTimes.add(currentTime);
071        countFramesInLastSecond(currentTime); // update Max value
072    }
073
074    protected void incremenetReceived(){
075        rcvdTotal++;
076    }
077
078    protected void incremenetSent(){
079        sentTotal++;
080    }
081
082    protected void incrementEvents() {
083        eventTotal++;
084    }
085
086    protected void incrementDcc() {
087        dccTotal++;
088    }
089
090    private void initButtons() {
091        sentCountField = new JTextField("0", 7);
092        rcvdCountField = new JTextField("0", 7);
093        eventsCountField = new JTextField("0", 7);
094        dccCountField = new JTextField("0", 7);
095        totalCountField = new JTextField("0", 7);
096        framesLastSecondField = new JTextField("0", 7);
097        meanFramesPerSecondField = new JTextField("0", 7);
098        maxFramesPerSecondField = new JTextField("0", 7);
099        statsClearButton = new JButton();
100        initButtonBorderToolTips();
101    }
102
103    private void initButtonBorderToolTips(){
104
105        sentCountField.setToolTipText(Bundle.getMessage("TooltipSent"));
106        sentCountField.setBorder(BorderFactory.createTitledBorder(
107                BorderFactory.createEtchedBorder(), Bundle.getMessage("SentTitle")));
108
109        rcvdCountField.setToolTipText(Bundle.getMessage("TooltipReceived"));
110        rcvdCountField.setBorder(BorderFactory.createTitledBorder(
111                BorderFactory.createEtchedBorder(), Bundle.getMessage("ReceivedTitle")));
112
113        eventsCountField.setToolTipText(Bundle.getMessage("eventsCountFieldTip"));
114        eventsCountField.setBorder(BorderFactory.createTitledBorder(
115                BorderFactory.createEtchedBorder(), Bundle.getMessage("CbusEvents")));
116
117        dccCountField.setToolTipText(Bundle.getMessage("dccCountFieldTip"));
118        dccCountField.setBorder(BorderFactory.createTitledBorder(
119                BorderFactory.createEtchedBorder(), Bundle.getMessage("dccCountField")));
120
121        totalCountField.setToolTipText(Bundle.getMessage("totalCountFieldTip"));
122        totalCountField.setBorder(BorderFactory.createTitledBorder(
123                BorderFactory.createEtchedBorder(), Bundle.getMessage("totalCountField")));
124
125        framesLastSecondField.setToolTipText(Bundle.getMessage("FramesPerSecondTip"));
126        framesLastSecondField.setBorder(BorderFactory.createTitledBorder(
127                BorderFactory.createEtchedBorder(), Bundle.getMessage("FramesPerSecond")));
128
129        meanFramesPerSecondField.setToolTipText(Bundle.getMessage("AverageFramesPerSecondTip"));
130        meanFramesPerSecondField.setBorder(BorderFactory.createTitledBorder(
131                BorderFactory.createEtchedBorder(), Bundle.getMessage("AverageFramesPerSecond")));
132
133        maxFramesPerSecondField.setToolTipText(Bundle.getMessage("MaxFramesPerSecondTip"));
134        maxFramesPerSecondField.setBorder(BorderFactory.createTitledBorder(
135                BorderFactory.createEtchedBorder(), Bundle.getMessage("MaxFramesPerSecond")));
136
137        statsClearButton.setText(Bundle.getMessage("ButtonReset"));
138        statsClearButton.setVisible(true);
139    }
140
141    private void statsClearButtonActionPerformed(java.awt.event.ActionEvent e) {
142        frameTimes.clear();
143        startTime = System.currentTimeMillis();
144        sentTotal = 0;
145        rcvdTotal = 0;
146        eventTotal = 0;
147        dccTotal = 0;
148        total = 0;
149        maxPerSecondCount = 0;
150    }
151
152    /**
153     * Set up the GUI Update Timer, and start it.
154     */
155    private void startUpdateTimer() {
156        disposed = false;
157        startTime = System.currentTimeMillis();
158        keepAliveTimer = new TimerTask(){
159            @Override
160            public void run () {
161                if ( disposed ) {
162                    return;
163                }
164                long currentTime = System.currentTimeMillis();
165                float secsDuration = (currentTime-startTime)/1000f;
166                framesLastSecondField.setText(Integer.toString(
167                    countFramesInLastSecond(currentTime)));
168                maxFramesPerSecondField.setText(Integer.toString(maxPerSecondCount));
169                float average = total / secsDuration;
170                meanFramesPerSecondField.setText(String.format("%.01f", average));
171                totalCountField.setText(Integer.toString(total));
172                rcvdCountField.setText(Integer.toString(rcvdTotal));
173                sentCountField.setText(Integer.toString(sentTotal));
174                eventsCountField.setText(Integer.toString(eventTotal));
175                dccCountField.setText(Integer.toString(dccTotal));
176                statsClearButton.setToolTipText(Bundle.getMessage("ResetButtonLastRestTip",
177                    String.format("%.01f", secsDuration)));
178                jmri.util.TimerUtil.scheduleOnGUIThread(keepAliveTimer, 500);
179            }
180        };
181        jmri.util.TimerUtil.scheduleOnGUIThread(keepAliveTimer, 500);
182    }
183
184    private int countFramesInLastSecond(long currentTime) {
185        while (!frameTimes.isEmpty() && currentTime - frameTimes.peek() > 1000) {
186            frameTimes.remove(); // Remove Frames older than 1 second
187        }
188        maxPerSecondCount = Math.max(maxPerSecondCount, frameTimes.size());
189        return frameTimes.size();
190    }
191
192    public void dispose() {
193        disposed = true; // cancels GUI updates
194        if (keepAliveTimer != null) {
195            keepAliveTimer.cancel();
196            keepAliveTimer = null;
197        }
198    }
199
200    // private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CbusConsoleStatsPane.class);
201
202}