001package jmri.jmris.srcp;
002
003import java.beans.PropertyChangeEvent;
004import java.io.DataInputStream;
005import java.io.IOException;
006import java.io.OutputStream;
007
008import jmri.InstanceManager;
009import jmri.Turnout;
010import jmri.jmris.AbstractTurnoutServer;
011import jmri.SystemConnectionMemo;
012import org.slf4j.Logger;
013import org.slf4j.LoggerFactory;
014
015/**
016 * SRCP Server interface between the JMRI Turnout manager and a network
017 * connection
018 *
019 * @author Paul Bender Copyright (C) 2010-2013
020 */
021public class JmriSRCPTurnoutServer extends AbstractTurnoutServer {
022
023    private OutputStream output;
024
025    public JmriSRCPTurnoutServer(DataInputStream inStream, OutputStream outStream) {
026        output = outStream;
027    }
028
029    /*
030     * Protocol Specific Abstract Functions
031     */
032    @Override
033    public void sendStatus(String turnoutName, int Status) throws IOException {
034        output.write("499 ERROR unspecified error\n\r".getBytes());
035    }
036
037    public void sendStatus(int bus, int address) throws IOException {
038        log.debug("send Status called with bus {} and address {}", bus, address);
039        java.util.List<SystemConnectionMemo> list = InstanceManager.getList(SystemConnectionMemo.class);
040        SystemConnectionMemo memo = null;
041        try {
042            memo = list.get(bus - 1);
043        } catch (java.lang.IndexOutOfBoundsException obe) {
044            output.write("412 ERROR wrong value\n\r".getBytes());
045            return;
046        }
047        String turnoutName = memo.getSystemPrefix()
048                + "T" + address;
049        try {
050            // busy loop, wait for turnout to settle before continuing.
051            while (InstanceManager.turnoutManagerInstance().provideTurnout(turnoutName).getKnownState() != InstanceManager.turnoutManagerInstance().provideTurnout(turnoutName).getCommandedState()) {
052            }
053            int Status = InstanceManager.turnoutManagerInstance().provideTurnout(turnoutName).getKnownState();
054            if (Status == Turnout.THROWN) {
055                output.write(("100 INFO " + bus + " GA " + address + " 1 0\n\r").getBytes());
056            } else if (Status == Turnout.CLOSED) {
057                output.write(("100 INFO " + bus + " GA " + address + " 0 0\n\r").getBytes());
058            } else {
059                //  unknown state
060                output.write("411 ERROR unknown value\n\r".getBytes());
061            }
062        } catch (IllegalArgumentException ex) {
063            log.warn("Failed to provide Turnout \"{}\" in sendStatus", turnoutName);
064        }
065    }
066
067    @Override
068    public void sendErrorStatus(String turnoutName) throws IOException {
069        output.write("499 ERROR unspecified error\n\r".getBytes());
070    }
071
072    @Override
073    public void parseStatus(String statusString) throws jmri.JmriException, java.io.IOException {
074        output.write("499 ERROR unspecified error\n\r".getBytes());
075    }
076
077    /*
078     * Initialize an SRCP server turnout. Constructs the system name 
079     * string from the provided parameters.
080     */
081    public void initTurnout(int bus, int address, String protocol) throws jmri.JmriException, java.io.IOException {
082
083        log.debug("init Turnout called with bus {} address {} and protocol {}", bus, address, protocol);
084        java.util.List<SystemConnectionMemo> list = InstanceManager.getList(SystemConnectionMemo.class);
085        SystemConnectionMemo memo;
086        try {
087            memo = list.get(bus - 1);
088        } catch (java.lang.IndexOutOfBoundsException obe) {
089            output.write("412 ERROR wrong value\n\r".getBytes());
090            return;
091        }
092        String turnoutName = memo.getSystemPrefix()
093                + "T" + address;
094        // create turnout if it does not exist.
095        this.initTurnout(turnoutName);
096        output.write(("101 INFO " + bus + " GA " + address + " " + protocol + "\n\r").getBytes());
097    }
098
099    /*
100     * for SRCP, we're doing the parsing elsewhere, so we just need to build
101     * the correct string from the provided compoents.
102     */
103    public void parseStatus(int bus, int address, int value) throws jmri.JmriException, java.io.IOException {
104
105        log.debug("parse Status called with bus {} address {} and value {}", bus, address, value);
106        java.util.List<SystemConnectionMemo> list = InstanceManager.getList(SystemConnectionMemo.class);
107        SystemConnectionMemo memo;
108        try {
109            memo = list.get(bus - 1);
110        } catch (java.lang.IndexOutOfBoundsException obe) {
111            output.write("412 ERROR wrong value\n\r".getBytes());
112            return;
113        }
114        String turnoutName = memo.getSystemPrefix()
115                + "T" + address;
116        if (value == 1) {
117            log.debug("Setting Turnout THROWN");
118            throwTurnout(turnoutName);
119        } else if (value == 0) {
120            log.debug("Setting Turnout CLOSED");
121            closeTurnout(turnoutName);
122        }
123        sendStatus(bus, address);
124    }
125
126    @Override
127    protected TurnoutListener getListener(String turnoutName) {
128        return new TurnoutListener(turnoutName);
129    }
130
131    class TurnoutListener extends AbstractTurnoutServer.TurnoutListener {
132
133        TurnoutListener(String turnoutName) {
134            super(turnoutName);
135        }
136
137        // update state as state of turnout changes
138        @Override
139        public void propertyChange(PropertyChangeEvent e) {
140            // If the Commanded State changes, show transition state as "<inconsistent>"
141            if (e.getPropertyName().equals("KnownState")) {
142                try {
143                    String Name = ((jmri.Turnout) e.getSource()).getSystemName();
144                    java.util.List<SystemConnectionMemo> List = InstanceManager.getList(SystemConnectionMemo.class);
145                    int i = 0;
146                    int address;
147                    for (Object memo : List) {
148                        String prefix = memo.getClass().getName();
149                        if (Name.startsWith(prefix)) {
150                            address = Integer.parseInt(Name.substring(prefix.length()));
151                            sendStatus(i, address);
152                            break;
153                        }
154                        i++;
155                    }
156                } catch (java.io.IOException ie) {
157                    log.error("Error Sending Status");
158                }
159            }
160        }
161    }
162    private final static Logger log = LoggerFactory.getLogger(JmriSRCPTurnoutServer.class);
163}