001package jmri.implementation;
002
003import java.beans.PropertyChangeEvent;
004import java.util.ArrayList;
005import java.util.List;
006import jmri.Conditional;
007import jmri.NamedBeanHandle;
008import org.slf4j.Logger;
009import org.slf4j.LoggerFactory;
010
011/**
012 * A service base class for monitoring a bound property in one of the JMRI Named
013 * beans (Turnout, Sensor, etc). For use with properties that may have more than
014 * two states where the states are represented by numbers than can be cast to
015 * integers.
016 * <p>
017 * This file is part of JMRI.
018 * <p>
019 * JMRI is free software; you can redistribute it and/or modify it under the
020 * terms of version 2 of the GNU General Public License as published by the Free
021 * Software Foundation. See the "COPYING" file for a copy of this license.
022 * <p>
023 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY
024 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
025 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
026 *
027 * @author Pete Cressman Copyright (C) 2009
028 * @since 2.5.1
029 */
030public class JmriMultiStatePropertyListener extends JmriSimplePropertyListener {
031
032    ArrayList<Integer> _states;
033
034    JmriMultiStatePropertyListener(String propName, int type, String name, Conditional.Type varType,
035            Conditional client, int state) {
036        super(propName, type, name, varType, client);
037        _states = new ArrayList<>();
038        _states.add(Integer.valueOf(state));
039    }
040
041    JmriMultiStatePropertyListener(String propName, int type, NamedBeanHandle<?> namedBean, Conditional.Type varType,
042            Conditional client, int state) {
043        super(propName, type, namedBean, varType, client);
044        _states = new ArrayList<>();
045        _states.add(Integer.valueOf(state));
046    }
047
048    public void setState(int state) {
049        _states.add(Integer.valueOf(state));
050    }
051
052    /**
053     * Add a Conditional for the state set next by {@link #setState(int)}.
054     * Each state has its own entry in the client list, so a Conditional
055     * watching several states is listed once for each of them.
056     *
057     * @param client the Conditional to calculate
058     */
059    @Override
060    public void addConditional(Conditional client) {
061        _clients.add(client);
062    }
063
064    @Override
065    public void propertyChange(PropertyChangeEvent evt) {
066        log.debug("\"{}\" sent PropertyChangeEvent {}, old value =\"{}\", new value =\"{}, enabled = {}", _varName, evt.getPropertyName(), evt.getOldValue(), evt.getNewValue(), _enabled);
067        if (getPropertyName().equals(evt.getPropertyName())) {
068            int newState = ((Number) evt.getNewValue()).intValue();
069            int oldState = ((Number) evt.getOldValue()).intValue();
070            if (newState != oldState) {
071                List<Conditional> calculated = new ArrayList<>();
072                for (int i = 0; i < _states.size(); i++) {
073                    int state = _states.get(i).intValue();
074                    if ((oldState == state || newState == state) && !calculated.contains(_clients.get(i))) {
075                        // calculate each Conditional once, even if it watches both states
076                        calculated.add(_clients.get(i));
077                        calculateClient(i, evt);
078                    }
079                }
080            }
081        }
082    }
083    private static final Logger log = LoggerFactory.getLogger(JmriMultiStatePropertyListener.class);
084}