001package jmri.jmrit.logixng.actions; 002 003import java.util.Locale; 004import java.util.Map; 005 006import jmri.InstanceManager; 007import jmri.JmriException; 008import jmri.jmrit.logixng.*; 009 010/** 011 * Emulates Logix. 012 * 013 * @author Daniel Bergqvist Copyright 2018 014 */ 015public class Logix extends AbstractDigitalAction 016 implements FemaleSocketListener { 017 018 private ExecuteType _executeType = ExecuteType.ExecuteOnChange; 019 private boolean _lastExpressionResult = false; 020 private String _expressionSocketSystemName; 021 private String _actionSocketSystemName; 022 private final FemaleDigitalExpressionSocket _expressionSocket; 023 private final FemaleDigitalBooleanActionSocket _actionSocket; 024 025 public Logix(String sys, String user) { 026 super(sys, user); 027 _expressionSocket = InstanceManager.getDefault(DigitalExpressionManager.class) 028 .createFemaleSocket(this, this, "E"); 029 _actionSocket = InstanceManager.getDefault(DigitalBooleanActionManager.class) 030 .createFemaleSocket(this, this, "A"); 031 } 032 033 @Override 034 public Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) throws JmriException { 035 DigitalActionManager manager = InstanceManager.getDefault(DigitalActionManager.class); 036 String sysName = systemNames.get(getSystemName()); 037 String userName = userNames.get(getSystemName()); 038 if (sysName == null) sysName = manager.getAutoSystemName(); 039 Logix copy = new Logix(sysName, userName); 040 copy.setComment(getComment()); 041 copy.setExecuteType(_executeType); 042 return manager.registerAction(copy).deepCopyChildren(this, systemNames, userNames); 043 } 044 045 /** {@inheritDoc} */ 046 @Override 047 public Category getCategory() { 048 return Category.OTHER; 049 } 050 051 /** 052 * Get the execute type. 053 * @return the type 054 */ 055 public ExecuteType getExecuteType() { 056 return _executeType; 057 } 058 059 /** 060 * Set the execute type. 061 * @param type the type 062 */ 063 public void setExecuteType(ExecuteType type) { 064 _executeType = type; 065 } 066 067 /** {@inheritDoc} */ 068 @Override 069 public void execute() throws JmriException { 070 boolean result = _expressionSocket.evaluate(); 071 072 if ((_executeType == ExecuteType.ExecuteAlways) || (result != _lastExpressionResult)) { 073 _actionSocket.execute(result); 074 } 075 _lastExpressionResult = result; 076 } 077 078 /** {@inheritDoc} */ 079 @Override 080 public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException { 081 switch (index) { 082 case 0: 083 return _expressionSocket; 084 085 case 1: 086 return _actionSocket; 087 088 default: 089 throw new IllegalArgumentException( 090 String.format("index has invalid value: %d", index)); 091 } 092 } 093 094 /** {@inheritDoc} */ 095 @Override 096 public int getChildCount() { 097 return 2; 098 } 099 100 /** {@inheritDoc} */ 101 @Override 102 public void connected(FemaleSocket socket) { 103 if (socket == _expressionSocket) { 104 _expressionSocketSystemName = socket.getConnectedSocket().getSystemName(); 105 } else if (socket == _actionSocket) { 106 _actionSocketSystemName = socket.getConnectedSocket().getSystemName(); 107 } else { 108 throw new IllegalArgumentException("unkown socket"); 109 } 110 } 111 112 /** {@inheritDoc} */ 113 @Override 114 public void disconnected(FemaleSocket socket) { 115 if (socket == _expressionSocket) { 116 _expressionSocketSystemName = null; 117 } else if (socket == _actionSocket) { 118 _actionSocketSystemName = null; 119 } else { 120 throw new IllegalArgumentException("unkown socket"); 121 } 122 } 123 124 /** {@inheritDoc} */ 125 @Override 126 public String getShortDescription(Locale locale) { 127 return Bundle.getMessage(locale, "Logix_Short"); 128 } 129 130 /** {@inheritDoc} */ 131 @Override 132 public String getLongDescription(Locale locale) { 133 return Bundle.getMessage(locale, "Logix_Long", _executeType.toString()); 134 } 135 136 public FemaleDigitalExpressionSocket getExpressionSocket() { 137 return _expressionSocket; 138 } 139 140 public String getExpressionSocketSystemName() { 141 return _expressionSocketSystemName; 142 } 143 144 public void setExpressionSocketSystemName(String systemName) { 145 _expressionSocketSystemName = systemName; 146 } 147 148 public FemaleDigitalBooleanActionSocket getActionSocket() { 149 return _actionSocket; 150 } 151 152 public String getActionSocketSystemName() { 153 return _actionSocketSystemName; 154 } 155 156 public void setActionSocketSystemName(String systemName) { 157 _actionSocketSystemName = systemName; 158 } 159 160 /** {@inheritDoc} */ 161 @Override 162 public void setup() { 163 try { 164 if ( !_expressionSocket.isConnected() 165 || !_expressionSocket.getConnectedSocket().getSystemName() 166 .equals(_expressionSocketSystemName)) { 167 168 String socketSystemName = _expressionSocketSystemName; 169 _expressionSocket.disconnect(); 170 if (socketSystemName != null) { 171 MaleSocket maleSocket = 172 InstanceManager.getDefault(DigitalExpressionManager.class) 173 .getBySystemName(socketSystemName); 174 if (maleSocket != null) { 175 _expressionSocket.connect(maleSocket); 176 maleSocket.setup(); 177 } else { 178 log.error("cannot load digital expression {}", socketSystemName); 179 } 180 } 181 } else { 182 _expressionSocket.getConnectedSocket().setup(); 183 } 184 185 if ( !_actionSocket.isConnected() 186 || !_actionSocket.getConnectedSocket().getSystemName() 187 .equals(_actionSocketSystemName)) { 188 189 String socketSystemName = _actionSocketSystemName; 190 _actionSocket.disconnect(); 191 if (socketSystemName != null) { 192 MaleSocket maleSocket = 193 InstanceManager.getDefault(DigitalBooleanActionManager.class) 194 .getBySystemName(socketSystemName); 195 _actionSocket.disconnect(); 196 if (maleSocket != null) { 197 _actionSocket.connect(maleSocket); 198 maleSocket.setup(); 199 } else { 200 log.error("cannot load digital boolean action {}", socketSystemName); 201 } 202 } 203 } else { 204 _actionSocket.getConnectedSocket().setup(); 205 } 206 } catch (SocketAlreadyConnectedException ex) { 207 // This shouldn't happen and is a runtime error if it does. 208 throw new RuntimeException("socket is already connected"); 209 } 210 } 211 212 /** {@inheritDoc} */ 213 @Override 214 public void registerListenersForThisClass() { 215 } 216 217 /** {@inheritDoc} */ 218 @Override 219 public void unregisterListenersForThisClass() { 220 } 221 222 /** {@inheritDoc} */ 223 @Override 224 public void disposeMe() { 225 } 226 227 228 /** 229 * The type of Action. If the type is changed, the action is aborted if it 230 * is currently running. 231 */ 232 public enum ExecuteType { 233 /** 234 * The "then" or "else" action is executed when the expression changes 235 * its result. If the expression has returned "false", but now returns 236 * "true", the "then" action is executed. If the expression has 237 * returned "true", but now returns "false", the "else" action is executed. 238 */ 239 ExecuteOnChange(Bundle.getMessage("Logix_ExecuteOnChange")), 240 241 /** 242 * The "then" or "else" action is always executed when this action is 243 * executed. If the expression returns "true", the "then" action is 244 * executed. If the expression returns "false", the "else" action is 245 * executed. 246 */ 247 ExecuteAlways(Bundle.getMessage("Logix_ExecuteAlways")); 248 249 private final String _text; 250 251 private ExecuteType(String text) { 252 this._text = text; 253 } 254 255 @Override 256 public String toString() { 257 return _text; 258 } 259 260 } 261 262 263 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Logix.class); 264 265}