001package jmri.jmrit.logixng; 002 003import java.util.Map; 004import java.util.List; 005import javax.annotation.CheckForNull; 006 007/** 008 * A LogixNG female expression socket. 009 * A Expression or a Action that has children must not use 010 * these directly but instead use a FemaleSocket. 011 * 012 * @author Daniel Bergqvist Copyright 2018 013 */ 014public interface FemaleSocket extends Base { 015 016 /** 017 * Connect the male socket to this female socket. 018 * @param socket the socket to connect 019 * @throws SocketAlreadyConnectedException if the socket is already connected 020 */ 021 void connect(MaleSocket socket) throws SocketAlreadyConnectedException; 022 023 /** 024 * Disconnect the current connected male socket from this female socket. 025 */ 026 void disconnect(); 027 028 /** 029 * Can a connected socket be disconnected? 030 * @return true if the socket can be disconnected, false otherwise 031 */ 032 default boolean canDisconnect() { 033 return true; 034 } 035 036 /** 037 * Get the connected socket. 038 * @return the male socket or null if not connected 039 */ 040 MaleSocket getConnectedSocket(); 041 042 /** 043 * Is a male socket connected to this female socket? 044 * @return true if connected 045 */ 046 boolean isConnected(); 047 048 /** 049 * Is a particular male socket compatible with this female socket? 050 * @param socket the male socket 051 * @return true if the male socket can be connected to this female socket 052 */ 053 boolean isCompatible(MaleSocket socket); 054 055 /** 056 * Validates a name for a FemaleSocket. 057 * <P> 058 * The name must have at least one character and only alphanumeric 059 * characters. The first character must not be a digit. 060 * 061 * @param name the name 062 * @return true if the name is valid, false otherwise 063 */ 064 default boolean validateName(String name) { 065 return validateName(name, false); 066 } 067 068 /** 069 * Validates a name for a FemaleSocket. 070 * <P> 071 * The name must have at least one character and only alphanumeric 072 * characters. The first character must not be a digit. 073 * 074 * @param name the name 075 * @param ignoreDuplicateErrors true if duplicate names should be ignored, 076 * false otherwise 077 * @return true if the name is valid, false otherwise 078 */ 079 boolean validateName(String name, boolean ignoreDuplicateErrors); 080 081 /** 082 * Set the name of this socket. 083 * <P> 084 * The name must have at least one character and only alphanumeric 085 * characters. The first character must not be a digit. 086 * 087 * @param name the name 088 */ 089 default void setName(String name) { 090 setName(name, false); 091 } 092 093 /** 094 * Set the name of this socket. 095 * <P> 096 * The name must have at least one character and only alphanumeric 097 * characters. The first character must not be a digit. 098 * 099 * @param name the name 100 * @param ignoreDuplicateErrors true if duplicate names should be ignored, 101 * false otherwise 102 */ 103 void setName(String name, boolean ignoreDuplicateErrors); 104 105 /** 106 * Get the name of this socket. 107 * @return the name 108 */ 109 @CheckForNull 110 String getName(); 111 112 /** 113 * Is the operation allowed on this socket? 114 * @param oper the operation to do 115 * @return true if operation is allowed, false otherwise 116 */ 117 default boolean isSocketOperationAllowed(FemaleSocketOperation oper) { 118 Base parent = getParent(); 119 if (parent == null) return false; 120 121 for (int i=0; i < parent.getChildCount(); i++) { 122 if (parent.getChild(i) == this) { 123 return parent.isSocketOperationAllowed(i, oper); 124 } 125 } 126 throw new IllegalArgumentException("Invalid index"); 127 } 128 129 /** 130 * Do an operation on this socket 131 * @param oper the operation to do 132 */ 133 default void doSocketOperation(FemaleSocketOperation oper) { 134 Base parent = getParent(); 135 for (int i=0; i < parent.getChildCount(); i++) { 136 if (parent.getChild(i) == this) { 137 parent.doSocketOperation(i, oper); 138 return; 139 } 140 } 141 throw new IllegalArgumentException("Invalid index"); 142 } 143 144 /** 145 * Sets whenever listeners are enabled or not. 146 * ConditionalNG has always listeners enabled, but Clipboard and Module 147 * has never listeners enabled. 148 * @param enable true if listeners should be enabled, false otherwise 149 */ 150 void setEnableListeners(boolean enable); 151 152 /** 153 * Gets whenever listeners are enabled or not. 154 * ConditionalNG has always listeners enabled, but Clipboard and Module 155 * has never listeners enabled. 156 * @return true if listeners should be enabled, false otherwise 157 */ 158 boolean getEnableListeners(); 159 160 /** 161 * Am I an ancestor to this maleSocket? 162 * 163 * @param maleSocket the maleSocket that could be a child 164 * @return true if this oject is an ancestor to the maleSocket object 165 */ 166 default boolean isAncestor(MaleSocket maleSocket) { 167 Base base = maleSocket; 168 while ((base != null) && (base != this)) { 169 base = base.getParent(); 170 } 171 return base == this; 172 } 173 174 /** 175 * Get a set of classes that are compatible with this female socket. 176 * 177 * @return a set of entries with category and class 178 */ 179 Map<Category, List<Class<? extends Base>>> getConnectableClasses(); 180 181 /** {@inheritDoc} */ 182 @Override 183 default void setup() { 184 if (isConnected()) { 185 getConnectedSocket().setup(); 186 } 187 } 188 189}