001package jmri.jmrit.withrottle; 002 003import java.beans.PropertyChangeEvent; 004import java.beans.PropertyChangeListener; 005import java.util.ArrayList; 006import jmri.InstanceManager; 007import jmri.Turnout; 008import jmri.TurnoutManager; 009import org.apache.commons.lang3.math.NumberUtils; 010import org.slf4j.Logger; 011import org.slf4j.LoggerFactory; 012 013/** 014 * 015 * 016 * @author Brett Hoffman Copyright (C) 2010 017 */ 018public class TurnoutController extends AbstractController implements PropertyChangeListener { 019 020 private TurnoutManager manager = null; 021 private final boolean isTurnoutCreationAllowed = InstanceManager.getDefault(WiThrottlePreferences.class).isAllowTurnoutCreation(); 022 023 024 public TurnoutController() { 025 manager = InstanceManager.getNullableDefault(jmri.TurnoutManager.class); 026 if (manager == null) { 027 log.info("No turnout manager instance."); 028 isValid = false; 029 } else { 030 031 isValid = true; 032 } 033 } 034 035 @Override 036 boolean verifyCreation() { 037 038 return isValid; 039 } 040 041 @Override 042 public void filterList() { 043 ArrayList<String> tempList = new ArrayList<>(0); 044 for (String sysName : sysNameList) { 045 Turnout t = manager.getBySystemName(sysName); 046 if (t != null) { 047 Object o = t.getProperty("WifiControllable"); 048 if (o == null || Boolean.valueOf(o.toString())) { 049 // Only skip if 'false' 050 tempList.add(sysName); 051 } 052 } 053 } 054 sysNameList = tempList; 055 } 056 057 /** 058 * parse and process a turnout command message 059 * <p> 060 * Format: PTA[command][turnoutname] 061 * where command is 'C'losed, 'T'hrown, '2'oggle and 062 * turnoutname is a complete system name or a turnout number only 063 * if number only, system prefix and letter will be added 064 * Checks for existing turnout and verifies it is allowed, or 065 * if Create Turnout preference enabled, will attempt to create turnout 066 * Then sends command to alter state of turnout 067 * Can return HM error messages to client 068 * @param message Command string to be parsed 069 * @param deviceServer client to send responses (error messages) back to 070 */ 071 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( value="SLF4J_FORMAT_SHOULD_BE_CONST", 072 justification="I18N of warn Message also sent to deviceServer") 073 @Override 074 void handleMessage(String message, DeviceServer deviceServer) { 075 if (message.charAt(0) == 'A') { 076 String tName = message.substring(2); 077 //first look for existing turnout with name passed in 078 Turnout t = manager.getTurnout(tName); 079 //if not found that way AND input is all numeric, prepend system prefix + type and try again 080 if (t == null && NumberUtils.isDigits(tName)) { 081 tName = manager.getSystemPrefix() + manager.typeLetter() + tName; 082 t = manager.getTurnout(tName); 083 } 084 //this turnout IS known to JMRI 085 if (t != null) { 086 //send error if this turnout is not allowed 087 Object o = t.getProperty("WifiControllable"); 088 if (o != null && Boolean.valueOf(o.toString())==false) { 089 String msg = Bundle.getMessage("ErrorTurnoutNotAllowed", t.getSystemName()); 090 log.warn(msg); 091 deviceServer.sendAlertMessage(msg); 092 return; 093 } 094 //turnout is NOT known to JMRI, attempt to create it (if allowed) 095 } else { 096 //check if turnout creation is allowed 097 if (!isTurnoutCreationAllowed) { 098 String msg = Bundle.getMessage("ErrorTurnoutNotDefined", message.substring(2)); 099 log.warn(msg); 100 deviceServer.sendAlertMessage(msg); 101 return; 102 } else { 103 try { 104 t = manager.provideTurnout(message.substring(2)); 105 } catch (IllegalArgumentException e) { 106 String msg = Bundle.getMessage("ErrorCreatingTurnout", e.getLocalizedMessage()); 107 log.warn(msg); 108 deviceServer.sendAlertMessage(msg); 109 return; 110 } 111 String msg = Bundle.getMessage("InfoCreatedTurnout", t.getSystemName()); 112 log.debug(msg); 113 deviceServer.sendInfoMessage(msg); 114 } 115 } 116 117 switch (message.charAt(1)) { 118 case '2': 119 if (t.getCommandedState() == Turnout.CLOSED) { 120 t.setCommandedState(Turnout.THROWN); 121 } else { 122 t.setCommandedState(Turnout.CLOSED); 123 } 124 break; 125 case 'C': 126 t.setCommandedState(Turnout.CLOSED); 127 break; 128 case 'T': 129 t.setCommandedState(Turnout.THROWN); 130 break; 131 default: 132 log.warn("Message \"{}\" unknown.", message); 133 break; 134 } 135 } 136 } 137 138 139 140 /** 141 * Send Info on turnouts to devices, not specific to any one turnout. 142 * <p> 143 * Format: PTT]\[turnoutText}|{turnoutKey]\[stateText}|{stateKey]\[stateText}|{stateKey... 144 */ 145 public void sendTitles() { 146 if (listeners == null) { 147 return; 148 } 149 150 StringBuilder labels = new StringBuilder("PTT"); // Panel Turnout Titles 151 152 labels.append("]\\[").append(Bundle.getMessage("MenuItemTurnoutTable")).append("}|{Turnout"); 153 labels.append("]\\[").append(manager.getClosedText()).append("}|{2"); 154 labels.append("]\\[").append(manager.getThrownText()).append("}|{4"); 155 labels.append("]\\[").append(Bundle.getMessage("StateUnknown")).append("}|{1"); 156 labels.append("]\\[").append(Bundle.getMessage("StateInconsistent")).append("}|{8"); 157 158 String message = labels.toString(); 159 160 for (ControllerInterface listener : listeners) { 161 listener.sendPacketToDevice(message); 162 } 163 164 } 165 166 /** 167 * Send list of turnouts Format: 168 * PTL]\[SysName}|{UsrName}|{CurrentState]\[SysName}|{UsrName}|{CurrentState 169 * <p> 170 * States: 1 - UNKNOWN, 2 - CLOSED, 4 - THROWN 171 */ 172 public void sendList() { 173 if (listeners == null) { 174 return; 175 } 176 if (canBuildList) { 177 buildList(manager); 178 } 179 180 if (sysNameList.isEmpty()) { 181 return; 182 } 183 184 StringBuilder list = new StringBuilder("PTL"); // Panel Turnout List 185 186 for (String sysName : sysNameList) { 187 Turnout t = manager.getBySystemName(sysName); 188 if (t != null) { 189 list.append("]\\[").append(sysName); 190 list.append("}|{"); 191 if (t.getUserName() != null) { 192 list.append(t.getUserName()); 193 } 194 list.append("}|{").append(t.getKnownState()); 195 if (canBuildList) { 196 t.addPropertyChangeListener(this); 197 } 198 } 199 } 200 String message = list.toString(); 201 202 for (ControllerInterface listener : listeners) { 203 listener.sendPacketToDevice(message); 204 } 205 } 206 207 /** 208 * 209 */ 210 @Override 211 public void propertyChange(PropertyChangeEvent evt) { 212 if (evt.getPropertyName().equals("KnownState")) { 213 Turnout t = (Turnout) evt.getSource(); 214 sendTurnoutState(t); 215 } 216 } 217 218 public void sendTurnoutState(Turnout t) { 219 String message; 220 221 message = "PTA" + t.getKnownState() + t.getSystemName(); 222 223 for (ControllerInterface listener : listeners) { 224 listener.sendPacketToDevice(message); 225 } 226 } 227 228 @Override 229 public void register() { 230 for (String sysName : sysNameList) { 231 Turnout t = manager.getBySystemName(sysName); 232 if (t != null) { 233 t.addPropertyChangeListener(this); 234 if (log.isDebugEnabled()) { 235 log.debug("Add listener to Turnout: {}", t.getSystemName()); 236 } 237 } 238 239 } 240 } 241 242 @Override 243 public void deregister() { 244 if (sysNameList.isEmpty()) { 245 return; 246 } 247 248 for (String sysName : sysNameList) { 249 Turnout t = manager.getBySystemName(sysName); 250 251 if (t != null) { 252 t.removePropertyChangeListener(this); 253 if (log.isDebugEnabled()) { 254 log.debug("Remove listener from Turnout: {}", t.getSystemName()); 255 } 256 } 257 258 } 259 } 260 261 private final static Logger log = LoggerFactory.getLogger(TurnoutController.class); 262}