001package jmri.jmrix.rps;
002
003import java.util.List;
004import jmri.LocoAddress;
005import jmri.DccLocoAddress;
006import jmri.DccThrottle;
007import jmri.SignalHead;
008import org.slf4j.Logger;
009import org.slf4j.LoggerFactory;
010
011/**
012 * Create a Block that can control a locomotive within a specific Block based on
013 * an RpsSensor. It sets speed based on aspect of a specific signal.
014 *
015 * @author Bob Jacobsen Copyright (C) 2007
016 */
017public class RpsBlock implements java.beans.PropertyChangeListener, jmri.ThrottleListener {
018
019    public RpsBlock(RpsSensor sensor, SignalHead signal, float slow, float fast) {
020        this.sensor = sensor;
021        this.signal = signal;
022        this.slow = slow;
023        this.fast = fast;
024
025        this.sensor.addPropertyChangeListener(this);
026        this.signal.addPropertyChangeListener(this);
027    }
028
029    public RpsBlock(String sensorname, String signalname, float slow, float fast) {
030        this((RpsSensor) jmri.InstanceManager.sensorManagerInstance().getSensor(sensorname),
031                jmri.InstanceManager.getDefault(jmri.SignalHeadManager.class).getSignalHead(signalname),
032                slow, fast);
033    }
034
035    float slow, fast;
036    SignalHead signal = null;
037    RpsSensor sensor = null;
038
039    @Override
040    public void propertyChange(java.beans.PropertyChangeEvent e) {
041        handleParameterChange(e.getPropertyName(),
042                e.getOldValue(), e.getNewValue(),
043                e.getSource());
044    }
045
046    void handleParameterChange(String property,
047            Object oldState, Object newState,
048            Object source) {
049        log.debug("Change {} from {}", property, source);
050        if (property.equals("Arriving")) {
051            arriving((Integer) newState);
052        } else if (property.equals("Leaving")) {
053            leaving((Integer) newState);
054        } else if (property.equals("Appearance")) {
055            appearance();
056        } else {
057            log.debug("Parameter ignored");
058        }
059    }
060
061    // arriving and departing just checks who's here
062    void arriving(Integer number) {
063        acquireThrottle(number);
064        updateCurrentThrottles();
065    }
066
067    void leaving(Integer number) {
068        acquireThrottle(number);
069    }
070
071    void appearance() {
072        updateCurrentThrottles();
073    }
074
075    void acquireThrottle(Integer num) {
076        Object o = throttleTable.get(num);
077        if (o != null) {
078            return;  // already present
079        }
080    }
081
082    @Override
083    public void notifyThrottleFound(DccThrottle t) {
084        // put in map
085        Integer num = Integer.valueOf(((DccLocoAddress) t.getLocoAddress()).getNumber());
086        throttleTable.put(num, t);
087    }
088
089    @Override
090    public void notifyFailedThrottleRequest(LocoAddress address, String reason) {
091    }
092
093    /**
094     * No steal or share decisions made locally
095     * <p>
096     * {@inheritDoc}
097     */
098    @Override
099    public void notifyDecisionRequired(jmri.LocoAddress address, DecisionType question) {
100    }
101
102    void updateCurrentThrottles() {
103        List<Integer> l = sensor.getContents();
104        if (l.size() == 0) {
105            return;
106        }
107        if (l.size() > 1) {
108            log.warn("More than one address present!");
109        }
110        for (int i = 0; i < l.size(); i++) {
111            Integer num = l.get(i);
112            DccThrottle t = throttleTable.get(num);
113            if (t != null) {
114                updateOneThrottle(t);
115            } else {
116                log.warn("Throttle not yet available for: {}", num);
117            }
118        }
119    }
120
121    void updateOneThrottle(DccThrottle t) {
122        // get proper speed
123        int app = signal.getAppearance();
124        switch (app) {
125            case SignalHead.RED:
126                t.setSpeedSetting(0.f);
127                break;
128            case SignalHead.GREEN:
129                t.setSpeedSetting(fast);
130                break;
131            default:
132                t.setSpeedSetting(slow);
133                break;
134        }
135    }
136
137    public void dispose() {
138        sensor.removePropertyChangeListener(this);
139    }
140
141    static java.util.Hashtable<Integer, DccThrottle> throttleTable = new java.util.Hashtable<Integer, DccThrottle>();
142
143    private final static Logger log = LoggerFactory.getLogger(RpsBlock.class);
144
145}