001package jmri.jmrit.logixng.implementation; 002 003import java.util.ArrayList; 004import java.util.List; 005import java.util.Map; 006import java.util.HashMap; 007import java.util.Locale; 008 009import javax.annotation.CheckForNull; 010 011import jmri.*; 012import jmri.jmrit.logixng.*; 013 014/** 015 * Default implementation of the FemaleGenericExpressionSocket 016 */ 017public class DefaultFemaleGenericExpressionSocket 018 extends AbstractFemaleSocket 019 implements FemaleGenericExpressionSocket, FemaleSocketListener { 020 021 private SocketType _socketType; // The type of the socket the user has selected 022 private SocketType _currentSocketType; // The current type of the socket. 023 private FemaleSocket _currentActiveSocket; // The socket that is currently in use, if any. Null otherwise. 024 private final FemaleAnalogExpressionSocket _analogSocket = new DefaultFemaleAnalogExpressionSocket(this, this, "A"); 025 private final FemaleDigitalExpressionSocket _digitalSocket = new DefaultFemaleDigitalExpressionSocket(this, this, "D"); 026 private final FemaleStringExpressionSocket _stringSocket = new DefaultFemaleStringExpressionSocket(this, this, "S"); 027 private boolean _do_i18n; 028 029 public DefaultFemaleGenericExpressionSocket( 030 SocketType socketType, 031 Base parent, 032 FemaleSocketListener listener, 033 String name) { 034 035 super(parent, listener, name); 036 037 _socketType = socketType; 038 _currentSocketType = socketType; 039 040 switch (_socketType) { 041 case ANALOG: 042 _currentActiveSocket = _analogSocket; 043 break; 044 045 case DIGITAL: 046 _currentActiveSocket = _digitalSocket; 047 break; 048 049 case STRING: 050 _currentActiveSocket = _stringSocket; 051 break; 052 053 case GENERIC: 054 _currentActiveSocket = null; 055 break; 056 057 default: 058 throw new RuntimeException("_socketType has invalid value: "+socketType.name()); 059 } 060 } 061 062 063 /** {@inheritDoc} */ 064 @Override 065 public FemaleSocket getCurrentActiveSocket() { 066 return _currentActiveSocket; 067 } 068 069 070 /** {@inheritDoc} */ 071 @Override 072 public boolean isCompatible(MaleSocket socket) { 073 return (socket instanceof MaleAnalogExpressionSocket) 074 || (socket instanceof MaleDigitalExpressionSocket) 075 || (socket instanceof MaleStringExpressionSocket); 076 } 077 078 /** {@inheritDoc} */ 079 @Override 080 public void setSocketType(SocketType socketType) 081 throws SocketAlreadyConnectedException { 082 083 if (socketType == _socketType) { 084 return; 085 } 086 087 if ((_currentActiveSocket != null) && (_currentActiveSocket.isConnected())) { 088 throw new SocketAlreadyConnectedException("Socket is already connected"); 089 } 090 091 switch (socketType) { 092 case DIGITAL: 093 _socketType = SocketType.DIGITAL; 094 _currentSocketType = SocketType.DIGITAL; 095 _currentActiveSocket = _digitalSocket; 096 break; 097 098 case ANALOG: 099 _socketType = SocketType.ANALOG; 100 _currentSocketType = SocketType.ANALOG; 101 _currentActiveSocket = _analogSocket; 102 break; 103 104 case STRING: 105 _socketType = SocketType.STRING; 106 _currentSocketType = SocketType.STRING; 107 _currentActiveSocket = _stringSocket; 108 break; 109 110 case GENERIC: 111 _socketType = SocketType.GENERIC; 112 _currentSocketType = SocketType.GENERIC; 113 _currentActiveSocket = null; 114 break; 115 116 default: 117 throw new RuntimeException("socketType has invalid value: "+socketType.name()); 118 } 119 } 120 121 /** {@inheritDoc} */ 122 @Override 123 public SocketType getSocketType() { 124 return _socketType; 125 } 126 127 public void setDoI18N(boolean do_i18n) { 128 _do_i18n = do_i18n; 129 } 130 131 public boolean getDoI18N() { 132 return _do_i18n; 133 } 134 135 @Override 136 @CheckForNull 137 public Object evaluateGeneric() throws JmriException { 138 if (isConnected()) { 139 switch (_currentSocketType) { 140 case DIGITAL: 141 return ((MaleDigitalExpressionSocket)getConnectedSocket()) 142 .evaluate(); 143 144 case ANALOG: 145 return ((MaleAnalogExpressionSocket)getConnectedSocket()) 146 .evaluate(); 147 148 case STRING: 149 return ((MaleStringExpressionSocket)getConnectedSocket()) 150 .evaluate(); 151 152 default: 153 throw new RuntimeException("_currentSocketType has invalid value: "+_currentSocketType.name()); 154 } 155 } else { 156 return null; 157 } 158 } 159 160 /** {@inheritDoc} */ 161 @Override 162 public String getShortDescription(Locale locale) { 163 return Bundle.getMessage(locale, "DefaultFemaleGenericExpressionSocket_Short"); 164 } 165 166 /** {@inheritDoc} */ 167 @Override 168 public String getLongDescription(Locale locale) { 169 return Bundle.getMessage(locale, "DefaultFemaleGenericExpressionSocket_Long", getName()); 170 } 171 172 private void addClassesToMap( 173 Map<Category, List<Class<? extends Base>>> destinationClasses, 174 Map<Category, List<Class<? extends Base>>> sourceClasses) { 175 176 for (Category category : Category.values()) { 177 // Some categories might not have any expression. 178 if (sourceClasses.get(category) == null) continue; 179 180 for (Class<? extends Base> clazz : sourceClasses.get(category)) { 181 destinationClasses.get(category).add(clazz); 182 } 183 } 184 } 185 186 @Override 187 public Map<Category, List<Class<? extends Base>>> getConnectableClasses() { 188 Map<Category, List<Class<? extends Base>>> classes = new HashMap<>(); 189 190 for (Category category : Category.values()) { 191 classes.put(category, new ArrayList<>()); 192 } 193 194 addClassesToMap(classes, InstanceManager.getDefault(AnalogExpressionManager.class).getExpressionClasses()); 195 addClassesToMap(classes, InstanceManager.getDefault(DigitalExpressionManager.class).getExpressionClasses()); 196 addClassesToMap(classes, InstanceManager.getDefault(StringExpressionManager.class).getExpressionClasses()); 197 198 return classes; 199 } 200 201 /** {@inheritDoc} */ 202 @Override 203 public void connect(MaleSocket socket) throws SocketAlreadyConnectedException { 204 205 if (socket == null) { 206 throw new NullPointerException("socket cannot be null"); 207 } 208 209 // If _currentActiveSocket is not null, the socket is either connected 210 // or locked to a particular type. 211 if (_currentActiveSocket != null) { 212 if (_currentActiveSocket.isConnected()) { 213 throw new SocketAlreadyConnectedException("Socket is already connected"); 214 } else { 215 _currentActiveSocket.connect(socket); 216 _listener.connected(this); 217 return; 218 } 219 } 220 221 // If we are here, the socket is not connected and is not locked to a 222 // particular type. 223 224 if (_digitalSocket.isCompatible(socket)) { 225 _currentSocketType = SocketType.DIGITAL; 226 _currentActiveSocket = _digitalSocket; 227 } else if (_analogSocket.isCompatible(socket)) { 228 _currentSocketType = SocketType.ANALOG; 229 _currentActiveSocket = _analogSocket; 230 } else if (_stringSocket.isCompatible(socket)) { 231 _currentSocketType = SocketType.STRING; 232 _currentActiveSocket = _stringSocket; 233 } else { 234 throw new IllegalArgumentException("Socket is not compatible"); 235 } 236 _currentActiveSocket.connect(socket); 237 _listener.connected(this); 238 } 239 240 /** {@inheritDoc} */ 241 @Override 242 public void disconnect() { 243 if ((_currentActiveSocket != null) 244 && _currentActiveSocket.isConnected()) { 245 246 _currentActiveSocket.disconnect(); 247 _listener.disconnected(this); 248 } 249 } 250 251 /** {@inheritDoc} */ 252 @Override 253 public MaleSocket getConnectedSocket() { 254 if (_currentActiveSocket != null) { 255 return _currentActiveSocket.getConnectedSocket(); 256 } else { 257 return null; 258 } 259 } 260 261 /** {@inheritDoc} */ 262 @Override 263 public boolean isConnected() { 264 return (_currentActiveSocket != null) && _currentActiveSocket.isConnected(); 265 } 266 267 @Override 268 public void connected(FemaleSocket socket) { 269 // Do nothing 270 } 271 272 @Override 273 public void disconnected(FemaleSocket socket) { 274 if (_socketType == SocketType.GENERIC) { 275 _currentActiveSocket = null; 276 } 277 } 278 279 /** {@inheritDoc} */ 280 @Override 281 public void disposeMe() { 282 // Do nothing 283 } 284 285}