001/**
002 * Consist Manager for use with the NceConsist class for the
003 * consists it builds.
004 *
005 * @author Paul Bender Copyright (C) 2011
006 * @author Daniel Boudreau Copyright (C) 2012
007 */
008package jmri.jmrix.nce;
009
010import jmri.Consist;
011import jmri.LocoAddress;
012import jmri.DccLocoAddress;
013import jmri.implementation.AbstractConsistManager;
014import jmri.jmrix.ConnectionStatus;
015import jmri.jmrix.JmrixConfigPane;
016import org.slf4j.Logger;
017import org.slf4j.LoggerFactory;
018
019public class NceConsistManager extends AbstractConsistManager {
020
021    private NceSystemConnectionMemo memo = null;
022
023    public NceConsistManager(NceSystemConnectionMemo m) {
024        super();
025        memo = m;
026    }
027
028    /**
029     * Request an update from the layout, loading
030     * Consists from the command station.
031     */
032    @Override
033    public void requestUpdateFromLayout() {
034        if (shouldRequestUpdateFromLayout()) {
035            startConsistReader();
036        }
037    }
038
039    /**
040     * This implementation does not support command station assisted consists,
041     * so return false.
042     *
043     */
044    @Override
045    public boolean isCommandStationConsistPossible() {
046        return false;
047    }
048
049    /**
050     * Does a CS consist require a separate consist address?
051     *
052     */
053    @Override
054    public boolean csConsistNeedsSeperateAddress() {
055        return false;
056    }
057
058    /**
059     * Add a new NceConsist with the given address to consistTable/consistList
060     */
061    @Override
062    public Consist addConsist(LocoAddress locoAddress) {
063        if (! (locoAddress instanceof DccLocoAddress)) {
064            throw new IllegalArgumentException("locoAddress is not a DccLocoAddress object");
065        }
066        if (consistTable.containsKey(locoAddress)) // no duplicates allowed.
067        {
068            return consistTable.get(locoAddress);
069        }
070        log.debug("Add consist, address {}", locoAddress);
071        NceConsist consist = new NceConsist((DccLocoAddress) locoAddress, memo);
072        consistTable.put(locoAddress, consist);
073        return consist;
074    }
075
076    private void addConsist(NceConsist consist) {
077        log.debug("Add consist {}", consist.getConsistAddress());
078        //delConsist(consist.getConsistAddress()); // remove consist if one exists
079        consistTable.put(consist.getConsistAddress(), consist);
080    }
081
082    @Override
083    public Consist getConsist(LocoAddress locoAddress) {
084        log.debug("Requesting NCE consist {}", locoAddress);
085        NceConsist consist = (NceConsist) super.getConsist(locoAddress);
086        // Checking the CS memory each time a consist is requested creates lots of NCE messages!
087        //consist.checkConsist();
088        return consist;
089    }
090
091    // remove the old Consist
092    @Override
093    public void delConsist(LocoAddress locoAddress) {
094        NceConsist consist = (NceConsist) getConsist(locoAddress);
095        // kill this consist
096        consist.dispose();
097        super.delConsist(locoAddress);
098    }
099
100    public void startConsistReader() {
101        // read command station memory (not USB and not simulator) Can't determine if simulator selected, but can determine if port name is the default
102        if (memo.getNceUsbSystem() == NceTrafficController.USB_SYSTEM_NONE && !memo.getNceTrafficController().getPortName().equals(JmrixConfigPane.NONE_SELECTED)
103                && memo.getNceTrafficController().getCommandOptions() > NceTrafficController.OPTION_1999) {
104            new NceConsistReader().start();
105        }
106    }
107
108    public class NceConsistReader extends Thread {
109
110        int _consistNum = NceConsist.CONSIST_MAX;
111
112        NceConsistReader() {
113            setName("Initialize NCE consists");
114        }
115
116        @Override
117        public void run() {
118            searchNext();
119        }
120
121        // NCE allocates consist numbers starting at 127, so we do the same
122        private void searchNext() {
123            synchronized (this) {
124                // we need to wait for the connection to be up and running
125                while (!ConnectionStatus.instance()
126                            .getConnectionState(memo.getUserName(), memo.getNceTrafficController().getPortName())
127                        .equals(ConnectionStatus.CONNECTION_UP)) {
128                    log.debug("Waiting for NCE connected");
129                    try {
130                        wait(2000); // wait 2 seconds and try again
131                    } catch (InterruptedException e) {
132                        Thread.currentThread().interrupt(); // retain if needed later
133                    }
134                }
135            }
136            while (_consistNum >= NceConsist.CONSIST_MIN) {
137                if (log.isDebugEnabled()) {
138                    log.debug("Reading consist from command station: {}", _consistNum);
139                }
140                NceConsist consist = new NceConsist(_consistNum, memo);
141                // wait until consist finishes CS read
142                while (!consist.isValid()) {
143                    synchronized (this) {
144                        try {
145                            //log.debug("Waiting for consist "+_consistNum+" to be valid");
146                            wait(100); // wait 100 milliseconds and check again
147                        } catch (InterruptedException e) {
148                            Thread.currentThread().interrupt(); // retain if needed later
149                        }
150                    }
151                }
152                if (consist.getConsistList().size() > 0) {
153                    addConsist(consist);
154                }
155                _consistNum--;
156            }
157            // when we finish reading, notify any listeners.
158            notifyConsistListChanged();
159        }
160    }
161
162    private final static Logger log = LoggerFactory.getLogger(NceConsistManager.class);
163
164}