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