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    public boolean isAtStop() {
127        if  (speed.equals("0")) return true;  // should this also include DANGER?
128        return false;
129    }
130
131    public boolean isShowingRestricting() {
132        if (getAspect().equals(getAppearanceMap().getSpecificAppearance(jmri.SignalAppearanceMap.PERMISSIVE))) return true;
133        return false;
134    }
135
136    public boolean isCleared() {
137        if (getAspect().equals(getAppearanceMap().getSpecificAppearance(jmri.SignalAppearanceMap.PERMISSIVE))) return false;
138        if (getAspect().equals(getAppearanceMap().getSpecificAppearance(jmri.SignalAppearanceMap.HELD))) return false;
139        if (getAspect().equals(getAppearanceMap().getSpecificAppearance(jmri.SignalAppearanceMap.DANGER))) return false;
140        return true;
141    }
142
143    protected DefaultSignalAppearanceMap map;
144    SignalSystem systemDefn;
145
146    boolean disablePermissiveSignalMastLogic = false;
147    @Override
148    public void setPermissiveSmlDisabled(boolean disabled) {
149        disablePermissiveSignalMastLogic = disabled;
150        firePropertyChange("PermissiveSmlDisabled", null, disabled);
151    }
152    /**
153     * {@inheritDoc }
154     */
155    @Override
156    public boolean isPermissiveSmlDisabled() {
157        return disablePermissiveSignalMastLogic;
158    }
159
160    protected void configureSignalSystemDefinition(String name) {
161        systemDefn = InstanceManager.getDefault(jmri.SignalSystemManager.class).getSystem(name);
162        if (systemDefn == null) {
163            log.error("Did not find signal definition: {}", name);
164            throw new IllegalArgumentException("Signal definition not found: " + name);
165        }
166    }
167
168    protected void configureAspectTable(String signalSystemName, String aspectMapName) {
169        map = DefaultSignalAppearanceMap.getMap(signalSystemName, aspectMapName);
170    }
171
172    @Override
173    public SignalSystem getSignalSystem() {
174        return systemDefn;
175    }
176
177    @Override
178    public SignalAppearanceMap getAppearanceMap() {
179        return map;
180    }
181
182    protected ArrayList<String> disabledAspects = new ArrayList<>(1);
183
184    @Override
185    @Nonnull
186    public Vector<String> getValidAspects() {
187        java.util.Enumeration<String> e = map.getAspects();
188        // copy List to Vector
189        Vector<String> v = new Vector<>();
190        while (e.hasMoreElements()) {
191            String a = e.nextElement();
192            if (!disabledAspects.contains(a)) {
193                v.add(a);
194            }
195        }
196        return v;
197    }
198
199    /**
200     * {@inheritDoc }
201     */
202    @Override
203    public String getMastType() { return mastType; }
204    @Override
205    public void setMastType(@Nonnull String type) {
206        Objects.requireNonNull(type, "MastType cannot be null");
207        mastType = type;
208    }
209    String mastType;
210
211    /**
212     * Get a list of all the known aspects for this mast, including those that
213     * have been disabled.
214     *
215     * @return list of known aspects; may be empty
216     */
217    public Vector<String> getAllKnownAspects() {
218        java.util.Enumeration<String> e = map.getAspects();
219        Vector<String> v = new Vector<>();
220        while (e.hasMoreElements()) {
221            v.add(e.nextElement());
222        }
223        return v;
224    }
225
226    public void setAspectDisabled(String aspect) {
227        if (aspect == null || aspect.equals("")) {
228            return;
229        }
230        if (!map.checkAspect(aspect)) {
231            log.warn("attempting to disable an aspect: {} that is not on the mast {}", aspect, getDisplayName());
232            return;
233        }
234        if (!disabledAspects.contains(aspect)) {
235            disabledAspects.add(aspect);
236            firePropertyChange("aspectDisabled", null, aspect);
237        }
238    }
239
240    public void setAspectEnabled(String aspect) {
241        if (aspect == null || aspect.equals("")) {
242            return;
243        }
244        if (!map.checkAspect(aspect)) {
245            log.warn("attempting to disable an aspect: {} that is not on the mast {}", aspect, getDisplayName());
246            return;
247        }
248        if (disabledAspects.contains(aspect)) {
249            disabledAspects.remove(aspect);
250            firePropertyChange("aspectEnabled", null, aspect);
251        }
252    }
253
254    public List<String> getDisabledAspects() {
255        return disabledAspects;
256    }
257
258    @Override
259    public boolean isAspectDisabled(String aspect) {
260        return disabledAspects.contains(aspect);
261    }
262
263    boolean allowUnLit = true;
264
265    @Override
266    public void setAllowUnLit(boolean boo) {
267        allowUnLit = boo;
268    }
269
270    @Override
271    public boolean allowUnLit() {
272        return allowUnLit;
273    }
274
275    @Override
276    public void vetoableChange(java.beans.PropertyChangeEvent evt) throws java.beans.PropertyVetoException {
277    }
278
279    @Override
280    public String getBeanType() {
281        return Bundle.getMessage("BeanNameSignalMast");
282    }
283
284}