001package jmri.jmrix.jmriclient;
002
003import jmri.Turnout;
004import jmri.implementation.AbstractTurnout;
005import org.slf4j.Logger;
006import org.slf4j.LoggerFactory;
007
008/**
009 * JMRIClient implementation of the Turnout interface.
010 *
011 * @author Bob Jacobsen Copyright (C) 2001, 2008
012 * @author Paul Bender Copyright (C) 2010
013 */
014public class JMRIClientTurnout extends AbstractTurnout implements JMRIClientListener {
015
016    // data members
017    private int _number;   // turnout number
018    private JMRIClientTrafficController tc = null;
019    private String prefix = null;
020    private String transmitName = null;
021
022    /* Static arrays to hold Lenz specific feedback mode information */
023    static String[] modeNames = null;
024    static int[] modeValues = null;
025
026    /**
027     * JMRIClient turnouts use the turnout number on the remote host.
028     * @param number turnout number
029     * @param memo system connection
030     */
031    public JMRIClientTurnout(int number, JMRIClientSystemConnectionMemo memo) {
032        super(memo.getSystemPrefix() + "T" + number);
033        _number = number;
034        tc = memo.getJMRIClientTrafficController();
035        prefix = memo.getSystemPrefix();
036        transmitName = memo.getTransmitPrefix() + "T" + number;
037        /* allow monitoring mode feedback, which is the same
038         as direct for this connection (this aids the 
039         transition from directly connected hardware to remotly
040         connected hardware.)*/
041        _validFeedbackTypes |= MONITORING;
042
043        // Default feedback mode is MONITORING
044        _activeFeedbackType = MONITORING;
045
046        setModeInformation(_validFeedbackNames, _validFeedbackModes);
047
048        // set the mode names and values based on the static values.
049        _validFeedbackNames = getModeNames();
050        _validFeedbackModes = getModeValues();
051
052        // At construction, register for messages
053        tc.addJMRIClientListener(this);
054        // Then request status.
055        requestUpdateFromLayout();
056    }
057
058    //Set the mode information for JMRIClient Turnouts.
059    synchronized static private void setModeInformation(String[] feedbackNames, int[] feedbackModes) {
060        // if it hasn't been done already, create static arrays to hold
061        // the JMRIClient specific feedback information.
062        if (modeNames == null) {
063            if (feedbackNames.length != feedbackModes.length) {
064                log.error("int and string feedback arrays different length");
065            }
066            modeNames = new String[feedbackNames.length + 1];
067            modeValues = new int[feedbackNames.length + 1];
068            for (int i = 0; i < feedbackNames.length; i++) {
069                modeNames[i] = feedbackNames[i];
070                modeValues[i] = feedbackModes[i];
071            }
072            modeNames[feedbackNames.length] = "MONITORING";
073            modeValues[feedbackNames.length] = MONITORING;
074        }
075    }
076
077    static int[] getModeValues() {
078        return modeValues;
079    }
080
081    static String[] getModeNames() {
082        return modeNames;
083    }
084
085    public int getNumber() {
086        return _number;
087    }
088
089    /**
090     * {@inheritDoc}
091     */
092    @Override
093    protected void forwardCommandChangeToLayout(int newState) {
094        // sort out states
095        if ((newState & Turnout.CLOSED) != 0) {
096            // first look for the double case, which we can't handle
097            if ((newState & Turnout.THROWN) != 0) {
098                // this is the disaster case!
099                log.error("Cannot command both CLOSED and THROWN {}", newState);
100                return;
101            } else {
102                // send a CLOSED command
103                sendMessage(!getInverted());
104            }
105        } else {
106            // send a THROWN command
107            sendMessage(getInverted());
108        }
109    }
110
111    @Override
112    public boolean canInvert() {
113        return true;
114    }
115
116    // request a status update from the layout.
117    @Override
118    public void requestUpdateFromLayout() {
119        // create the message
120        String text = "TURNOUT " + transmitName + "\n";
121        // create and send the message itself
122        tc.sendJMRIClientMessage(new JMRIClientMessage(text), this);
123        // This will handle ONESENSOR and TWOSENSOR feedback modes.
124        super.requestUpdateFromLayout();
125    }
126
127    @Override
128    protected void turnoutPushbuttonLockout(boolean _pushButtonLockout) {
129        log.debug("Send command to {} Pushbutton {}{}", (_pushButtonLockout ? "Lock" : "Unlock"), prefix, _number);
130    }
131
132    protected void sendMessage(boolean closed) {
133        // get the message text
134        String text;
135        if (closed) {
136            text = "TURNOUT " + transmitName + " CLOSED\n";
137        } else // thrown
138        {
139            text = "TURNOUT " + transmitName + " THROWN\n";
140        }
141
142        // create and send the message itself
143        tc.sendJMRIClientMessage(new JMRIClientMessage(text), this);
144    }
145
146    // to listen for status changes from JMRIClient system
147    @Override
148    public void reply(JMRIClientReply m) {
149        String message = m.toString();
150        if (!message.contains(transmitName + " ")) {
151            return; // not for us
152        }
153        if (m.toString().contains("THROWN")) {
154            newKnownState(!getInverted() ? jmri.Turnout.THROWN : jmri.Turnout.CLOSED);
155        } else if (m.toString().contains("CLOSED")) {
156            newKnownState(!getInverted() ? jmri.Turnout.CLOSED : jmri.Turnout.THROWN);
157        } else {
158            newKnownState(jmri.Turnout.UNKNOWN);
159        }
160    }
161
162    @Override
163    public void message(JMRIClientMessage m) {
164    }
165
166    private final static Logger log = LoggerFactory.getLogger(JMRIClientTurnout.class);
167
168}