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