001package jmri.jmrit.logixng.actions; 002 003import java.util.Locale; 004import java.util.Map; 005 006import jmri.*; 007import jmri.jmrit.logixng.*; 008import jmri.jmrit.logixng.util.LogixNG_SelectEnum; 009import jmri.jmrit.logixng.util.LogixNG_SelectInteger; 010 011/** 012 * Sets a function on a throttle 013 * 014 * @author Daniel Bergqvist Copyright 2023 015 */ 016public final class ActionThrottleFunction extends AbstractDigitalAction { 017 018 private SystemConnectionMemo _memo; 019 private ThrottleManager _throttleManager; 020 private ThrottleManager _oldThrottleManager; 021 022 // The throttle if we have one or if a request is sent, null otherwise 023 private DccThrottle _throttle; 024 private ThrottleListener _throttleListener; 025 026 private final LogixNG_SelectInteger _selectAddress = new LogixNG_SelectInteger(this); 027 private final LogixNG_SelectInteger _selectFunction = new LogixNG_SelectInteger(this); 028 private final LogixNG_SelectEnum<FunctionState> _selectOnOff = 029 new LogixNG_SelectEnum<>(this, FunctionState.values(), FunctionState.On); 030 031 032 public ActionThrottleFunction(String sys, String user) { 033 super(sys, user); 034 035 // Set the _throttleManager variable 036 setMemo(null); 037 } 038 039 @Override 040 public Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) throws JmriException { 041 DigitalActionManager manager = InstanceManager.getDefault(DigitalActionManager.class); 042 String sysName = systemNames.get(getSystemName()); 043 String userName = userNames.get(getSystemName()); 044 if (sysName == null) sysName = manager.getAutoSystemName(); 045 ActionThrottleFunction copy = new ActionThrottleFunction(sysName, userName); 046 copy.setComment(getComment()); 047 copy.setMemo(_memo); 048 _selectAddress.copy(copy._selectAddress); 049 _selectFunction.copy(copy._selectFunction); 050 _selectOnOff.copy(copy._selectOnOff); 051 return manager.registerAction(copy).deepCopyChildren(this, systemNames, userNames); 052 } 053 054 public LogixNG_SelectInteger getSelectAddress() { 055 return _selectAddress; 056 } 057 058 public LogixNG_SelectInteger getSelectFunction() { 059 return _selectFunction; 060 } 061 062 public LogixNG_SelectEnum<FunctionState> getSelectOnOff() { 063 return _selectOnOff; 064 } 065 066 public void setMemo(SystemConnectionMemo memo) { 067 assertListenersAreNotRegistered(log, "setMemo"); 068 _memo = memo; 069 if (_memo != null) { 070 _throttleManager = _memo.get(jmri.ThrottleManager.class); 071 if (_throttleManager == null) { 072 throw new IllegalArgumentException("Memo "+memo.getUserName()+" doesn't have a ThrottleManager"); 073 } 074 } else { 075 _throttleManager = InstanceManager.getDefault(ThrottleManager.class); 076 } 077 } 078 079 public SystemConnectionMemo getMemo() { 080 return _memo; 081 } 082 083 /** {@inheritDoc} */ 084 @Override 085 public LogixNG_Category getCategory() { 086 return LogixNG_Category.ITEM; 087 } 088 089 /** {@inheritDoc} */ 090 @Override 091 public void execute() throws JmriException { 092 093 ConditionalNG conditionalNG = this.getConditionalNG(); 094 095 int currentLocoAddress = -1; 096 int newLocoAddress = -1; 097 098 if (_throttle != null) { 099 currentLocoAddress = _throttle.getLocoAddress().getNumber(); 100 } 101 102 newLocoAddress = _selectAddress.evaluateValue(conditionalNG); 103 104 if (_throttleManager != _oldThrottleManager) { 105 currentLocoAddress = -1; // Force request of new throttle 106 _oldThrottleManager = _throttleManager; 107 } 108 109 if (newLocoAddress != currentLocoAddress) { 110 111 if (_throttle != null) { 112 // Release the loco 113 _throttleManager.releaseThrottle(_throttle, _throttleListener); 114 _throttle = null; 115 } 116 117 if (newLocoAddress != -1) { 118 119 _throttleListener = new ThrottleListener() { 120 @Override 121 public void notifyThrottleFound(DccThrottle t) { 122 _throttle = t; 123 executeConditionalNG(); 124 } 125 126 @Override 127 public void notifyFailedThrottleRequest(LocoAddress address, String reason) { 128 log.warn("loco {} cannot be aquired", address.getNumber()); 129 } 130 131 @Override 132 public void notifyDecisionRequired(LocoAddress address, ThrottleListener.DecisionType question) { 133 log.warn("Loco {} cannot be aquired. Decision required.", address.getNumber()); 134 } 135 }; 136 137 boolean result = _throttleManager.requestThrottle(newLocoAddress, _throttleListener); 138 139 if (!result) { 140 log.warn("loco {} cannot be aquired", newLocoAddress); 141 } 142 } 143 144 } 145 146 // We have a throttle if _throttle is not null 147 if (_throttle != null) { 148 149 int function = _selectFunction.evaluateValue(conditionalNG); 150 boolean isFunctionOn = _selectOnOff.evaluateEnum(conditionalNG)._value; 151 152 DccThrottle throttle = _throttle; 153 int func = function; 154 boolean funcState = isFunctionOn; 155 jmri.util.ThreadingUtil.runOnLayoutWithJmriException(() -> { 156 throttle.setFunction(func, funcState); 157 }); 158 } 159 } 160 161 private void executeConditionalNG() { 162 if (_listenersAreRegistered) { 163 ConditionalNG c = getConditionalNG(); 164 if (c != null) { 165 c.execute(); 166 } 167 } 168 } 169 170 @Override 171 public String getShortDescription(Locale locale) { 172 return Bundle.getMessage(locale, "ActionThrottleFunction_Short"); 173 } 174 175 @Override 176 public String getLongDescription(Locale locale) { 177 if (_memo != null) { 178 return Bundle.getMessage(locale, "ActionThrottleFunction_LongConnection", 179 _selectAddress.getDescription(locale), 180 _selectFunction.getDescription(locale), 181 _selectOnOff.getDescription(locale), 182 _memo.getUserName()); 183 } else { 184 return Bundle.getMessage(locale, "ActionThrottleFunction_Long", 185 _selectAddress.getDescription(locale), 186 _selectFunction.getDescription(locale), 187 _selectOnOff.getDescription(locale)); 188 } 189 } 190 191 /** {@inheritDoc} */ 192 @Override 193 public void setup() { 194 // Do nothing 195 } 196 197 /** {@inheritDoc} */ 198 @Override 199 public void disposeMe() { 200 if (_throttle != null) { 201 _throttleManager.releaseThrottle(_throttle, _throttleListener); 202 } 203 } 204 205 public enum FunctionState { 206 Off(false, Bundle.getMessage("StateOff")), 207 On(true, Bundle.getMessage("StateOn")); 208 209 private final boolean _value; 210 private final String _text; 211 212 private FunctionState(boolean value, String text) { 213 this._value = value; 214 this._text = text; 215 } 216 217 public boolean getValue() { 218 return _value; 219 } 220 221 @Override 222 public String toString() { 223 return _text; 224 } 225 226 } 227 228 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ActionThrottleFunction.class); 229 230}