001package jmri.jmrit.ctc.topology;
002
003import java.util.*;
004import jmri.*;
005import jmri.jmrit.ctc.ctcserialdata.CTCSerialData;
006
007/**
008 * This class contains all of the information needed (in lists) for the higher level
009 * "TRL_Rules" to generate all of the entries in "_mTRL_TrafficLockingRulesSSVList"
010 * 
011 * @author Gregory J. Bedlek Copyright (C) 2018, 2019, 2020
012 */
013
014public class TopologyInfo {
015    private final CTCSerialData _mCTCSerialData;    // Needed to look up a turnout in order to return an O.S. section text.
016    private final String _mDestinationSignalMast;
017    private final String _mNormal;                  // Bundle.getMessage("TLE_Normal")
018    private final String _mReverse;                 // Bundle.getMessage("TLE_Reverse")
019    public TopologyInfo() { // Temporary for test suite only
020        _mCTCSerialData = null;
021        _mDestinationSignalMast = null;
022        _mNormal = null;
023        _mReverse = null; 
024    }
025    public TopologyInfo(CTCSerialData CTCSerialData, String destinationSignalMast, String normal, String reverse) {
026        _mCTCSerialData = CTCSerialData;
027        _mDestinationSignalMast = destinationSignalMast;
028        _mNormal = normal;
029        _mReverse = reverse;
030    }
031    public String getDestinationSignalMast() { return _mDestinationSignalMast; }
032    
033    /**
034     * Simple class to contain simple info about a turnout.
035     */
036    private static class TurnoutInfo {
037        public final String _mOSSectionText;
038        public final String _mNormalReversed;
039        public final int    _mUniqueID;
040        public TurnoutInfo(String OSSectionText, String normalReversed, int uniqueID) {
041            _mOSSectionText = OSSectionText;
042            _mNormalReversed = normalReversed;
043            _mUniqueID = uniqueID;
044        }
045    }
046    private final ArrayList<Sensor> _mSensors = new ArrayList<>();
047//  private final LinkedList<String> _mSensorNamesDebug = new LinkedList<>();    //Debugging
048    private final ArrayList<TurnoutInfo> _mTurnoutInfos = new ArrayList<>();
049//  private final LinkedList<String> _mOSSectionInfosDebug = new LinkedList<>(); //Debugging
050    private final ArrayList<Turnout> _mTurnouts = new ArrayList<>();  // ONLY used for duplicate check (lazy).
051    
052    /**
053     * @return true if any of our lists have anything.
054     */
055    public boolean nonEmpty() { return !_mSensors.isEmpty() || !_mTurnoutInfos.isEmpty(); }
056    
057    /**
058     * Quick and dirty routine to get O.S. section information.
059     * 
060     * @param index Index into array
061     * @return null if no information, else text (of form "29/30" for instance)
062     */
063    public String getOSSectionText(int index) {
064        if (index < _mTurnoutInfos.size()) { // Safety: Can return info:
065            return _mTurnoutInfos.get(index)._mOSSectionText;
066        } else {
067            return null;
068        }
069    }
070
071    
072    /**
073     * Quick and dirty routine to get "Normal"/"Reverse" information.
074     * 
075     * @param index Index into array
076     * @return "Normal" if no information, else text (of form "Normal" for instance)
077     */
078    public String getNormalReversed(int index) {
079        if (index < _mTurnoutInfos.size()) { // Safety: Can return info:
080            return _mTurnoutInfos.get(index)._mNormalReversed;
081        } else {
082            return "Normal";    // Doesn't hurt to return this for a turnout that has no information.
083        }
084    }
085
086    
087    /**
088     * Quick and dirty routine to get the Display Name of the sensor.
089     * 
090     * @param index Index into array
091     * @return "" if no information, else text (of form "SW31-OS" for instance)
092     */
093    public String getSensorDisplayName(int index) {
094        if (index < _mSensors.size()) { // Safety: Can return info:
095            return _mSensors.get(index).getDisplayName();
096        } else {
097            return "";
098        }
099    }
100    
101    
102    /**
103     * Quick and dirty routine to get the unique id..
104     * 
105     * @param index Index into array
106     * @return null if no information, else uniqueID as String of the O.S. section.
107     */
108    public String getUniqueID(int index) {
109        if (index < _mTurnoutInfos.size()) { // Safety: Can return info:
110            return Integer.toString(_mTurnoutInfos.get(index)._mUniqueID);
111        } else {
112            return null;
113        }
114    }
115    
116    
117    /**    
118     * Quick and dirty routine to all all of the sensors in the passed blocks to
119     * our internal lists.  Duplicates are ignored.  It is possible that the user
120     * didn't associate a sensor with the block.  Ignore such entries.
121     * @param blocks    List of Blocks to add.
122     */
123    public void addBlocks(List<Block> blocks) {
124        for (Block block : blocks) {
125            Sensor sensor = block.getSensor();
126            if (null != sensor && !_mSensors.contains(sensor)) { //  Safety: valid && VERIFY not in list already for some reason (safety, shouldn't happen):
127                _mSensors.add(sensor);
128//              _mSensorNamesDebug.add(sensor.getDisplayName());
129            }
130        }
131    }
132    
133    
134    /**
135     * Quick and dirty routine to add all of the turnouts in SML to our internal lists.
136     * Duplicates are ignored.
137     * 
138     * @param signalMastLogic   SML to work against.
139     * @param signalMast        Destination mast in SML.
140     */
141    public void addTurnouts(SignalMastLogic signalMastLogic, SignalMast signalMast) {
142//  Right now, I cannot make a subroutine call out of this, because I have to call two different
143//  routines at the lowest level: "signalMastLogic.getTurnoutState" and "signalMastLogic.getAutoTurnoutState"
144//  depending on which it is.  In Java method reference is a way.  But I'm lazy and in a hurry:
145        for (Turnout turnout : signalMastLogic.getTurnouts(signalMast)) {
146            if (!_mTurnouts.contains(turnout)) {    // VERIFY not in list already for some reason (safety, shouldn't happen):
147                _mTurnouts.add(turnout);            // For above if statement dup check.
148//  Need to convert the turnout to an O.S. section text:                
149                CTCSerialData.CTCTurnoutData turnoutData = _mCTCSerialData.getCTCTurnoutData(turnout);
150                if (null != turnoutData) { // Safety:
151//  ToDo someday: Reverse "isNormal" if feedback different?                    
152                    boolean isNormal = signalMastLogic.getTurnoutState(turnout, signalMast) == Turnout.CLOSED;
153                    _mTurnoutInfos.add(new TurnoutInfo(turnoutData._mOSSectionText, isNormal ? _mNormal : _mReverse, turnoutData._mUniqueID));
154//                  _mOSSectionInfosDebug.add(OSSectionText);
155                }
156            }
157        }
158        for (Turnout turnout : signalMastLogic.getAutoTurnouts(signalMast)) {
159            if (!_mTurnouts.contains(turnout)) {    // VERIFY not in list already for some reason (safety, shouldn't happen):
160                _mTurnouts.add(turnout);            // For above if statement dup check.
161//  Need to convert the turnout to an O.S. section text:                
162                CTCSerialData.CTCTurnoutData turnoutData = _mCTCSerialData.getCTCTurnoutData(turnout);
163                if (null != turnoutData) { // Safety:
164//  ToDo someday: Reverse "isNormal" if feedback different?                    
165                    boolean isNormal = signalMastLogic.getAutoTurnoutState(turnout, signalMast) == Turnout.CLOSED;
166                    _mTurnoutInfos.add(new TurnoutInfo(turnoutData._mOSSectionText, isNormal ? _mNormal : _mReverse, turnoutData._mUniqueID));
167//                  _mOSSectionInfosDebug.add(OSSectionText);
168                }
169            }
170        }
171    }
172}