001package jmri.jmrit.display.logixng.swing;
002
003import java.awt.event.ActionEvent;
004import java.util.*;
005
006import javax.annotation.CheckForNull;
007import javax.annotation.Nonnull;
008import javax.swing.*;
009
010import jmri.InstanceManager;
011import jmri.jmrit.display.EditorManager;
012import jmri.jmrit.display.layoutEditor.LayoutEditor;
013import jmri.jmrit.display.layoutEditor.LayoutTurnout;
014import jmri.jmrit.display.logixng.ActionLayoutTurnout;
015import jmri.jmrit.display.logixng.ActionLayoutTurnout.Operation;
016import jmri.jmrit.logixng.*;
017import jmri.jmrit.logixng.actions.swing.AbstractDigitalActionSwing;
018import jmri.jmrit.logixng.swing.SwingConfiguratorInterface;
019import jmri.jmrit.logixng.util.parser.ParserException;
020import jmri.util.swing.JComboBoxUtil;
021
022/**
023 * Configures an ActionLayoutTurnout object with a Swing JPanel.
024 *
025 * @author Daniel Bergqvist Copyright (C) 2022
026 */
027public class ActionLayoutTurnoutSwing extends AbstractDigitalActionSwing {
028
029    private String _selectedLayoutEditor;
030
031    private JComboBox<EditorItem> _layoutEditorComboBox;
032    private JTabbedPane _tabbedPaneLayoutTurnout;
033    private JComboBox<Turnout> _layoutTurnoutComboBox;
034    private JPanel _panelLayoutTurnoutDirect;
035    private JPanel _panelLayoutTurnoutReference;
036    private JPanel _panelLayoutTurnoutLocalVariable;
037    private JPanel _panelLayoutTurnoutFormula;
038    private JTextField _layoutTurnoutReferenceTextField;
039    private JTextField _layoutTurnoutLocalVariableTextField;
040    private JTextField _layoutTurnoutFormulaTextField;
041
042    private JTabbedPane _tabbedPaneLayoutTurnoutState;
043    private JComboBox<Operation> _isControllingComboBox;
044    private JPanel _panelLayoutTurnoutStateDirect;
045    private JPanel _panelLayoutTurnoutStateReference;
046    private JPanel _panelLayoutTurnoutStateLocalVariable;
047    private JPanel _panelLayoutTurnoutStateFormula;
048    private JTextField _layoutTurnoutStateReferenceTextField;
049    private JTextField _layoutTurnoutStateLocalVariableTextField;
050    private JTextField _layoutTurnoutStateFormulaTextField;
051
052
053    @Override
054    protected void createPanel(@CheckForNull Base object, @Nonnull JPanel buttonPanel) {
055        ActionLayoutTurnout action = (ActionLayoutTurnout)object;
056
057        panel = new JPanel();
058
059        _selectedLayoutEditor = action != null ? action.getLayoutEditorName() : null;
060
061        _layoutEditorComboBox = new JComboBox<>();
062        JComboBoxUtil.setupComboBoxMaxRows(_layoutEditorComboBox);
063        for (LayoutEditor layoutEditor : jmri.InstanceManager.getDefault(EditorManager.class).getAll(LayoutEditor.class)) {
064            EditorItem item = new EditorItem(layoutEditor);
065            _layoutEditorComboBox.addItem(item);
066            if (layoutEditor.getName().equals(_selectedLayoutEditor)) _layoutEditorComboBox.setSelectedItem(item);
067        }
068        _layoutEditorComboBox.addActionListener(this::updateLayoutTurnouts);
069
070        _tabbedPaneLayoutTurnout = new JTabbedPane();
071        _panelLayoutTurnoutDirect = new javax.swing.JPanel();
072        _panelLayoutTurnoutReference = new javax.swing.JPanel();
073        _panelLayoutTurnoutLocalVariable = new javax.swing.JPanel();
074        _panelLayoutTurnoutFormula = new javax.swing.JPanel();
075
076        _tabbedPaneLayoutTurnout.addTab(NamedBeanAddressing.Direct.toString(), _panelLayoutTurnoutDirect);
077        _tabbedPaneLayoutTurnout.addTab(NamedBeanAddressing.Reference.toString(), _panelLayoutTurnoutReference);
078        _tabbedPaneLayoutTurnout.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelLayoutTurnoutLocalVariable);
079        _tabbedPaneLayoutTurnout.addTab(NamedBeanAddressing.Formula.toString(), _panelLayoutTurnoutFormula);
080
081        _layoutTurnoutComboBox = new JComboBox<>();
082        JComboBoxUtil.setupComboBoxMaxRows(_layoutTurnoutComboBox);
083        updateLayoutTurnouts(null);
084        _panelLayoutTurnoutDirect.add(_layoutTurnoutComboBox);
085
086        _layoutTurnoutReferenceTextField = new JTextField();
087        _layoutTurnoutReferenceTextField.setColumns(30);
088        _panelLayoutTurnoutReference.add(_layoutTurnoutReferenceTextField);
089
090        _layoutTurnoutLocalVariableTextField = new JTextField();
091        _layoutTurnoutLocalVariableTextField.setColumns(30);
092        _panelLayoutTurnoutLocalVariable.add(_layoutTurnoutLocalVariableTextField);
093
094        _layoutTurnoutFormulaTextField = new JTextField();
095        _layoutTurnoutFormulaTextField.setColumns(30);
096        _panelLayoutTurnoutFormula.add(_layoutTurnoutFormulaTextField);
097
098
099        _tabbedPaneLayoutTurnoutState = new JTabbedPane();
100        _panelLayoutTurnoutStateDirect = new javax.swing.JPanel();
101        _panelLayoutTurnoutStateReference = new javax.swing.JPanel();
102        _panelLayoutTurnoutStateLocalVariable = new javax.swing.JPanel();
103        _panelLayoutTurnoutStateFormula = new javax.swing.JPanel();
104
105        _tabbedPaneLayoutTurnoutState.addTab(NamedBeanAddressing.Direct.toString(), _panelLayoutTurnoutStateDirect);
106        _tabbedPaneLayoutTurnoutState.addTab(NamedBeanAddressing.Reference.toString(), _panelLayoutTurnoutStateReference);
107        _tabbedPaneLayoutTurnoutState.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelLayoutTurnoutStateLocalVariable);
108        _tabbedPaneLayoutTurnoutState.addTab(NamedBeanAddressing.Formula.toString(), _panelLayoutTurnoutStateFormula);
109
110        _isControllingComboBox = new JComboBox<>();
111        for (Operation e : Operation.values()) {
112            _isControllingComboBox.addItem(e);
113        }
114        JComboBoxUtil.setupComboBoxMaxRows(_isControllingComboBox);
115
116        _panelLayoutTurnoutStateDirect.add(_isControllingComboBox);
117
118        _layoutTurnoutStateReferenceTextField = new JTextField();
119        _layoutTurnoutStateReferenceTextField.setColumns(30);
120        _panelLayoutTurnoutStateReference.add(_layoutTurnoutStateReferenceTextField);
121
122        _layoutTurnoutStateLocalVariableTextField = new JTextField();
123        _layoutTurnoutStateLocalVariableTextField.setColumns(30);
124        _panelLayoutTurnoutStateLocalVariable.add(_layoutTurnoutStateLocalVariableTextField);
125
126        _layoutTurnoutStateFormulaTextField = new JTextField();
127        _layoutTurnoutStateFormulaTextField.setColumns(30);
128        _panelLayoutTurnoutStateFormula.add(_layoutTurnoutStateFormulaTextField);
129
130
131        if (action != null) {
132            switch (action.getAddressing()) {
133                case Direct: _tabbedPaneLayoutTurnout.setSelectedComponent(_panelLayoutTurnoutDirect); break;
134                case Reference: _tabbedPaneLayoutTurnout.setSelectedComponent(_panelLayoutTurnoutReference); break;
135                case LocalVariable: _tabbedPaneLayoutTurnout.setSelectedComponent(_panelLayoutTurnoutLocalVariable); break;
136                case Formula: _tabbedPaneLayoutTurnout.setSelectedComponent(_panelLayoutTurnoutFormula); break;
137                default: throw new IllegalArgumentException("invalid _addressing state: " + action.getAddressing().name());
138            }
139            if (action.getLayoutTurnout() != null) {
140                _layoutTurnoutComboBox.setSelectedItem(action.getLayoutTurnout());
141            }
142            _layoutTurnoutReferenceTextField.setText(action.getReference());
143            _layoutTurnoutLocalVariableTextField.setText(action.getLocalVariable());
144            _layoutTurnoutFormulaTextField.setText(action.getFormula());
145
146            switch (action.getStateAddressing()) {
147                case Direct: _tabbedPaneLayoutTurnoutState.setSelectedComponent(_panelLayoutTurnoutStateDirect); break;
148                case Reference: _tabbedPaneLayoutTurnoutState.setSelectedComponent(_panelLayoutTurnoutStateReference); break;
149                case LocalVariable: _tabbedPaneLayoutTurnoutState.setSelectedComponent(_panelLayoutTurnoutStateLocalVariable); break;
150                case Formula: _tabbedPaneLayoutTurnoutState.setSelectedComponent(_panelLayoutTurnoutStateFormula); break;
151                default: throw new IllegalArgumentException("invalid _addressing state: " + action.getAddressing().name());
152            }
153            _isControllingComboBox.setSelectedItem(action.getOperation());
154            _layoutTurnoutStateReferenceTextField.setText(action.getStateReference());
155            _layoutTurnoutStateLocalVariableTextField.setText(action.getStateLocalVariable());
156            _layoutTurnoutStateFormulaTextField.setText(action.getStateFormula());
157        }
158
159        JComponent[] components = new JComponent[]{
160            _layoutEditorComboBox,
161            _tabbedPaneLayoutTurnout,
162            _tabbedPaneLayoutTurnoutState};
163
164        List<JComponent> componentList = SwingConfiguratorInterface.parseMessage(
165                Bundle.getMessage("ActionLayoutTurnout_Components"), components);
166
167        for (JComponent c : componentList) panel.add(c);
168    }
169
170    private void updateLayoutTurnouts(ActionEvent e) {
171        _layoutTurnoutComboBox.removeAllItems();
172        if (_layoutEditorComboBox.getSelectedIndex() == -1) return;
173
174        EditorItem item = _layoutEditorComboBox.getItemAt(_layoutEditorComboBox.getSelectedIndex());
175        List<LayoutTurnout> list = new ArrayList<>();
176        for (LayoutTurnout layoutTurnout : item._layoutEditor.getLayoutTurnouts()) {
177            if (!layoutTurnout.getTurnoutName().isBlank()) {
178                list.add(layoutTurnout);
179            }
180        }
181        Collections.sort(list, (o1,o2) -> o1.getTurnoutName().compareTo(o2.getTurnoutName()));
182        for (LayoutTurnout lt : list) {
183            _layoutTurnoutComboBox.addItem(new Turnout(lt));
184        }
185    }
186
187    /** {@inheritDoc} */
188    @Override
189    public boolean validate(@Nonnull List<String> errorMessages) {
190        // Create a temporary action to test formula
191        ActionLayoutTurnout action = new ActionLayoutTurnout("IQDA1", null);
192
193        try {
194            if (_tabbedPaneLayoutTurnout.getSelectedComponent() == _panelLayoutTurnoutReference) {
195                action.setReference(_layoutTurnoutReferenceTextField.getText());
196            }
197        } catch (IllegalArgumentException e) {
198            errorMessages.add(e.getMessage());
199            return false;
200        }
201
202        try {
203            if (_tabbedPaneLayoutTurnoutState.getSelectedComponent() == _panelLayoutTurnoutStateReference) {
204                action.setStateReference(_layoutTurnoutStateReferenceTextField.getText());
205            }
206        } catch (IllegalArgumentException e) {
207            errorMessages.add(e.getMessage());
208            return false;
209        }
210
211        try {
212            action.setFormula(_layoutTurnoutFormulaTextField.getText());
213            if (_tabbedPaneLayoutTurnout.getSelectedComponent() == _panelLayoutTurnoutDirect) {
214                action.setAddressing(NamedBeanAddressing.Direct);
215            } else if (_tabbedPaneLayoutTurnout.getSelectedComponent() == _panelLayoutTurnoutReference) {
216                action.setAddressing(NamedBeanAddressing.Reference);
217            } else if (_tabbedPaneLayoutTurnout.getSelectedComponent() == _panelLayoutTurnoutLocalVariable) {
218                action.setAddressing(NamedBeanAddressing.LocalVariable);
219            } else if (_tabbedPaneLayoutTurnout.getSelectedComponent() == _panelLayoutTurnoutFormula) {
220                action.setAddressing(NamedBeanAddressing.Formula);
221            } else {
222                throw new IllegalArgumentException("_tabbedPane has unknown selection");
223            }
224        } catch (ParserException e) {
225            errorMessages.add("Cannot parse formula: " + e.getMessage());
226        }
227        return true;
228    }
229
230    /** {@inheritDoc} */
231    @Override
232    public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName) {
233        ActionLayoutTurnout action = new ActionLayoutTurnout(systemName, userName);
234        updateObject(action);
235        return InstanceManager.getDefault(DigitalActionManager.class).registerAction(action);
236    }
237
238    /** {@inheritDoc} */
239    @Override
240    public void updateObject(@Nonnull Base object) {
241        if (! (object instanceof ActionLayoutTurnout)) {
242            throw new IllegalArgumentException("object must be an ActionLayoutTurnout but is a: "+object.getClass().getName());
243        }
244        ActionLayoutTurnout action = (ActionLayoutTurnout)object;
245        if (_layoutEditorComboBox.getSelectedIndex() != -1) {
246            action.setLayoutEditor(_layoutEditorComboBox.getItemAt(_layoutEditorComboBox.getSelectedIndex())._layoutEditor.getName());
247        }
248        if (_tabbedPaneLayoutTurnout.getSelectedComponent() == _panelLayoutTurnoutDirect) {
249            if (_layoutTurnoutComboBox.getSelectedIndex() != -1) {
250                action.setLayoutTurnout(_layoutTurnoutComboBox.getItemAt(_layoutTurnoutComboBox.getSelectedIndex())._lt);
251            } else {
252                action.setLayoutTurnout((LayoutTurnout)null);
253            }
254        }
255        try {
256            if (_tabbedPaneLayoutTurnout.getSelectedComponent() == _panelLayoutTurnoutDirect) {
257                action.setAddressing(NamedBeanAddressing.Direct);
258            } else if (_tabbedPaneLayoutTurnout.getSelectedComponent() == _panelLayoutTurnoutReference) {
259                action.setAddressing(NamedBeanAddressing.Reference);
260                action.setReference(_layoutTurnoutReferenceTextField.getText());
261            } else if (_tabbedPaneLayoutTurnout.getSelectedComponent() == _panelLayoutTurnoutLocalVariable) {
262                action.setAddressing(NamedBeanAddressing.LocalVariable);
263                action.setLocalVariable(_layoutTurnoutLocalVariableTextField.getText());
264            } else if (_tabbedPaneLayoutTurnout.getSelectedComponent() == _panelLayoutTurnoutFormula) {
265                action.setAddressing(NamedBeanAddressing.Formula);
266                action.setFormula(_layoutTurnoutFormulaTextField.getText());
267            } else {
268                throw new IllegalArgumentException("_tabbedPaneLayoutTurnout has unknown selection");
269            }
270
271            if (_tabbedPaneLayoutTurnoutState.getSelectedComponent() == _panelLayoutTurnoutStateDirect) {
272                action.setStateAddressing(NamedBeanAddressing.Direct);
273                action.setOperation(_isControllingComboBox.getItemAt(_isControllingComboBox.getSelectedIndex()));
274            } else if (_tabbedPaneLayoutTurnoutState.getSelectedComponent() == _panelLayoutTurnoutStateReference) {
275                action.setStateAddressing(NamedBeanAddressing.Reference);
276                action.setStateReference(_layoutTurnoutStateReferenceTextField.getText());
277            } else if (_tabbedPaneLayoutTurnoutState.getSelectedComponent() == _panelLayoutTurnoutStateLocalVariable) {
278                action.setStateAddressing(NamedBeanAddressing.LocalVariable);
279                action.setStateLocalVariable(_layoutTurnoutStateLocalVariableTextField.getText());
280            } else if (_tabbedPaneLayoutTurnoutState.getSelectedComponent() == _panelLayoutTurnoutStateFormula) {
281                action.setStateAddressing(NamedBeanAddressing.Formula);
282                action.setStateFormula(_layoutTurnoutStateFormulaTextField.getText());
283            } else {
284                throw new IllegalArgumentException("_tabbedPaneLayoutTurnoutState has unknown selection");
285            }
286        } catch (ParserException e) {
287            throw new RuntimeException("ParserException: "+e.getMessage(), e);
288        }
289    }
290
291    /** {@inheritDoc} */
292    @Override
293    public String toString() {
294        return Bundle.getMessage("ActionLayoutTurnout_Short");
295    }
296
297    @Override
298    public void dispose() {
299        // Do nothing
300    }
301
302
303    private static class EditorItem {
304
305        private final LayoutEditor _layoutEditor;
306
307        public EditorItem(LayoutEditor layoutEditor) {
308            this._layoutEditor = layoutEditor;
309        }
310
311        @Override
312        public String toString() {
313            return _layoutEditor.getName();
314        }
315    }
316
317
318    private static class Turnout {
319        private final LayoutTurnout _lt;
320
321        public Turnout(LayoutTurnout turnout) {
322            _lt = turnout;
323        }
324
325        @Override
326        public String toString() {
327            return _lt.getTurnoutName();
328        }
329    }
330
331//    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ActionLayoutTurnoutSwing.class);
332
333}