001package jmri.implementation;
002
003import java.util.Arrays;
004import jmri.NamedBeanHandle;
005import jmri.Turnout;
006
007/**
008 * Drive a single signal head via four "Turnout" objects.
009 * <p>
010 * After much confusion, the user-level terminology was changed to call these
011 * "Triple Output"; the class name remains the same to reduce recoding.
012 * <p>
013 * The four Turnout objects are provided during construction, and each drives a
014 * specific color (RED, YELLOW, GREEN, and LUNAR). Normally, "THROWN" is on, and
015 * "CLOSED" is off.
016 * <p>
017 * This class doesn't currently listen to the Turnout's to see if they've been
018 * changed via some other mechanism.
019 *
020 * @author Bob Jacobsen Copyright (C) 2009
021 */
022public class QuadOutputSignalHead extends TripleTurnoutSignalHead {
023
024    public QuadOutputSignalHead(String sys, String user, NamedBeanHandle<Turnout> green, NamedBeanHandle<Turnout> yellow, NamedBeanHandle<Turnout> red, NamedBeanHandle<Turnout> lunar) {
025        super(sys, user, green, yellow, red);
026        mLunar = lunar;
027    }
028
029    public QuadOutputSignalHead(String sys, NamedBeanHandle<Turnout> green, NamedBeanHandle<Turnout> yellow, NamedBeanHandle<Turnout> red, NamedBeanHandle<Turnout> lunar) {
030        super(sys, green, yellow, red);
031        mLunar = lunar;
032    }
033
034    @Override
035    protected void updateOutput() {
036        if (mLit == false) {
037            super.updateOutput();
038        } else if (!mFlashOn
039                && ((mAppearance == FLASHGREEN)
040                || (mAppearance == FLASHYELLOW)
041                || (mAppearance == FLASHRED)
042                || (mAppearance == FLASHLUNAR))) {
043            // flash says to make output dark
044            mRed.getBean().setCommandedState(Turnout.CLOSED);
045            mYellow.getBean().setCommandedState(Turnout.CLOSED);
046            mGreen.getBean().setCommandedState(Turnout.CLOSED);
047            mLunar.getBean().setCommandedState(Turnout.CLOSED);
048
049        } else {
050            switch (mAppearance) {
051                case LUNAR:
052                case FLASHLUNAR:
053                    mLunar.getBean().setCommandedState(Turnout.THROWN);
054                    mRed.getBean().setCommandedState(Turnout.CLOSED);
055                    mYellow.getBean().setCommandedState(Turnout.CLOSED);
056                    mGreen.getBean().setCommandedState(Turnout.CLOSED);
057                    break;
058                default:
059                    // let parent handle rest of cases
060                    mLunar.getBean().setCommandedState(Turnout.CLOSED);
061                    super.updateOutput();
062                    break;
063            }
064        }
065    }
066
067    /**
068     * Remove references to and from this object, so that it can eventually be
069     * garbage-collected.
070     */
071    @Override
072    public void dispose() {
073        mLunar = null;
074        super.dispose();
075    }
076
077    NamedBeanHandle<Turnout> mLunar;
078
079    public NamedBeanHandle<Turnout> getLunar() {
080        return mLunar;
081    }
082
083    public void setLunar(NamedBeanHandle<Turnout> t) {
084        mLunar = t;
085    }
086
087    // claim support for Lunar aspects
088    private final static int[] validStates = new int[]{
089        DARK,
090        RED,
091        LUNAR,
092        YELLOW,
093        GREEN,
094        FLASHRED,
095        FLASHLUNAR,
096        FLASHYELLOW,
097        FLASHGREEN
098    };
099    private static final String[] validStateKeys = new String[]{
100            "SignalHeadStateDark",
101            "SignalHeadStateRed",
102            "SignalHeadStateLunar",
103            "SignalHeadStateYellow",
104            "SignalHeadStateGreen",
105            "SignalHeadStateFlashingRed",
106            "SignalHeadStateFlashingLunar",
107            "SignalHeadStateFlashingYellow",
108            "SignalHeadStateFlashingGreen"
109    };
110
111    /**
112     * {@inheritDoc}
113     */
114    @Override
115    public int[] getValidStates() {
116        return Arrays.copyOf(validStates, validStates.length);
117    }
118
119    /**
120     * {@inheritDoc}
121     */
122    @Override
123    public String[] getValidStateKeys() {
124        return Arrays.copyOf(validStateKeys, validStateKeys.length); // includes int for Lunar
125    }
126
127    /**
128     * {@inheritDoc}
129     */
130    @Override
131    public String[] getValidStateNames() {
132        String[] stateNames = new String[validStateKeys.length];
133        int i = 0;
134        for (String stateKey : validStateKeys) {
135            stateNames[i++] = Bundle.getMessage(stateKey);
136        }
137        return stateNames;
138    }
139
140    @Override
141    boolean isTurnoutUsed(Turnout t) {
142        if (super.isTurnoutUsed(t)) {
143            return true;
144        }
145        return getLunar() != null && t.equals(getLunar().getBean());
146    }
147}