001package jmri.jmrit.logixng.actions.swing;
002
003import java.util.List;
004
005import javax.annotation.CheckForNull;
006import javax.annotation.Nonnull;
007import javax.swing.*;
008
009import jmri.*;
010import jmri.jmrit.logixng.*;
011import jmri.jmrit.logixng.actions.ForEachWithDelay;
012import jmri.jmrit.logixng.actions.CommonManager;
013import jmri.jmrit.logixng.actions.ForEachWithDelay.UserSpecifiedSource;
014import jmri.jmrit.logixng.util.parser.ParserException;
015import jmri.jmrit.logixng.util.swing.LogixNG_SelectNamedBeanSwing;
016import jmri.jmrit.logixng.util.swing.LogixNG_SelectStringSwing;
017import jmri.util.TimerUnit;
018import jmri.util.swing.JComboBoxUtil;
019
020/**
021 * Configures an ForEachWithDelay object with a Swing JPanel.
022 *
023 * @author Daniel Bergqvist Copyright 2025
024 */
025public class ForEachWithDelaySwing extends AbstractDigitalActionSwing {
026
027    private LogixNG_SelectStringSwing _selectVariableSwing;
028    private LogixNG_SelectNamedBeanSwing<Memory> _selectMemorySwing;
029
030    private JTabbedPane _commonOrUserSpecifiedPane;
031    private JPanel _commonPanel;
032    private JComboBox<CommonManager> _commonManagersComboBox;
033
034    private JTabbedPane _tabbedPaneUserSpecifiedSource;
035    JPanel _tabbedPaneMemoryBean;
036    JPanel _tabbedPaneVariable;
037    private JPanel _calculateFormula;
038    private JTextField _calculateFormulaTextField;
039
040    private JTextField _localVariable;
041
042    private JFormattedTextField _timerDelay;
043    private JComboBox<TimerUnit> _unitComboBox;
044    private JCheckBox _resetIfAlreadyStarted;
045    private JCheckBox _useIndividualTimers;
046
047
048    @Override
049    protected void createPanel(@CheckForNull Base object, @Nonnull JPanel buttonPanel) {
050        if ((object != null) && !(object instanceof ForEachWithDelay)) {
051            throw new IllegalArgumentException("object must be an ForEachWithDelay but is a: "+object.getClass().getName());
052        }
053
054        ForEachWithDelay action = (ForEachWithDelay)object;
055
056        _selectVariableSwing = new LogixNG_SelectStringSwing(getJDialog(), this);
057
058        _selectMemorySwing = new LogixNG_SelectNamedBeanSwing<>(
059                InstanceManager.getDefault(MemoryManager.class), getJDialog(), this);
060
061        panel = new JPanel();
062        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
063
064        if (action != null) {
065            _tabbedPaneMemoryBean = _selectMemorySwing.createPanel(action.getSelectMemoryNamedBean());
066            _tabbedPaneVariable = _selectVariableSwing.createPanel(action.getSelectVariable());
067        } else {
068            _tabbedPaneMemoryBean = _selectMemorySwing.createPanel(null);
069            _tabbedPaneVariable = _selectVariableSwing.createPanel(null);
070        }
071
072        _commonOrUserSpecifiedPane = new JTabbedPane();
073
074        _commonPanel = new JPanel();
075        _commonOrUserSpecifiedPane.addTab(Bundle.getMessage("ForEachWithDelaySwing_Common"), _commonPanel);
076        _commonManagersComboBox = new JComboBox<>();
077        for (CommonManager commonManager : CommonManager.values()) {
078            _commonManagersComboBox.addItem(commonManager);
079        }
080        JComboBoxUtil.setupComboBoxMaxRows(_commonManagersComboBox);
081
082        _commonPanel.add(_commonManagersComboBox);
083
084
085        _tabbedPaneUserSpecifiedSource = new JTabbedPane();
086        _commonOrUserSpecifiedPane.addTab(Bundle.getMessage("ForEachWithDelaySwing_UserSpecified"), _tabbedPaneUserSpecifiedSource);
087
088        _calculateFormula = new JPanel();
089
090        _tabbedPaneUserSpecifiedSource.addTab(UserSpecifiedSource.Memory.toString(), _tabbedPaneMemoryBean);
091        _tabbedPaneUserSpecifiedSource.addTab(UserSpecifiedSource.Variable.toString(), _tabbedPaneVariable);
092        _tabbedPaneUserSpecifiedSource.addTab(UserSpecifiedSource.Formula.toString(), _calculateFormula);
093
094        _calculateFormulaTextField = new JTextField(30);
095        _calculateFormula.add(_calculateFormulaTextField);
096
097        JPanel localVariablePanel = new JPanel();
098        localVariablePanel.add(new JLabel(Bundle.getMessage("ForEachWithDelaySwing_LocalVariable")));
099        _localVariable = new JTextField(20);
100        localVariablePanel.add(_localVariable);
101        panel.add(localVariablePanel);
102
103        panel.add(_commonOrUserSpecifiedPane);
104        panel.add(localVariablePanel);
105
106        JPanel panelDelay = new javax.swing.JPanel();
107        panelDelay.add(new JLabel(Bundle.getMessage("ForEachWithDelaySwing_Time")));
108        _timerDelay = new JFormattedTextField("0");
109        _timerDelay.setColumns(7);
110        panelDelay.add(_timerDelay);
111        panel.add(panelDelay);
112
113        JPanel unitPanel = new JPanel();
114        unitPanel.add(new JLabel(Bundle.getMessage("ForEachWithDelaySwing_Unit")));
115        panel.add(unitPanel);
116
117        _unitComboBox = new JComboBox<>();
118        for (TimerUnit u : TimerUnit.values()) _unitComboBox.addItem(u);
119        JComboBoxUtil.setupComboBoxMaxRows(_unitComboBox);
120        if (action != null) _unitComboBox.setSelectedItem(action.getUnit());
121        unitPanel.add(_unitComboBox);
122        panel.add(unitPanel);
123
124        _resetIfAlreadyStarted = new JCheckBox(Bundle.getMessage("ForEachWithDelaySwing_ResetIfAlreadyStarted"));
125        panel.add(_resetIfAlreadyStarted);
126
127        _useIndividualTimers = new JCheckBox(Bundle.getMessage("ForEachWithDelaySwing_UseIndividualTimers"));
128        _useIndividualTimers.addActionListener((evt)->{
129            if (_useIndividualTimers.isSelected()) {
130                _resetIfAlreadyStarted.setEnabled(false);
131                _resetIfAlreadyStarted.setSelected(false);
132            } else {
133                _resetIfAlreadyStarted.setEnabled(true);
134            }
135        });
136        panel.add(_useIndividualTimers);
137
138
139        if (action != null) {
140            if (!action.isUseCommonSource()) {
141                _commonOrUserSpecifiedPane.setSelectedComponent(_tabbedPaneUserSpecifiedSource);
142            }
143            _commonManagersComboBox.setSelectedItem(action.getCommonManager());
144
145            switch (action.getUserSpecifiedSource()) {
146                case Memory: _tabbedPaneUserSpecifiedSource.setSelectedComponent(_tabbedPaneMemoryBean); break;
147                case Variable: _tabbedPaneUserSpecifiedSource.setSelectedComponent(_tabbedPaneVariable); break;
148                case Formula: _tabbedPaneUserSpecifiedSource.setSelectedComponent(_calculateFormula); break;
149                default: throw new IllegalArgumentException("invalid _addressing state: " + action.getUserSpecifiedSource().name());
150            }
151            _calculateFormulaTextField.setText(action.getFormula());
152            _timerDelay.setText(Integer.toString(action.getDelay()));
153            _localVariable.setText(action.getLocalVariableName());
154            _resetIfAlreadyStarted.setSelected(action.getResetIfAlreadyStarted());
155            _useIndividualTimers.setSelected(action.getUseIndividualTimers());
156            _resetIfAlreadyStarted.setEnabled(!action.getUseIndividualTimers());
157        }
158    }
159
160    /** {@inheritDoc} */
161    @Override
162    public boolean validate(@Nonnull List<String> errorMessages) {
163        // Create a temporary action to test formula
164        ForEachWithDelay action = new ForEachWithDelay("IQDA1", null);
165
166        if (_commonOrUserSpecifiedPane.getSelectedComponent() == _tabbedPaneUserSpecifiedSource) {
167            // If using the Memory tab, validate the memory variable selection.
168            if (_tabbedPaneUserSpecifiedSource.getSelectedComponent() == _tabbedPaneMemoryBean) {
169                _selectMemorySwing.validate(action.getSelectMemoryNamedBean(), errorMessages);
170            }
171
172            // If using the Variable tab, validate the memory variable selection.
173            if (_tabbedPaneUserSpecifiedSource.getSelectedComponent() == _tabbedPaneVariable) {
174                _selectVariableSwing.validate(action.getSelectVariable(), errorMessages);
175            }
176
177            if (_tabbedPaneUserSpecifiedSource.getSelectedComponent() == _calculateFormula) {
178                try {
179                    action.setUserSpecifiedSource(UserSpecifiedSource.Formula);
180                    action.setFormula(_calculateFormulaTextField.getText());
181                } catch (ParserException e) {
182                    errorMessages.add(e.getMessage());
183                }
184            }
185        }
186
187        try {
188            action.setDelay(Integer.parseInt(_timerDelay.getText()));
189        } catch (NumberFormatException e) {
190            errorMessages.add(e.getLocalizedMessage());
191        }
192
193        return errorMessages.isEmpty();
194    }
195
196    /** {@inheritDoc} */
197    @Override
198    public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName) {
199        ForEachWithDelay action = new ForEachWithDelay(systemName, userName);
200        updateObject(action);
201        return InstanceManager.getDefault(DigitalActionManager.class).registerAction(action);
202    }
203
204    /** {@inheritDoc} */
205    @Override
206    public void updateObject(@Nonnull Base object) {
207        if (!(object instanceof ForEachWithDelay)) {
208            throw new IllegalArgumentException("object must be an ForEachWithDelay but is a: "+object.getClass().getName());
209        }
210
211        ForEachWithDelay action = (ForEachWithDelay)object;
212
213        try {
214            if (_commonOrUserSpecifiedPane.getSelectedComponent() == _commonPanel) {
215
216                action.setUseCommonSource(true);
217                action.setCommonManager(_commonManagersComboBox.getItemAt(
218                        _commonManagersComboBox.getSelectedIndex()));
219
220            } else if (_commonOrUserSpecifiedPane.getSelectedComponent() == _tabbedPaneUserSpecifiedSource) {
221
222                action.setUseCommonSource(false);
223
224                try {
225                    if (_tabbedPaneUserSpecifiedSource.getSelectedComponent() == _tabbedPaneMemoryBean) {
226                        action.setUserSpecifiedSource(UserSpecifiedSource.Memory);
227                        _selectMemorySwing.updateObject(action.getSelectMemoryNamedBean());
228                    } else if (_tabbedPaneUserSpecifiedSource.getSelectedComponent() == _tabbedPaneVariable) {
229                        action.setUserSpecifiedSource(UserSpecifiedSource.Variable);
230                        _selectVariableSwing.updateObject(action.getSelectVariable());
231                    } else if (_tabbedPaneUserSpecifiedSource.getSelectedComponent() == _calculateFormula) {
232                        action.setUserSpecifiedSource(UserSpecifiedSource.Formula);
233                        action.setFormula(_calculateFormulaTextField.getText());
234                    } else {
235                        throw new IllegalArgumentException("_tabbedPaneUserSpecifiedSource has unknown selection");
236                    }
237                } catch (ParserException e) {
238                    throw new RuntimeException("ParserException: "+e.getMessage(), e);
239                }
240
241            } else {
242                throw new IllegalArgumentException("_tabbedPaneUserSpecifiedSource has unknown selection");
243            }
244        } catch (ParserException e) {
245            throw new RuntimeException("ParserException: "+e.getMessage(), e);
246        }
247
248        action.setLocalVariableName(_localVariable.getText());
249
250        action.setDelay(Integer.parseInt(_timerDelay.getText()));
251        action.setUnit(_unitComboBox.getItemAt(_unitComboBox.getSelectedIndex()));
252        action.setResetIfAlreadyStarted(_resetIfAlreadyStarted.isSelected());
253        action.setUseIndividualTimers(_useIndividualTimers.isSelected());
254    }
255
256    /** {@inheritDoc} */
257    @Override
258    public String toString() {
259        return Bundle.getMessage("ForEachWithDelay_Short");
260    }
261
262    @Override
263    public void dispose() {
264    }
265
266//    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ForEachSwing.class);
267
268}