001package jmri.managers;
002
003import jmri.JmriException;
004import jmri.PowerManager;
005
006import java.beans.PropertyChangeEvent;
007import java.beans.PropertyChangeListener;
008import java.time.Instant;
009import jmri.beans.PropertyChangeSupport;
010import jmri.SystemConnectionMemo;
011
012/**
013 * Base PowerManager implementation for controlling layout power.
014 * <p>
015 * These are registered when they are added to the InstanceManager
016 *
017 * @author Bob Jacobsen Copyright (C) 2001, 2003, 2010
018 * @author Randall Wood Copyright 2020
019 * @param <M> the type of SystemConnectionMemo supported by this PowerManager
020 */
021abstract public class AbstractPowerManager<M extends SystemConnectionMemo> extends PropertyChangeSupport implements PowerManager {
022
023    protected final M memo;
024    /**
025     * Note that all changes must fire a property change with the old and new values
026     */
027    protected int power = UNKNOWN;
028    private Instant lastOn;
029
030    public AbstractPowerManager(M memo) {
031        this.memo = memo;
032        TimeKeeper tk = new TimeKeeper();
033        AbstractPowerManager.this.addPropertyChangeListener(tk);
034    }
035
036    /**
037     * {@inheritDoc}
038     */
039    @Override
040    public int getPower() {
041        return power;
042    }
043
044    /**
045     * {@inheritDoc}
046     */
047    @Override
048    public void setPower(int state) throws JmriException {
049        int old = power;
050        power = state;
051        firePowerPropertyChange(old, power);
052    }
053
054    /** {@inheritDoc} */
055    @Override
056    public final String getUserName() {
057        return memo.getUserName();
058    }
059
060    // a class for listening for power state changes
061    public class TimeKeeper implements PropertyChangeListener {
062        @Override
063        public void propertyChange(PropertyChangeEvent e) {
064            if (POWER.equals(e.getPropertyName())) {
065                int newPowerState = getPower();
066                if (newPowerState != power) {
067                    power = newPowerState;
068                    if (newPowerState == ON) {
069                        lastOn = Instant.now();
070                    }
071                }
072            }
073        }
074    }
075
076    /**
077     * Returns the amount of time since the layout was last powered up,
078     * in milliseconds. If the layout has not been powered up as far as
079     * JMRI knows it returns a very long time indeed.
080     *
081     * @return long int
082     */
083    public long timeSinceLastPowerOn() {
084        if (lastOn == null) {
085            return Long.MAX_VALUE;
086        }
087        return Instant.now().toEpochMilli() - lastOn.toEpochMilli();
088    }
089
090    /**
091     * Fires a {@link java.beans.PropertyChangeEvent} for the power state using
092     * property name "power".
093     *
094     * @param old the old power state
095     * @param current the new power state
096     */
097    protected final void firePowerPropertyChange(int old, int current) {
098        firePropertyChange(POWER, old, current);
099    }
100}