001package jmri.jmrix.loconet.logixng.swing;
002
003import java.awt.Frame;
004import java.awt.event.WindowAdapter;
005import java.awt.event.WindowEvent;
006import java.awt.event.ActionEvent;
007
008import javax.swing.BoxLayout;
009import javax.swing.*;
010
011import jmri.*;
012import jmri.jmrix.loconet.*;
013import jmri.util.ThreadingUtil;
014
015/**
016 * This dialog tests how many slots the command station has for engines.
017 * 
018 * @author Daniel Bergqvist Copyright 2020
019 */
020public class GetNumSlotsDialog extends JDialog implements ThrottleListener, SlotListener {
021    
022    private static final int NUM_LOCO_TO_REQUEST = 119;
023    
024    private final LocoNetSystemConnectionMemo _memo;
025    private JTextField _numEnginesField;
026    private JTextField _requestLocoField;
027    private JLabel _status;
028    private int _maxNumLocos = 0;
029    private boolean _freeSlots = false;
030    private final JTextField _textField;
031    private volatile boolean _abort = false;
032    
033    
034    public GetNumSlotsDialog(LocoNetSystemConnectionMemo memo, JTextField textField) {
035        super((Frame)null, true);
036        _memo = memo;
037        _textField = textField;
038    }
039    
040    public void initComponents() {
041        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
042        
043        this.addWindowListener(new WindowAdapter() {
044            @Override
045            public void windowClosing(WindowEvent windowEvent) {
046                _abort = true;
047                releaseThrottles();
048            }
049        });
050        
051        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
052        
053        JPanel numEnginesPanel = new JPanel();
054        numEnginesPanel.add(new JLabel("Current number of engines: "));
055        _numEnginesField = new JTextField("0");
056        _numEnginesField.setColumns(5);
057        _numEnginesField.setEnabled(false);
058        numEnginesPanel.add(_numEnginesField);
059        
060        JPanel requestLocoPanel = new JPanel();
061        _requestLocoField = new JTextField("0");
062        _requestLocoField.setColumns(5);
063        _requestLocoField.setEnabled(false);
064        JButton cancelRequestLocoField = new JButton(Bundle.getMessage("ButtonCancel"));
065        cancelRequestLocoField.addActionListener((ActionEvent e) -> {
066//            new GetNumSlotsDialog().initComponents();
067        });
068        requestLocoPanel.add(new JLabel("Request loco: "));
069        requestLocoPanel.add(_requestLocoField);
070        requestLocoPanel.add(cancelRequestLocoField);
071        
072        getContentPane().add(numEnginesPanel);
073        getContentPane().add(requestLocoPanel);
074        
075        _status = new JLabel("aaa");
076        getContentPane().add(_status);
077        
078        JButton buttonOK = new JButton(Bundle.getMessage("ButtonOK"));
079        buttonOK.addActionListener((ActionEvent e) -> {
080            _abort = true;
081            releaseThrottles();
082            dispose();
083        });
084        getContentPane().add(buttonOK);
085        
086        pack();
087        setLocationRelativeTo(null);
088        
089        _memo.getSlotManager().addSlotListener(this);
090        
091        ThreadingUtil.runOnGUIEventually(() -> {
092            _freeSlots = true;
093            _memo.getSlotManager().update();
094        });
095        
096        // Wait 10 seconds before starting to try request throttles
097        ThreadingUtil.runOnGUIDelayed(() -> {
098            _freeSlots = false;
099            requestThrottle(1);
100        },10000);
101        
102        setVisible(true);
103    }
104    
105    private void requestThrottle(int address) {
106//        System.out.format("Request throttle: %d%n", address);
107        ThreadingUtil.runOnGUI(() -> {
108            _requestLocoField.setText(Integer.toString(address));
109        });
110//        boolean result = InstanceManager.getDefault(ThrottleManager.class)
111        boolean result = _memo.getThrottleManager().requestThrottle(address, this);
112        if (!result && (address < NUM_LOCO_TO_REQUEST)) requestThrottle(address+1);
113    }
114    
115    private void updateNumLocos() {
116//        System.out.format("Update num locos%n");
117        // _maxNumLocos
118        int numLocos = 0;
119        SlotManager slotManager = _memo.getSlotManager();
120        for (int i=1; i <= 119; i++) {
121            LocoNetSlot slot = slotManager.slot(i);
122            if ((slot.slotStatus() & LnConstants.LOCOSTAT_MASK) != LnConstants.LOCO_FREE) {
123                numLocos++;
124            }
125        }
126        
127        if (numLocos > _maxNumLocos) {
128            _maxNumLocos = numLocos;
129            ThreadingUtil.runOnGUI(() -> {
130                _numEnginesField.setText(Integer.toString(_maxNumLocos));
131                _textField.setText(Integer.toString(_maxNumLocos));
132            });
133        }
134    }
135    
136    private void releaseThrottles() {
137        for (int i=1; i < 120; i++) {
138            LocoNetSlot slot = _memo.getSlotManager().slot(i);
139            if ((slot.slotStatus() & LnConstants.LOCOSTAT_MASK) != LnConstants.LOCO_FREE) {
140                _memo.getLnTrafficController().sendLocoNetMessage(slot.writeStatus(LnConstants.LOCO_FREE));
141//                _memo.getLnTrafficController().sendLocoNetMessage(slot.releaseSlot());
142            }
143        }
144    }
145    
146    @Override
147    public void notifyThrottleFound(DccThrottle t) {
148//        System.out.format("Throttle found: %d%n", t.getLocoAddress().getNumber());
149        updateNumLocos();
150        ThreadingUtil.runOnGUI(() -> {
151            _status.setText("Throttle was added");
152        });
153        if (!_abort && (t.getLocoAddress().getNumber() < NUM_LOCO_TO_REQUEST)) {
154            ThreadingUtil.runOnGUIDelayed(() -> {
155                requestThrottle(t.getLocoAddress().getNumber()+1);
156            }, 200);
157//            ThreadingUtil.runOnGUIEventually(() -> {
158//                requestThrottle(t.getLocoAddress().getNumber()+1);
159//            });
160        }
161    }
162
163    @Override
164    public void notifyFailedThrottleRequest(LocoAddress address, String reason) {
165//        System.out.format("Throttle failed%n");
166        ThreadingUtil.runOnGUI(() -> {
167            _status.setText(reason);
168        });
169        if (!_abort && (address.getNumber() < NUM_LOCO_TO_REQUEST)) {
170            ThreadingUtil.runOnGUIDelayed(() -> {
171                requestThrottle(address.getNumber()+1);
172            }, 200);
173//            ThreadingUtil.runOnGUIEventually(() -> {
174//                requestThrottle(address.getNumber()+1);
175//            });
176        }
177    }
178
179    @Override
180    public void notifyDecisionRequired(LocoAddress address, DecisionType question) {
181//        System.out.format("Decision required%n");
182//        throw new UnsupportedOperationException("Not supported.");
183    }
184
185    @Override
186    public void notifyChangedSlot(LocoNetSlot s) {
187//        System.out.format("notifyChangedSlot: %d%n", s.getSlot());
188        
189        // Try to free slot
190        if (_freeSlots
191                && (s.getSlot() != 0)
192                && (s.slotStatus() != LnConstants.LOCO_FREE)
193                && (s.slotStatus() != LnConstants.LOCO_COMMON)) {
194//            System.out.format("Send message: %s%n", s.releaseSlot().toMonitorString());
195            _memo.getLnTrafficController().sendLocoNetMessage(s.releaseSlot());
196        }
197    }
198    
199}