001package jmri.jmrit.logixng.actions;
002
003import java.beans.PropertyChangeEvent;
004import java.beans.PropertyChangeListener;
005import java.util.*;
006
007import jmri.*;
008import jmri.Block;
009import jmri.Sensor;
010import jmri.jmrit.display.layoutEditor.LayoutBlock;
011import jmri.jmrit.display.layoutEditor.LayoutBlockManager;
012import jmri.jmrit.logixng.*;
013import jmri.jmrit.logixng.util.*;
014import jmri.jmrit.logixng.util.parser.*;
015import jmri.util.ThreadingUtil;
016
017/**
018 * This action triggers a block.
019 *
020 * @author Daniel Bergqvist Copyright 2021
021 * @author Dave Sand Copyright 2021
022 */
023public class ActionBlock extends AbstractDigitalAction
024        implements PropertyChangeListener {
025
026    private final LogixNG_SelectNamedBean<Block> _selectNamedBean =
027            new LogixNG_SelectNamedBean<>(
028                    this, Block.class, InstanceManager.getDefault(BlockManager.class), this);
029
030    private final LogixNG_SelectEnum<DirectOperation> _selectEnum =
031            new LogixNG_SelectEnum<>(this, DirectOperation.values(), DirectOperation.SetOccupied, this);
032
033    private final LogixNG_SelectString _selectBlockValue =
034            new LogixNG_SelectString(this, this);
035
036
037    public ActionBlock(String sys, String user)
038            throws BadUserNameException, BadSystemNameException {
039        super(sys, user);
040    }
041
042    @Override
043    public Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) throws ParserException {
044        DigitalActionManager manager = InstanceManager.getDefault(DigitalActionManager.class);
045        String sysName = systemNames.get(getSystemName());
046        String userName = userNames.get(getSystemName());
047        if (sysName == null) sysName = manager.getAutoSystemName();
048        ActionBlock copy = new ActionBlock(sysName, userName);
049        copy.setComment(getComment());
050        _selectNamedBean.copy(copy._selectNamedBean);
051        _selectEnum.copy(copy._selectEnum);
052        _selectBlockValue.copy(copy._selectBlockValue);
053        return manager.registerAction(copy);
054    }
055
056    public LogixNG_SelectNamedBean<Block> getSelectNamedBean() {
057        return _selectNamedBean;
058    }
059
060    public LogixNG_SelectEnum<DirectOperation> getSelectEnum() {
061        return _selectEnum;
062    }
063
064    public LogixNG_SelectString getSelectBlockValue() {
065        return _selectBlockValue;
066    }
067
068    /** {@inheritDoc} */
069    @Override
070    public Category getCategory() {
071        return Category.ITEM;
072    }
073
074    /** {@inheritDoc} */
075    @Override
076    public void execute() throws JmriException {
077        ConditionalNG conditionalNG = getConditionalNG();
078
079        Block block = _selectNamedBean.evaluateNamedBean(conditionalNG);
080
081        if (block == null) {
082            return;
083        }
084
085        DirectOperation oper = _selectEnum.evaluateEnum(getConditionalNG());
086
087        // Variables used in lambda must be effectively final
088        DirectOperation theOper = oper;
089
090        ThreadingUtil.runOnLayoutWithJmriException(() -> {
091            Sensor sensor;
092            LayoutBlock lblk;
093
094            switch (theOper) {
095                case SetOccupied:
096                    sensor = block.getSensor();
097                    if (sensor != null) {
098                        try {
099                            sensor.setKnownState(Sensor.ACTIVE);
100                        } catch (JmriException ex) {
101                            log.debug("Exception setting sensor active");
102                        }
103                    } else {
104                        throw new JmriException(Bundle.getMessage("ActionBlock_ErrorSensor", block.getDisplayName()));
105                    }
106                    break;
107                case SetNotOccupied:
108                    sensor = block.getSensor();
109                    if (sensor != null) {
110                        try {
111                            sensor.setKnownState(Sensor.INACTIVE);
112                        } catch (JmriException ex) {
113                            log.debug("Exception setting sensor inactive");
114                        }
115                    } else {
116                        throw new JmriException(Bundle.getMessage("ActionBlock_ErrorSensor", block.getDisplayName()));
117                    }
118                    break;
119                case SetAltColorOn:
120                    lblk = InstanceManager.getDefault(LayoutBlockManager.class).getLayoutBlock(block);
121                    if (lblk != null) {
122                        lblk.setUseExtraColor(true);
123                    } else {
124                        throw new JmriException(Bundle.getMessage("ActionBlock_ErrorLayoutBlock", block.getDisplayName()));
125                    }
126                    break;
127                case SetAltColorOff:
128                    lblk = InstanceManager.getDefault(LayoutBlockManager.class).getLayoutBlock(block);
129                    if (lblk != null) {
130                        lblk.setUseExtraColor(false);
131                    } else {
132                        throw new JmriException(Bundle.getMessage("ActionBlock_ErrorLayoutBlock", block.getDisplayName()));
133                    }
134                    break;
135                case SetNullValue:
136                    block.setValue(null);
137                    break;
138                case SetValue:
139                    block.setValue(_selectBlockValue.evaluateValue(conditionalNG));
140                    break;
141                default:
142                    throw new IllegalArgumentException("invalid oper state: " + theOper.name());
143            }
144        });
145    }
146
147    @Override
148    public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException {
149        throw new UnsupportedOperationException("Not supported.");
150    }
151
152    @Override
153    public int getChildCount() {
154        return 0;
155    }
156
157    @Override
158    public String getShortDescription(Locale locale) {
159        return Bundle.getMessage(locale, "ActionBlock_Short");
160    }
161
162    @Override
163    public String getLongDescription(Locale locale) {
164        String namedBean = _selectNamedBean.getDescription(locale);
165        String state = _selectEnum.getDescription(locale);
166
167        if (_selectEnum.isDirectAddressing()) {
168            if (_selectEnum.getEnum() == DirectOperation.SetValue) {
169                String bundleKey = "ActionBlock_Long_Value";
170                return Bundle.getMessage(locale, bundleKey, namedBean, _selectBlockValue.getDescription(locale));
171            }
172        }
173
174        return Bundle.getMessage(locale, "ActionBlock_Long", namedBean, state);
175    }
176
177    /** {@inheritDoc} */
178    @Override
179    public void setup() {
180        // Do nothing
181    }
182
183    /** {@inheritDoc} */
184    @Override
185    public void registerListenersForThisClass() {
186        _selectNamedBean.registerListeners();
187        _selectEnum.registerListeners();
188        _selectBlockValue.registerListeners();
189    }
190
191    /** {@inheritDoc} */
192    @Override
193    public void unregisterListenersForThisClass() {
194        _selectNamedBean.unregisterListeners();
195        _selectEnum.unregisterListeners();
196        _selectBlockValue.unregisterListeners();
197    }
198
199    /** {@inheritDoc} */
200    @Override
201    public void disposeMe() {
202    }
203
204    public enum DirectOperation {
205        SetOccupied(Bundle.getMessage("ActionBlock_SetOccupied")),
206        SetNotOccupied(Bundle.getMessage("ActionBlock_SetNotOccupied")),
207        SetAltColorOn(Bundle.getMessage("ActionBlock_SetAltColorOn")),
208        SetAltColorOff(Bundle.getMessage("ActionBlock_SetAltColorOff")),
209        SetNullValue(Bundle.getMessage("ActionBlock_SetNullValue")),
210        SetValue(Bundle.getMessage("ActionBlock_SetValue"));
211
212        private final String _text;
213
214        private DirectOperation(String text) {
215            this._text = text;
216        }
217
218        @Override
219        public String toString() {
220            return _text;
221        }
222
223    }
224
225    /** {@inheritDoc} */
226    @Override
227    public void getUsageDetail(int level, NamedBean bean, List<NamedBeanUsageReport> report, NamedBean cdl) {
228        _selectNamedBean.getUsageDetail(level, bean, report, cdl, this, LogixNG_SelectNamedBean.Type.Action);
229    }
230
231    /** {@inheritDoc} */
232    @Override
233    public void propertyChange(PropertyChangeEvent evt) {
234        getConditionalNG().execute();
235    }
236
237    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ActionBlock.class);
238
239}