001package jmri.implementation;
002
003import java.beans.PropertyChangeListener;
004import java.util.List;
005
006import jmri.*;
007
008/**
009 * A programmer which supports permissions.
010 * @author Daniel Bergqvist Copyright (C) 2025
011 */
012public class PermissionProgrammer implements jmri.Programmer {
013
014    /**
015     * The minimum time to pass between requests to trigger an user request.
016     * During programming, JMRI might do thousands write requests, and to
017     * prevent that the user has to answer on each of these, this time needs
018     * to pass between two request to result in an user request to tell the
019     * user that permissions are denied.
020     */
021    private static final long THROTTLE_USER_REQUEST_TIME = 3000;  // time in milliseconds
022
023    private long _throttleUserRequestTime = 0L;
024
025    protected final Programmer _programmer;
026
027    public PermissionProgrammer(Programmer programmer) {
028        this._programmer = programmer;
029    }
030
031    protected boolean throttleUserRequest() {
032        long oldTime = _throttleUserRequestTime;
033        _throttleUserRequestTime = System.currentTimeMillis();
034        return (_throttleUserRequestTime - oldTime) > THROTTLE_USER_REQUEST_TIME;
035    }
036
037    protected Permission getPermission() {
038        return PermissionsProgrammer.PERMISSION_PROGRAMMING_TRACK;
039    }
040
041    private boolean hasPermission() {
042        // Does the user has permission?
043        boolean hasPerm = InstanceManager.getDefault(PermissionManager.class)
044                .hasAtLeastPermission(getPermission(),
045                        BooleanPermission.BooleanValue.TRUE);
046
047        if (!hasPerm && throttleUserRequest()) {
048            // Notify the user about lack of permission
049            InstanceManager.getDefault(PermissionManager.class)
050                    .ensureAtLeastPermission(getPermission(),
051                            BooleanPermission.BooleanValue.TRUE);
052
053            // Reset the time for throttle user request
054            throttleUserRequest();
055        }
056        return hasPerm;
057    }
058
059    /** {@inheritDoc} */
060    @Override
061    public void writeCV(String CV, int val, ProgListener p) throws ProgrammerException {
062        if (hasPermission()) {
063            _programmer.writeCV(CV, val, p);
064        } else {
065            notifyProgListenerEnd(p, 0, ProgListener.UnknownError);
066        }
067    }
068
069    /** {@inheritDoc} */
070    @Override
071    public void readCV(String CV, ProgListener p) throws ProgrammerException {
072        if (hasPermission()) {
073            _programmer.readCV(CV, p);
074        } else {
075            notifyProgListenerEnd(p, 0, ProgListener.UnknownError);
076        }
077    }
078
079    /** {@inheritDoc} */
080    @Override
081    public void confirmCV(String CV, int val, ProgListener p) throws ProgrammerException {
082        if (hasPermission()) {
083            _programmer.confirmCV(CV, val, p);
084        } else {
085            notifyProgListenerEnd(p, 0, ProgListener.UnknownError);
086        }
087    }
088
089    /** {@inheritDoc} */
090    @Override
091    public List<ProgrammingMode> getSupportedModes() {
092        return _programmer.getSupportedModes();
093    }
094
095    /** {@inheritDoc} */
096    @Override
097    public void setMode(ProgrammingMode p) {
098        _programmer.setMode(p);
099    }
100
101    /** {@inheritDoc} */
102    @Override
103    public ProgrammingMode getMode() {
104        return _programmer.getMode();
105    }
106
107    /** {@inheritDoc} */
108    @Override
109    public boolean getCanRead() {
110        return _programmer.getCanRead();
111    }
112
113    /** {@inheritDoc} */
114    @Override
115    public boolean getCanRead(String addr) {
116        return _programmer.getCanRead(addr);
117    }
118
119    /** {@inheritDoc} */
120    @Override
121    public boolean getCanWrite() {
122        return _programmer.getCanWrite();
123    }
124
125    /** {@inheritDoc} */
126    @Override
127    public boolean getCanWrite(String addr) {
128        return _programmer.getCanWrite(addr);
129    }
130
131    /** {@inheritDoc} */
132    @Override
133    public WriteConfirmMode getWriteConfirmMode(String addr) {
134        return _programmer.getWriteConfirmMode(addr);
135    }
136
137    /** {@inheritDoc} */
138    @Override
139    public void addPropertyChangeListener(PropertyChangeListener p) {
140        _programmer.addPropertyChangeListener(p);
141    }
142
143    /** {@inheritDoc} */
144    @Override
145    public void removePropertyChangeListener(PropertyChangeListener p) {
146        _programmer.removePropertyChangeListener(p);
147    }
148
149    /** {@inheritDoc} */
150    @Override
151    public String decodeErrorCode(int i) {
152        return _programmer.decodeErrorCode(i);
153    }
154
155    /** {@inheritDoc} */
156    @Override
157    public Configurator getConfigurator() {
158        return _programmer.getConfigurator();
159    }
160}