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