001package jmri.implementation;
002
003import java.util.*;
004import javax.annotation.*;
005import jmri.InstanceManager;
006import jmri.SignalAppearanceMap;
007import jmri.SignalMast;
008import jmri.SignalSystem;
009
010import org.slf4j.Logger;
011import org.slf4j.LoggerFactory;
012
013/**
014 * Abstract class providing the basic logic of the SignalMast interface.
015 *
016 * @author Bob Jacobsen Copyright (C) 2009
017 */
018public abstract class AbstractSignalMast extends AbstractNamedBean
019        implements SignalMast, java.beans.VetoableChangeListener {
020
021    private final static Logger log = LoggerFactory.getLogger(AbstractSignalMast.class);
022
023    public AbstractSignalMast(String systemName, String userName) {
024        super(systemName, userName);
025    }
026
027    public AbstractSignalMast(String systemName) {
028        super(systemName);
029    }
030
031    @Override
032    public void setAspect(@Nonnull String aspect) {
033        String oldAspect = this.aspect;
034        this.aspect = aspect;
035        this.speed = (String) getSignalSystem().getProperty(aspect, "speed");
036        firePropertyChange("Aspect", oldAspect, aspect);
037    }
038
039    @Override
040    public String getAspect() {
041        return aspect;
042    }
043    protected String aspect = null;
044
045    public String getSpeed() {
046        return speed;
047    }
048    protected String speed = null;
049
050    /**
051     * The state is the index of the current aspect in the list of possible
052     * aspects.
053     */
054    @Override
055    public int getState() {
056        return -1;
057    }
058
059    @Override
060    public void setState(int i) {
061    }
062
063    /**
064     * By default, signals are lit.
065     */
066    private boolean mLit = true;
067
068    /**
069     * Default behavior for "lit" property is to track value and return it.
070     */
071    @Override
072    public boolean getLit() {
073        return mLit;
074    }
075
076    /**
077     * By default, signals are not held.
078     */
079    private boolean mHeld = false;
080
081    /**
082     * "Held" property is just tracked and notified.
083     */
084    @Override
085    public boolean getHeld() {
086        return mHeld;
087    }
088
089    /**
090     * Set the lit property.
091     * <p>
092     * This acts on all the SignalHeads included in this SignalMast
093     *
094     * @param newLit the new value of lit
095     */
096    @Override
097    public void setLit(boolean newLit) {
098        boolean oldLit = mLit;
099        mLit = newLit;
100        if (oldLit != newLit) {
101            //updateOutput();
102            // notify listeners, if any
103            firePropertyChange("Lit", oldLit, newLit);
104        }
105    }
106
107    /**
108     * Set the held property of the signal mast.
109     * <p>
110     * Note that this does not directly effect the output on the layout; the
111     * held property is a local variable which effects the aspect only via
112     * higher-level logic.
113     *
114     * @param newHeld the new value of the help property
115     */
116    @Override
117    public void setHeld(boolean newHeld) {
118        boolean oldHeld = mHeld;
119        mHeld = newHeld;
120        if (oldHeld != newHeld) {
121            // notify listeners, if any
122            firePropertyChange("Held", oldHeld, newHeld);
123        }
124    }
125
126    @Override
127    public boolean isAtStop() {
128        if  (speed.equals("0")) return true;  // should this also include DANGER?
129        return false;
130    }
131
132    @Override
133    public boolean isShowingRestricting() {
134        String displayedAspect = getAspect();
135        if ( displayedAspect != null && displayedAspect.equals(getAppearanceMap().getSpecificAppearance(jmri.SignalAppearanceMap.PERMISSIVE))) return true;
136        return false;
137    }
138
139    @Override
140    public boolean isCleared() {
141        String displayedAspect = getAspect();
142        if ( displayedAspect == null ) {
143            return false;
144        }
145        if (displayedAspect.equals(getAppearanceMap().getSpecificAppearance(jmri.SignalAppearanceMap.PERMISSIVE))) return false;
146        if (displayedAspect.equals(getAppearanceMap().getSpecificAppearance(jmri.SignalAppearanceMap.HELD))) return false;
147        if (displayedAspect.equals(getAppearanceMap().getSpecificAppearance(jmri.SignalAppearanceMap.DANGER))) return false;
148        return true;
149    }
150
151    protected DefaultSignalAppearanceMap map;
152    SignalSystem systemDefn;
153
154    boolean disablePermissiveSignalMastLogic = false;
155    @Override
156    public void setPermissiveSmlDisabled(boolean disabled) {
157        disablePermissiveSignalMastLogic = disabled;
158        firePropertyChange("PermissiveSmlDisabled", null, disabled);
159    }
160    /**
161     * {@inheritDoc }
162     */
163    @Override
164    public boolean isPermissiveSmlDisabled() {
165        return disablePermissiveSignalMastLogic;
166    }
167
168    protected void configureSignalSystemDefinition(String name) {
169        systemDefn = InstanceManager.getDefault(jmri.SignalSystemManager.class).getSystem(name);
170        if (systemDefn == null) {
171            log.error("Did not find signal definition: {}", name);
172            throw new IllegalArgumentException("Signal definition not found: " + name);
173        }
174    }
175
176    protected void configureAspectTable(String signalSystemName, String aspectMapName) {
177        map = DefaultSignalAppearanceMap.getMap(signalSystemName, aspectMapName);
178    }
179
180    @Override
181    public SignalSystem getSignalSystem() {
182        return systemDefn;
183    }
184
185    @Override
186    public SignalAppearanceMap getAppearanceMap() {
187        return map;
188    }
189
190    protected ArrayList<String> disabledAspects = new ArrayList<>(1);
191
192    @Override
193    @Nonnull
194    public Vector<String> getValidAspects() {
195        java.util.Enumeration<String> e = map.getAspects();
196        // copy List to Vector
197        Vector<String> v = new Vector<>();
198        while (e.hasMoreElements()) {
199            String a = e.nextElement();
200            if (!disabledAspects.contains(a)) {
201                v.add(a);
202            }
203        }
204        return v;
205    }
206
207    /**
208     * {@inheritDoc }
209     */
210    @Override
211    public String getMastType() { return mastType; }
212    @Override
213    public void setMastType(@Nonnull String type) {
214        Objects.requireNonNull(type, "MastType cannot be null");
215        mastType = type;
216    }
217    String mastType;
218
219    /**
220     * Get a list of all the known aspects for this mast, including those that
221     * have been disabled.
222     *
223     * @return list of known aspects; may be empty
224     */
225    public Vector<String> getAllKnownAspects() {
226        java.util.Enumeration<String> e = map.getAspects();
227        Vector<String> v = new Vector<>();
228        while (e.hasMoreElements()) {
229            v.add(e.nextElement());
230        }
231        return v;
232    }
233
234    public void setAspectDisabled(String aspect) {
235        if (aspect == null || aspect.equals("")) {
236            return;
237        }
238        if (!map.checkAspect(aspect)) {
239            log.warn("attempting to disable an aspect: {} that is not on the mast {}", aspect, getDisplayName());
240            return;
241        }
242        if (!disabledAspects.contains(aspect)) {
243            disabledAspects.add(aspect);
244            firePropertyChange("aspectDisabled", null, aspect);
245        }
246    }
247
248    public void setAspectEnabled(String aspect) {
249        if (aspect == null || aspect.equals("")) {
250            return;
251        }
252        if (!map.checkAspect(aspect)) {
253            log.warn("attempting to disable an aspect: {} that is not on the mast {}", aspect, getDisplayName());
254            return;
255        }
256        if (disabledAspects.contains(aspect)) {
257            disabledAspects.remove(aspect);
258            firePropertyChange("aspectEnabled", null, aspect);
259        }
260    }
261
262    public List<String> getDisabledAspects() {
263        return disabledAspects;
264    }
265
266    @Override
267    public boolean isAspectDisabled(String aspect) {
268        return disabledAspects.contains(aspect);
269    }
270
271    boolean allowUnLit = true;
272
273    @Override
274    public void setAllowUnLit(boolean boo) {
275        allowUnLit = boo;
276    }
277
278    @Override
279    public boolean allowUnLit() {
280        return allowUnLit;
281    }
282
283    @Override
284    public void vetoableChange(java.beans.PropertyChangeEvent evt) throws java.beans.PropertyVetoException {
285    }
286
287    @Override
288    public String getBeanType() {
289        return Bundle.getMessage("BeanNameSignalMast");
290    }
291
292}