001package jmri.jmris;
002
003import java.beans.PropertyChangeEvent;
004import java.beans.PropertyChangeListener;
005import java.io.IOException;
006import java.util.HashMap;
007import java.util.Map;
008
009import jmri.InstanceManager;
010import jmri.JmriException;
011import jmri.Turnout;
012import org.slf4j.Logger;
013import org.slf4j.LoggerFactory;
014
015/**
016 * Abstract interface between the a JMRI turnout and a network connection
017 *
018 * @author Paul Bender Copyright (C) 2010-2013
019 * @author Randall Wood Copyright (C) 2013
020 */
021abstract public class AbstractTurnoutServer {
022
023    protected final HashMap<String, TurnoutListener> turnouts;
024    private final static Logger log = LoggerFactory.getLogger(AbstractTurnoutServer.class);
025
026    public AbstractTurnoutServer(){
027        turnouts = new HashMap<>();
028    }
029
030    /*
031     * Protocol Specific Abstract Functions
032     */
033    abstract public void sendStatus(String turnoutName, int Status) throws IOException;
034
035    abstract public void sendErrorStatus(String turnoutName) throws IOException;
036
037    abstract public void parseStatus(String statusString) throws JmriException, IOException;
038
039    synchronized protected void addTurnoutToList(String turnoutName) {
040        if (!turnouts.containsKey(turnoutName)) {
041            Turnout t = InstanceManager.turnoutManagerInstance().getTurnout(turnoutName);
042            if(t!=null) {
043               TurnoutListener tl = new TurnoutListener(turnoutName);
044               t.addPropertyChangeListener(tl);
045               turnouts.put(turnoutName, tl);
046            }
047        }
048    }
049
050    synchronized protected void removeTurnoutFromList(String turnoutName) {
051        if (turnouts.containsKey(turnoutName)) {
052            Turnout t = InstanceManager.turnoutManagerInstance().getTurnout(turnoutName);
053            if(t!=null) {
054               t.removePropertyChangeListener(turnouts.get(turnoutName));
055               turnouts.remove(turnoutName);
056            }
057        }
058    }
059
060    public Turnout initTurnout(String turnoutName) throws IllegalArgumentException {
061        Turnout turnout = InstanceManager.turnoutManagerInstance().provideTurnout(turnoutName);
062        this.addTurnoutToList(turnoutName);
063        return turnout;
064    }
065
066    public void closeTurnout(String turnoutName) {
067        // load address from switchAddrTextField
068        try {
069            if (!turnouts.containsKey(turnoutName)) {
070                // enforce that initTurnout must be called before moving a
071                // turnout
072                sendErrorStatus(turnoutName);
073                return;
074            }
075            Turnout turnout = InstanceManager.turnoutManagerInstance().getTurnout(turnoutName);
076            if (turnout == null) {
077                log.error("Turnout {} is not available", turnoutName);
078            } else {
079                log.debug("about to command CLOSED");
080                // and set commanded state to CLOSED
081                turnout.setCommandedState(Turnout.CLOSED);
082            }
083        } catch (IOException ex) {
084            log.error("Error closing turnout", ex);
085        }
086    }
087
088    public void throwTurnout(String turnoutName) {
089        // load address from switchAddrTextField
090        try {
091            Turnout turnout = InstanceManager.turnoutManagerInstance().getTurnout(turnoutName);
092            if (!turnouts.containsKey(turnoutName)) {
093                // enforce that initTurnout must be called before moving a
094                // turnout
095                sendErrorStatus(turnoutName);
096                return;
097            }
098
099            if (turnout == null) {
100                log.error("Turnout {} is not available", turnoutName);
101            } else {
102                if (log.isDebugEnabled()) {
103                    log.debug("about to command THROWN");
104                }
105                // and set commanded state to THROWN
106                turnout.setCommandedState(Turnout.THROWN);
107            }
108        } catch (IOException ex) {
109            log.error("Error throwing turnout", ex);
110        }
111    }
112
113    public void dispose() {
114        for (Map.Entry<String, TurnoutListener> turnout : this.turnouts.entrySet()) {
115            Turnout t = InstanceManager.turnoutManagerInstance().getTurnout(turnout.getKey());
116            if(t!=null) {
117               t.removePropertyChangeListener(turnout.getValue());
118            }
119        }
120        this.turnouts.clear();
121    }
122
123    protected TurnoutListener getListener(String turnoutName) {
124        if (!turnouts.containsKey(turnoutName)) {
125           return new TurnoutListener(turnoutName);
126        } else {
127           return turnouts.get(turnoutName);
128        }        
129    }
130
131    protected class TurnoutListener implements PropertyChangeListener {
132
133        protected TurnoutListener(String turnoutName) {
134            name = turnoutName;
135            turnout = InstanceManager.turnoutManagerInstance().getTurnout(turnoutName);
136        }
137
138        // update state as state of turnout changes
139        @Override
140        public void propertyChange(PropertyChangeEvent e) {
141            // If the Commanded State changes, show transition state as "<inconsistent>"
142            if (e.getPropertyName().equals("KnownState")) {
143                int now = ((Integer) e.getNewValue()).intValue();
144                try {
145                    sendStatus(name, now);
146                } catch (IOException ie) {
147                    log.debug("Error Sending Status");
148                    // if we get an error, de-register
149                    turnout.removePropertyChangeListener(this);
150                    removeTurnoutFromList(name);
151                }
152            }
153        }
154        String name = null;
155        Turnout turnout = null;
156    }
157}