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        notifyConsistListChanged();
074        return consist;
075    }
076
077    private void addConsist(NceConsist consist) {
078        log.debug("Add consist {}", consist.getConsistAddress());
079        //delConsist(consist.getConsistAddress()); // remove consist if one exists
080        consistTable.put(consist.getConsistAddress(), consist);
081        notifyConsistListChanged();
082    }
083
084    @Override
085    public Consist getConsist(LocoAddress locoAddress) {
086        log.debug("Requesting NCE consist {}", locoAddress);
087        NceConsist consist = (NceConsist) super.getConsist(locoAddress);
088        // Checking the CS memory each time a consist is requested creates lots of NCE messages!
089        //consist.checkConsist();
090        return consist;
091    }
092
093    // remove the old Consist
094    @Override
095    public void delConsist(LocoAddress locoAddress) {
096        NceConsist consist = (NceConsist) getConsist(locoAddress);
097        // kill this consist
098        consist.dispose();
099        super.delConsist(locoAddress);
100    }
101
102    public void startConsistReader() {
103        // read command station memory (not USB and not simulator) Can't determine if simulator selected, but can determine if port name is the default
104        if (memo.getNceUsbSystem() == NceTrafficController.USB_SYSTEM_NONE && !memo.getNceTrafficController().getPortName().equals(JmrixConfigPane.NONE_SELECTED)
105                && memo.getNceTrafficController().getCommandOptions() > NceTrafficController.OPTION_1999) {
106            new NceConsistReader().start();
107        }
108    }
109
110    public class NceConsistReader extends Thread {
111
112        int _consistNum = NceConsist.CONSIST_MAX;
113
114        NceConsistReader() {
115            setName("Initialize NCE consists");
116        }
117
118        @Override
119        public void run() {
120            searchNext();
121        }
122
123        // NCE allocates consist numbers starting at 127, so we do the same
124        private void searchNext() {
125            synchronized (this) {
126                // we need to wait for the connection to be up and running
127                while (!ConnectionStatus.instance()
128                            .getConnectionState(memo.getUserName(), memo.getNceTrafficController().getPortName())
129                        .equals(ConnectionStatus.CONNECTION_UP)) {
130                    log.debug("Waiting for NCE connected");
131                    try {
132                        wait(2000); // wait 2 seconds and try again
133                    } catch (InterruptedException e) {
134                        Thread.currentThread().interrupt(); // retain if needed later
135                    }
136                }
137            }
138            while (_consistNum >= NceConsist.CONSIST_MIN) {
139                if (log.isDebugEnabled()) {
140                    log.debug("Reading consist from command station: {}", _consistNum);
141                }
142                NceConsist consist = new NceConsist(_consistNum, memo);
143                // wait until consist finishes CS read
144                while (!consist.isValid()) {
145                    synchronized (this) {
146                        try {
147                            //log.debug("Waiting for consist "+_consistNum+" to be valid");
148                            wait(100); // wait 100 milliseconds and check again
149                        } catch (InterruptedException e) {
150                            Thread.currentThread().interrupt(); // retain if needed later
151                        }
152                    }
153                }
154                if (consist.getConsistList().size() > 0) {
155                    addConsist(consist);
156                }
157                _consistNum--;
158            }
159            // when we finish reading, notify any listeners.
160            notifyConsistListChanged();
161        }
162    }
163
164    private final static Logger log = LoggerFactory.getLogger(NceConsistManager.class);
165
166}