001package jmri.jmris;
002
003import java.beans.PropertyChangeEvent;
004import java.beans.PropertyChangeListener;
005import java.io.IOException;
006import java.util.HashMap;
007import java.util.Map;
008import jmri.InstanceManager;
009import jmri.JmriException;
010import jmri.Sensor;
011import jmri.Route;
012
013/**
014 * Abstract interface between the a JMRI route and a network connection
015 *
016 * @author Paul Bender Copyright (C) 2010
017 * @author Randall Wood Copyright (C) 2013
018 */
019abstract public class AbstractRouteServer {
020
021    private final HashMap<String, RouteListener> routes;
022
023    public AbstractRouteServer() {
024        routes = new HashMap<>();
025    }
026
027    /*
028     * Protocol Specific Abstract Functions
029     */
030    abstract public void sendStatus(String route, int Status) throws IOException;
031
032    abstract public void sendErrorStatus(String route) throws IOException;
033
034    abstract public void parseStatus(String statusString) throws JmriException, IOException;
035
036    synchronized protected void addRouteToList(String routeName) {
037        if (!routes.containsKey(routeName)) {
038            Route r = InstanceManager.getDefault(jmri.RouteManager.class).getRoute(routeName);
039            if(r!=null) {
040               Sensor tas = r.getTurnoutsAlgdSensor();
041               if (tas != null) {  //only add listener if there is a turnout-aligned sensor defined
042                   RouteListener rl = new RouteListener(routeName);
043                   tas.addPropertyChangeListener(rl);
044                   routes.put(routeName, rl);
045               }
046            }
047        }
048    }
049
050    synchronized protected void removeRouteFromList(String routeName) {
051        if (routes.containsKey(routeName)) {
052            Route r = InstanceManager.getDefault(jmri.RouteManager.class).getRoute(routeName);
053            if(r!=null) {
054               Sensor tas = r.getTurnoutsAlgdSensor();
055               if (tas != null) {  //only remove listener if there is a turnout-aligned sensor defined
056                   tas.removePropertyChangeListener(routes.get(routeName));
057               }
058               routes.remove(routeName);
059            }
060        }
061    }
062
063    public void setRoute(String routeName) throws IOException {
064        Route route = InstanceManager.getDefault(jmri.RouteManager.class).getRoute(routeName);
065        if ( route != null ) {
066            route.setRoute();
067            addRouteToList(routeName);
068        } else {
069            sendErrorStatus(routeName);
070        }
071    }
072
073    public void dispose() {
074        for (Map.Entry<String, RouteListener> route : this.routes.entrySet()) {
075            Route r = InstanceManager.getDefault(jmri.RouteManager.class).getRoute(route.getKey());
076            if (r!=null) {
077               Sensor tas = r.getTurnoutsAlgdSensor();
078               if (tas != null) {  //only remove listener if there is a turnout-aligned sensor defined
079                   tas.removePropertyChangeListener(route.getValue());
080               }
081            }
082        }
083        this.routes.clear();
084    }
085
086    class RouteListener implements PropertyChangeListener {
087
088        String name = null;
089        Sensor sensor = null;
090
091        RouteListener(String routeName) {
092            name = routeName;
093            Route r = InstanceManager.getDefault(jmri.RouteManager.class).getRoute(name);
094            if(r!=null) {
095               sensor = r.getTurnoutsAlgdSensor();
096            }
097        }
098
099        // update state as state of route changes
100        @Override
101        public void propertyChange(PropertyChangeEvent e) {
102            // If the Commanded State changes, show transition state as "<inconsistent>"
103            if (e.getPropertyName().equals("KnownState")) {
104                try {
105                    sendStatus(name, ((Integer) e.getNewValue()));
106                } catch (IOException ie) {
107                    log.debug("Error Sending Status");
108                    // if we get an error, de-register
109                    sensor.removePropertyChangeListener(this);
110                    removeRouteFromList(name);
111                }
112            }
113        }
114    }
115
116    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AbstractRouteServer.class);
117
118}