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 synchronized void readCV(String CVname, ProgListener p, int startVal) throws jmri.ProgrammerException {
082        if (hasPermission()) {
083            _programmer.readCV(CVname, p, startVal);
084        } else {
085            notifyProgListenerEnd(p, 0, ProgListener.UnknownError);
086        }
087    }
088    
089    /** {@inheritDoc} */
090    @Override
091    public void confirmCV(String CV, int val, ProgListener p) throws ProgrammerException {
092        if (hasPermission()) {
093            _programmer.confirmCV(CV, val, p);
094        } else {
095            notifyProgListenerEnd(p, 0, ProgListener.UnknownError);
096        }
097    }
098
099    /** {@inheritDoc} */
100    @Override
101    public List<ProgrammingMode> getSupportedModes() {
102        return _programmer.getSupportedModes();
103    }
104
105    /** {@inheritDoc} */
106    @Override
107    public void setMode(ProgrammingMode p) {
108        _programmer.setMode(p);
109    }
110
111    /** {@inheritDoc} */
112    @Override
113    public ProgrammingMode getMode() {
114        return _programmer.getMode();
115    }
116
117    /** {@inheritDoc} */
118    @Override
119    public boolean getCanRead() {
120        return _programmer.getCanRead();
121    }
122
123    /** {@inheritDoc} */
124    @Override
125    public boolean getCanRead(String addr) {
126        return _programmer.getCanRead(addr);
127    }
128
129    /** {@inheritDoc} */
130    @Override
131    public boolean getCanWrite() {
132        return _programmer.getCanWrite();
133    }
134
135    /** {@inheritDoc} */
136    @Override
137    public boolean getCanWrite(String addr) {
138        return _programmer.getCanWrite(addr);
139    }
140
141    /** {@inheritDoc} */
142    @Override
143    public WriteConfirmMode getWriteConfirmMode(String addr) {
144        return _programmer.getWriteConfirmMode(addr);
145    }
146
147    /** {@inheritDoc} */
148    @Override
149    public void addPropertyChangeListener(PropertyChangeListener p) {
150        _programmer.addPropertyChangeListener(p);
151    }
152
153    /** {@inheritDoc} */
154    @Override
155    public void removePropertyChangeListener(PropertyChangeListener p) {
156        _programmer.removePropertyChangeListener(p);
157    }
158
159    /** {@inheritDoc} */
160    @Override
161    public String decodeErrorCode(int i) {
162        return _programmer.decodeErrorCode(i);
163    }
164
165    /** {@inheritDoc} */
166    @Override
167    public Configurator getConfigurator() {
168        return _programmer.getConfigurator();
169    }
170}