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.SignalMast;
012import jmri.server.json.JsonException;
013import org.slf4j.Logger;
014import org.slf4j.LoggerFactory;
015
016/**
017 * Abstract interface between a JMRI signal mast and a network connection
018 *
019 * @author Paul Bender Copyright (C) 2010
020 * 
021 */
022abstract public class AbstractSignalMastServer {
023
024    private final HashMap<String, SignalMastListener> signalMasts;
025    static private final Logger log = LoggerFactory.getLogger(AbstractSignalMastServer.class);
026
027    public AbstractSignalMastServer(){
028        signalMasts = new HashMap<>();
029    }
030
031    /*
032     * Protocol Specific Abstract Functions
033     */
034    abstract public void sendStatus(String signalMast, String Status) throws IOException;
035
036    abstract public void sendErrorStatus(String signalMast) throws IOException;
037
038    abstract public void parseStatus(String statusString) throws JmriException, IOException, JsonException;
039
040    synchronized protected void addSignalMastToList(String signalMastName) {
041        if (!signalMasts.containsKey(signalMastName)) {
042            SignalMast sm = InstanceManager.getDefault(jmri.SignalMastManager.class).getSignalMast(signalMastName);
043            if(sm!=null) {
044               SignalMastListener sml =  new SignalMastListener(signalMastName);
045               sm.addPropertyChangeListener(sml);
046               signalMasts.put(signalMastName, sml);
047               log.debug("Added listener to signalMast {}", signalMastName);
048            }
049        }
050    }
051
052    synchronized protected void removeSignalMastFromList(String signalMastName) {
053        if (signalMasts.containsKey(signalMastName)) {
054            SignalMast sm = InstanceManager.getDefault(jmri.SignalMastManager.class).getSignalMast(signalMastName);
055            if(sm!=null) {
056               sm.removePropertyChangeListener(signalMasts.get(signalMastName));
057               signalMasts.remove(signalMastName);
058            }
059        }
060    }
061
062    protected void setSignalMastAspect(String signalMastName, String signalMastState) {
063        SignalMast signalMast;
064        try {
065            addSignalMastToList(signalMastName);
066            signalMast = InstanceManager.getDefault(jmri.SignalMastManager.class).getSignalMast(signalMastName);
067            if (signalMast == null) {
068                log.error("SignalMast {} is not available.", signalMastName);
069            } else {
070                String aspect = signalMast.getAspect();
071                if ( aspect == null || !aspect.equals(signalMastState) || signalMast.getHeld()) {
072                    if (signalMastState.equals("Held")) {
073                        signalMast.setHeld(true);
074                    } else {
075                        if (signalMast.getHeld()) signalMast.setHeld(false);
076                        signalMast.setAspect(signalMastState);
077                    }
078                } else {
079                    try {
080                        sendStatus(signalMastName, signalMastState);
081                    } catch (IOException ex) {
082                        log.error("Error sending aspect ", ex);
083                    }
084                }
085            }
086        } catch (Exception ex) {
087            log.error("Exception setting signalMast {} aspect:", signalMastName, ex);
088        }
089    }
090
091    public void dispose() {
092        for (Map.Entry<String, SignalMastListener> signalMast : this.signalMasts.entrySet()) {
093            SignalMast sm = InstanceManager.getDefault(jmri.SignalMastManager.class).getSignalMast(signalMast.getKey());
094            if(sm != null) {
095               sm.removePropertyChangeListener(signalMast.getValue());
096            }
097        }
098        this.signalMasts.clear();
099    }
100
101    class SignalMastListener implements PropertyChangeListener {
102
103        String name = null;
104        SignalMast signalMast = null;
105
106        SignalMastListener(String signalMastName) {
107            name = signalMastName;
108            signalMast = InstanceManager.getDefault(jmri.SignalMastManager.class).getSignalMast(signalMastName);
109        }
110
111        // update state as state of signalMast changes
112        @Override
113        public void propertyChange(PropertyChangeEvent e) {
114            if (e.getPropertyName().equals("Aspect") || e.getPropertyName().equals("Held") || e.getPropertyName().equals("Lit")) {
115                SignalMast sm = (SignalMast) e.getSource();
116                String state = sm.getAspect();
117                if ((sm.getHeld()) && (sm.getAppearanceMap().getSpecificAppearance(jmri.SignalAppearanceMap.HELD) != null)) {
118                    state = "Held";
119                } else if ((!sm.getLit()) && (sm.getAppearanceMap().getSpecificAppearance(jmri.SignalAppearanceMap.DARK) != null)) {
120                    state = "Dark";
121                }
122                try {
123                    sendStatus(name, state);
124                } catch (IOException ie) {
125                    // if we get an error, de-register
126                    if (log.isDebugEnabled()) {
127                        log.debug("Unable to send status, removing listener from signalMast {}", name);
128                    }
129                    signalMast.removePropertyChangeListener(this);
130                    removeSignalMastFromList(name);
131                }
132            }
133        }
134    }
135}