001package jmri.implementation;
002
003import java.util.*;
004
005import jmri.Meter;
006
007/**
008 * Handles updates of meters. Several meters may share the update task.
009 *
010 * @author Mark Underwood    (C) 2015
011 * @author Daniel Bergqvist  (C) 2020
012 */
013public abstract class MeterUpdateTask {
014
015    Map<Meter, Boolean> meters = new HashMap<>();
016    boolean _enabled = false;
017    private UpdateTask _intervalTask = null;
018    private int _initialInterval; //in ms
019    private int _sleepInterval;   //in ms
020
021    /* default values for both sleepIntervals */
022    public MeterUpdateTask() {
023        _sleepInterval = 10000;
024        _initialInterval = 10000;
025    }
026
027    /* if only one interval passed, set both to same */
028    public MeterUpdateTask(int interval) {
029        _initialInterval = interval;
030        _sleepInterval = interval;
031     }
032
033    public MeterUpdateTask(int initialInterval, int sleepInterval) {
034        _initialInterval = initialInterval;
035        _sleepInterval = sleepInterval;
036     }
037
038    public void addMeter(Meter m) {
039        meters.put(m, false);
040    }
041
042    public void removeMeter(Meter m) {
043        meters.remove(m);
044    }
045
046    public void enable() {
047        if(_intervalTask != null) {
048            _intervalTask.enable();
049        } else {
050            log.debug("_intervalTask is null, enable() ignored");
051        }
052    }
053
054    public void enable(Meter m) {
055        if (!meters.containsKey(m)) {
056            throw new IllegalArgumentException("Meter is not registered");
057        }
058
059        if (!meters.get(m)) {
060            meters.put(m, true);
061            if (!_enabled) {
062                _enabled = true;
063                enable();
064            }
065        }
066    }
067
068    protected void disable() {
069        if(_intervalTask != null) {
070            _intervalTask.disable();
071        }
072    }
073
074    public void disable(Meter m) {
075        if (!meters.containsKey(m)) return;
076
077        if (meters.get(m)) {
078            meters.put(m, false);
079            if (_enabled) {
080                // Is there any more meters that are active?
081                boolean found = false;
082                for (Boolean b : meters.values()) {
083                    found |= b;
084                }
085                if (! found) {
086                    _enabled = false;
087                    disable();
088                }
089            }
090        }
091    }
092
093    public void initTimer() {
094        if(_intervalTask != null) {
095           _intervalTask.cancel();
096           _intervalTask = null;
097        }
098        if(_sleepInterval < 0){
099           log.debug("_sleepInterval {} less than zero, initTimer() ignored", _sleepInterval);
100           return; // don't start or restart the timer.
101        }
102        _intervalTask = new UpdateTask();
103        // At some point this will be dynamic intervals...
104        log.debug("Starting Meter Timer for {}ms, {}ms", _initialInterval, _sleepInterval);
105        jmri.util.TimerUtil.scheduleAtFixedRate(_intervalTask,
106                _initialInterval, _sleepInterval);
107    }
108
109    public abstract void requestUpdateFromLayout();
110
111    /**
112     * Remove references to and from this object, so that it can eventually be
113     * garbage-collected.
114     * @param m the meter that is calling dispose
115     */
116    public void dispose(Meter m){
117        removeMeter(m);
118        if (meters.isEmpty() && (_intervalTask != null)) {
119           _intervalTask.cancel();
120           _intervalTask = null;
121        }
122    }
123
124
125    // Timer task for periodic updates...
126    private class UpdateTask extends TimerTask {
127
128        private boolean _isEnabled = false;
129
130        public UpdateTask() {
131            super();
132        }
133
134        public void enable() {
135            _isEnabled = true;
136        }
137
138        public void disable() {
139            _isEnabled = false;
140        }
141
142        @Override
143        public void run() {
144            if (_isEnabled) {
145                log.debug("UpdateTask requesting update from layout");
146                requestUpdateFromLayout();
147            } else {
148                log.debug("UpdateTask not enabled, run() ignored");
149            }
150        }
151    }
152
153    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MeterUpdateTask.class);
154}