001package jmri.jmrit.conditional;
002
003import java.awt.event.ActionEvent;
004import java.util.List;
005
006import javax.annotation.Nonnull;
007
008import javax.swing.Box;
009import javax.swing.BoxLayout;
010import javax.swing.JComponent;
011import javax.swing.JLabel;
012import javax.swing.JPanel;
013import javax.swing.JTextField;
014
015import jmri.*;
016import jmri.util.JmriJFrame;
017
018/**
019 * Basis for ConditionalEditFrame and ConditionalCopyFrame.
020 * Holds the common features.
021 *
022 * @author Pete Cressman Copyright (C) 2020
023 */
024public class ConditionalFrame extends JmriJFrame {
025    protected ConditionalList _parent;
026    boolean _dataChanged = false;
027
028    // ------------ Current Conditional Information ------------
029    List<ConditionalVariable> _variableList;
030    List<ConditionalAction> _actionList;
031
032    Conditional.AntecedentOperator _logicType = Conditional.AntecedentOperator.ALL_AND;
033    String _antecedent;
034    boolean _trigger;
035    boolean _referenceByMemory;
036
037    // ------------------ Common window parts --------------
038    private JTextField _conditionalUserName;
039
040    static final int STRUT = 10;
041
042    // ------------------------------------------------------------------
043
044    ConditionalFrame(String title, @Nonnull Conditional conditional, ConditionalList parent) {
045        super(title, false, false);
046        _parent = parent;
047        _variableList = conditional.getCopyOfStateVariables();
048        _actionList = conditional.getCopyOfActions();
049        _logicType = conditional.getLogicType();
050        _antecedent = conditional.getAntecedentExpression();
051    }
052
053    JPanel makeTopPanel(@Nonnull Conditional conditional) {
054        JPanel panel = new JPanel();
055        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
056        JPanel panel1 = new JPanel();
057        panel1.add(new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("ColumnSystemName"))));
058        JTextField systemName =  new JTextField(30);
059        systemName.setText(conditional.getSystemName());
060        systemName.setEditable(false);
061        panel1.add(systemName);
062        panel.add(panel1);
063        JPanel panel2 = new JPanel();
064        panel2.add(new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("ColumnUserName"))));
065        _conditionalUserName = new JTextField(30);
066        panel2.add(_conditionalUserName);
067        _conditionalUserName.setText(conditional.getUserName());
068        _conditionalUserName.setToolTipText(Bundle.getMessage("ConditionalUserNameHint"));
069        panel.add(panel2);
070        return panel;
071    }
072
073    /**
074     * Create Variable and Action editing pane center part. (Utility)
075     *
076     * @param comp  Field or comboBox to include on sub pane
077     * @param label property key for label
078     * @param hint  property key for tooltip for this sub pane
079     * @return JPanel containing interface
080     */
081    JPanel makeEditPanel(@Nonnull JComponent comp, @Nonnull String label, @javax.annotation.CheckForNull String hint) {
082        JPanel panel = new JPanel();
083        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
084        JPanel p = new JPanel();
085        p.add(new JLabel(Bundle.getMessage(label)));
086        panel.add(p);
087        if (hint != null) {
088            panel.setToolTipText(Bundle.getMessage(hint));
089        }
090        comp.setMaximumSize(comp.getPreferredSize());  // override for text fields
091        panel.add(comp);
092        panel.add(Box.createVerticalGlue());
093        return panel;
094    }
095
096    /**
097     * Respond to the Update Conditional Button in the Edit Conditional window.
098     *
099     * @param e The event heard
100     * @return true if updated
101     */
102    boolean updateConditionalPressed(ActionEvent e) {
103        log.debug("updateConditionalPressed");
104        String pref = InstanceManager.getDefault(jmri.LogixManager.class).getSystemPrefix();
105        // The IX:RTXINITIALIZER keyword has a type of NONE
106        // Safely remove elements from the list  (or use array.remove) if more than 1
107        _variableList.removeIf( cvar ->
108                (cvar.getType() == Conditional.Type.NONE && !cvar.getName().equals(pref + "X:RTXINITIALIZER")));
109        // and actions
110        _actionList.removeIf(cact -> cact.getType() == Conditional.Action.NONE);
111        if (_parent.updateConditional(_conditionalUserName.getText(), _logicType, _trigger, _antecedent)) {
112            if (_dataChanged) {
113                _parent._showReminder = true;
114            }
115            return true;
116        }
117        return false;
118    }
119
120    /**
121     * Respond to the Cancel button in the Edit Conditional frame.
122     * <p>
123     * Does the cleanup from deleteConditionalPressed, updateConditionalPressed
124     * and _editConditionalFrame window closer.
125     */
126    void cancelConditionalPressed() {
127        log.debug("cancelConditionalPressed");
128        _dataChanged = false;
129        _parent.closeConditionalFrame();
130    }
131
132    boolean checkReferenceByMemory(@Nonnull String name) {
133        _referenceByMemory = false;
134        if (name.length() > 0 && name.charAt(0) == '@') {
135            String memName = name.substring(1);
136            if (!_parent.confirmIndirectMemory(memName)) {
137                return false;
138            }
139            memName = _parent.validateMemoryReference(memName);
140            if (memName == null) {
141                return false;
142            }
143            _referenceByMemory = true;
144        }
145        return true;
146    }
147
148    /**
149     * Check that a state variable is not also used as an action
150     * @param name of the state variable
151     * @param itemType item type of the state variable
152     * @return true if action is not an action of if the user OK's
153     * its use as such.
154     */
155    boolean checkIsAction(@Nonnull String name, Conditional.ItemType itemType) {
156        String actionName = null;
157        for (ConditionalAction action : _actionList) {
158            Conditional.ItemType actionType = action.getType().getItemType();
159            if (itemType == actionType) {
160                if (name.equals(action.getDeviceName())) {
161                    actionName = action.getDeviceName();
162                } else {
163                    NamedBean bean  = action.getBean();
164                    if (bean != null &&
165                        (name.equals(bean.getSystemName()) ||
166                                name.equals(bean.getUserName()))) {
167                        actionName = action.getDeviceName();
168                   }
169                }
170            }
171            if (actionName != null) {
172                return _parent.confirmActionAsVariable(actionName, name);
173            }
174        }
175        return true;
176    }
177
178    /**
179     * Check that an action is not also used as a state variable
180     * @param name of the action
181     * @param itemType item type of the action
182     * @return true if action is not a state variable of if the user OK's
183     * its use as such.
184     */
185    boolean checkIsVariable(@Nonnull String name, Conditional.ItemType itemType) {
186        String varName = null;
187        for (ConditionalVariable condVar : _variableList) {
188            Conditional.ItemType varType = condVar.getType().getItemType();
189            if (itemType == varType) {
190                if (name.equals(condVar.getName())) {
191                    varName = condVar.getName();
192                } else {
193                    NamedBean bean  = condVar.getBean();
194                    if (bean != null &&
195                        (name.equals(bean.getSystemName()) ||
196                                name.equals(bean.getUserName()))) {
197                        varName = condVar.getName();
198                   }
199                }
200            }
201            if (varName != null) {
202                return _parent.confirmActionAsVariable(name, varName);
203            }
204        }
205        return true;
206    }
207
208    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ConditionalFrame.class);
209
210}