001package jmri.jmrit.ussctc;
002
003import java.util.*;
004import javax.annotation.Nonnull;
005import jmri.*;
006
007/**
008 * Lock if any of the SignalHeads controlling traffic over a turnout are not at stop.
009 * <p>
010 * This checks SignalHeads for RED; it locks against Restricting (FLASHRED) but you can
011 * change that by overriding the checkSignalClear() method.
012 *
013 * @author Bob Jacobsen Copyright (C) 2007, 2017
014 */
015public class RouteLock implements Lock {
016
017    /**
018     * @param list SignalHeads that cover this route
019     */
020    public RouteLock(@Nonnull List<NamedBeanHandle<SignalHead>> list) {
021        this.list = list;
022        this.beans = null;
023    }
024
025    /**
026     * @param list SignalHeads that cover this route
027     * @param beans Defines the specific route
028     */
029    public RouteLock(@Nonnull List<NamedBeanHandle<SignalHead>> list, @Nonnull List<BeanSetting> beans) {
030        this.list = list;
031        this.beans = beans;
032    }
033
034    /**
035     * @param array User or system names of SignalHeads that cover this route
036     */
037    public RouteLock(@Nonnull String[] array) {
038        NamedBeanHandleManager hm = InstanceManager.getDefault(NamedBeanHandleManager.class);
039        SignalHeadManager sm = InstanceManager.getDefault(SignalHeadManager.class);
040
041        ArrayDeque<NamedBeanHandle<SignalHead>> q = new ArrayDeque<>();
042        for (String s : array) {
043            SignalHead sig = sm.getSignalHead(s);
044            if (sig != null) {
045                q.add(hm.getNamedBeanHandle(s, sig));
046            }
047        }
048        this.list = q;
049        this.beans = null;
050    }
051
052    /**
053     * @param array User or system names of SignalHeads that cover this route
054     * @param beans Defines the specific route
055     */
056    public RouteLock(@Nonnull String[] array, @Nonnull BeanSetting[] beans) {
057        NamedBeanHandleManager hm = InstanceManager.getDefault(NamedBeanHandleManager.class);
058        SignalHeadManager sm = InstanceManager.getDefault(SignalHeadManager.class);
059
060        ArrayDeque<NamedBeanHandle<SignalHead>> q1 = new ArrayDeque<>();
061        for (String s : array) {
062            SignalHead sig = sm.getSignalHead(s);
063            if (sig != null) {
064                q1.add(hm.getNamedBeanHandle(s, sig));
065            }
066        }
067        this.list = q1;
068
069        ArrayDeque<BeanSetting> q2 = new ArrayDeque<>();
070        for (BeanSetting bean : beans) {
071            q2.add(bean);
072        }
073        this.beans = q2;
074
075    }
076
077    /**
078     * @param head User or system name of a SignalHead that covers this route
079     */
080    public RouteLock(@Nonnull String head) {
081        this(new String[]{head});
082    }
083
084    Iterable<NamedBeanHandle<SignalHead>> list;
085    Iterable<BeanSetting> beans;
086
087    /**
088     * Test the lock conditions
089     * @return True if lock is clear and operation permitted
090     */
091    @Override
092    public boolean isLockClear(LockLogger lockLogger) {
093        // if this route isn't in effect, then permitted
094        if (beans != null) {
095            for (BeanSetting bean : beans) {
096                if ( ! bean.check()) {
097                    lockLogger.setStatus(this, "");
098                    log.debug("RouteLock OK because {} doesn't match, route not engaged", bean.getBeanName());
099                    return true;
100                }
101            }
102        }
103
104        for (NamedBeanHandle<SignalHead> handle : list) {
105            if ( isSignalClear(handle) ) {
106                lockLogger.setStatus(this, "Locked due to route including signal "+handle.getBean().getDisplayName());
107                log.debug("RouteLock locked due to route including signal {} set clear", handle.getBean().getDisplayName());
108                return false;
109            }
110        }
111        lockLogger.setStatus(this, "");
112        log.debug("RouteLock OK, no signals set clear");
113        return true;
114    }
115
116    boolean isSignalClear(@Nonnull NamedBeanHandle<SignalHead> handle) {
117        return handle.getBean().getState() != SignalHead.RED;
118    }
119
120    @Override
121    public String toString() {
122        String retval = isLockClear(debugLockLogger) ? "clear " : "locked";
123        retval = retval+debugLockLogger.memory.getValue();
124        return retval;
125    }
126
127    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(RouteLock.class);
128}