All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bidib.wizard.mvc.main.model.MainModel Maven / Gradle / Ivy

There is a newer version: 2.0.0-M1
Show newest version
package org.bidib.wizard.mvc.main.model;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.swing.SwingUtilities;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Predicate;
import org.bidib.jbidibc.core.Feature;
import org.bidib.jbidibc.core.enumeration.IdentifyState;
import org.bidib.jbidibc.core.enumeration.LightPortEnum;
import org.bidib.jbidibc.core.enumeration.SysErrorEnum;
import org.bidib.jbidibc.core.node.ConfigurationVariable;
import org.bidib.jbidibc.core.port.PortConfigValue;
import org.bidib.jbidibc.core.utils.ByteUtils;
import org.bidib.jbidibc.core.utils.NodeUtils;
import org.bidib.jbidibc.exchange.vendorcv.VendorCvData;
import org.bidib.wizard.comm.AnalogPortStatus;
import org.bidib.wizard.comm.BacklightPortStatus;
import org.bidib.wizard.comm.BidibStatus;
import org.bidib.wizard.comm.BoosterStatus;
import org.bidib.wizard.comm.FeedbackPortStatus;
import org.bidib.wizard.comm.InputPortStatus;
import org.bidib.wizard.comm.LightPortStatus;
import org.bidib.wizard.comm.ServoPortStatus;
import org.bidib.wizard.comm.SwitchPortStatus;
import org.bidib.wizard.main.DefaultApplicationContext;
import org.bidib.wizard.mvc.main.model.listener.AccessoryListListener;
import org.bidib.wizard.mvc.main.model.listener.BoosterStatusListener;
import org.bidib.wizard.mvc.main.model.listener.CvDefinitionListener;
import org.bidib.wizard.mvc.main.model.listener.FeedbackPortListener;
import org.bidib.wizard.mvc.main.model.listener.MacroListListener;
import org.bidib.wizard.mvc.main.model.listener.NodeListListener;
import org.bidib.wizard.mvc.main.model.listener.PortListListener;
import org.bidib.wizard.mvc.main.model.listener.PortListener;
import org.bidib.wizard.mvc.main.model.listener.PortValueListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jgoodies.common.collect.ArrayListModel;

public class MainModel implements PortsProvider {
    private static final Logger LOGGER = LoggerFactory.getLogger(MainModel.class);

    private Collection accessoryListListeners = new LinkedList();

    private Collection analogPortListListeners = new LinkedList();

    private Collection> analogPortListeners =
        new LinkedList>();

    private Collection boosterStatusListeners = new LinkedList();

    private Collection> feedbackPortListeners =
        new LinkedList>();

    private Collection feedbackPortListListeners = new LinkedList();

    private Collection> inputPortListeners =
        new LinkedList>();

    private Collection inputPortListListeners = new LinkedList();

    private Collection lightPortListListeners = new LinkedList();

    private Collection> lightPortListeners =
        new LinkedList>();

    private Collection backlightPortListListeners = new LinkedList();

    private Collection> backlightPortValueListeners =
        new LinkedList>();

    private Collection> backlightPortListeners =
        new LinkedList>();

    private Collection macroListListeners = new LinkedList();

    private Collection motorPortListListeners = new LinkedList();

    private Collection nodeListListeners = new LinkedList();

    private Collection servoPortListListeners = new LinkedList();

    private Collection> servoPortValueListeners =
        new LinkedList>();

    private Collection soundPortListListeners = new LinkedList();

    private Collection switchPortListListeners = new LinkedList();

    private Collection> switchPortListeners =
        new LinkedList>();

    private Collection cvDefinitionListeners = new LinkedList();

    private ArrayListModel accessories = new ArrayListModel();

    private List analogPorts = new LinkedList();

    private List features = new LinkedList();

    private List configurationVariables = new LinkedList();

    private int boosterCurrent;

    private long lastCurrentUpdate;

    private int boosterMaximumCurrent;

    private BoosterStatus boosterStatus;

    private int boosterTemperature;

    private int boosterVoltage;

    private List feedbackPorts = new LinkedList();

    private List flags = new LinkedList();

    private List inputPorts = new LinkedList();

    private List lightPorts = new LinkedList();

    private List backlightPorts = new LinkedList();

    private List macros = new LinkedList();

    private List motorPorts = new LinkedList();

    private Set nodes = new LinkedHashSet();

    private List servoPorts = new LinkedList();

    private List soundPorts = new LinkedList();

    private List switchPorts = new LinkedList();

    private Accessory selectedAccessory;

    private Macro selectedMacro;

    private Node selectedNode;

    private Object nodeLock = new Object();

    private StatusModel statusModel = new StatusModel();

    private Object vendorCVLock = new Object();

    private Object configVarsLock = new Object();

    private Object featuresLock = new Object();

    private PropertyChangeListener macroPendingChangesListener;

    private PropertyChangeListener accessoryPendingChangesListener;

    private AtomicBoolean initalLoadFinished = new AtomicBoolean(false);

    public MainModel() {

        macroPendingChangesListener = new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                LOGGER.info("The pending changes flag of a macro has been changed.");

                // force refresh of macro list
                fireMacroPendingChangesChanged();
            }
        };

        accessoryPendingChangesListener = new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                LOGGER.info("The property of an accessory has been changed.");
                switch (evt.getPropertyName()) {
                    case Accessory.PROPERTY_PENDING_CHANGES:
                        // force refresh of accessory list
                        fireAccessoryPendingChangesChanged();
                        break;
                    case Accessory.PROPERTY_TOTAL_ASPECTS:
                        int accessoryId = (evt.getNewValue() != null ? (int) evt.getNewValue() : -1);
                        LOGGER.info("The total aspects of an accessory have been changed, accessory id: {}",
                            accessoryId);

                        // perform with accessory id
                        fireAccessoryChanged(accessoryId);
                        break;
                    default:
                        break;
                }

            }
        };
    }

    public void addAccessoryListListener(AccessoryListListener l) {
        accessoryListListeners.add(l);
    }

    public void addAnalogPortListListener(PortListListener l) {
        analogPortListListeners.add(l);
    }

    public void addAnalogPortListener(PortListener l) {
        analogPortListeners.add(l);
    }

    public void addBoosterStatusListener(BoosterStatusListener l) {
        boosterStatusListeners.add(l);
    }

    public void addFeedbackPortListener(FeedbackPortListener l) {
        feedbackPortListeners.add(l);
    }

    public void addFeedbackPortListListener(PortListListener l) {
        feedbackPortListListeners.add(l);
    }

    public void addInputPortListener(PortListener l) {
        inputPortListeners.add(l);
    }

    public void addInputPortListListener(PortListListener l) {
        inputPortListListeners.add(l);
    }

    public void addLightPortListListener(PortListListener l) {
        lightPortListListeners.add(l);
    }

    public void addBacklightPortListListener(PortListListener l) {
        backlightPortListListeners.add(l);
    }

    public void addBacklightPortValueListener(PortValueListener l) {
        backlightPortValueListeners.add(l);
    }

    public void addMacroListListener(MacroListListener l) {
        macroListListeners.add(l);
    }

    public void addMotorPortListListener(PortListListener l) {
        motorPortListListeners.add(l);
    }

    /**
     * Add a node to the list of nodes.
     * 
     * @param node
     *            the new node to add
     */
    public void addNode(Node node) {
        boolean nodeListChanged = false;
        synchronized (nodes) {
            LOGGER.info("Add new node: {}", node);
            if (nodes.add(node)) {
                // fireNodeListChanged();
                nodeListChanged = true;
            }
        }
        if (nodeListChanged) {
            fireNodeListChanged();

            fireNodeListAdded(node);
        }
    }

    /**
     * Remove a node from the list of nodes.
     * 
     * @param node
     *            the node to remove
     */
    public void removeNode(Node node) {
        boolean nodeListChanged = false;

        List nodesToRemove = null;
        synchronized (nodes) {
            LOGGER.info("Remove node: {}", node);

            // if a hub node is removed then we must remove all children of this hub
            nodesToRemove = new LinkedList();
            nodesToRemove.add(node);

            if (NodeUtils.hasSubNodesFunctions(node.getUniqueId())) {
                byte[] addr = node.getNode().getAddr();
                LOGGER
                    .info(
                        "The removed node has subnode functions. We must remove all subnodes, too. Address of current node: {}",
                        addr);
                if (addr != null && addr.length > 0) {
                    for (Node currentNode : nodes) {
                        LOGGER.debug("Check if we must remove the current node: {}", currentNode);
                        byte[] currentAddr = currentNode.getNode().getAddr();
                        if (currentAddr.length > addr.length) {
                            // potential subnode
                            if (currentAddr[addr.length - 1] == addr[addr.length - 1]) {
                                // this is a subnode
                                LOGGER.info("Found a subnode to be removed: {}", currentNode);
                                nodesToRemove.add(currentNode);
                            }
                        }
                    }
                }
            }

            if (nodes.removeAll(nodesToRemove)) {
                LOGGER.info("Removed all nodes that must be removed: {}", nodesToRemove);
                nodeListChanged = true;
            }
            else {
                LOGGER.warn("Remove nodes from nodes list failed: {}", nodesToRemove);
            }

            LOGGER.info("Remaining nodes in list: {}", nodes);

            if (nodesToRemove.contains(getSelectedNode())) {
                LOGGER.info("The active node in model was removed: {}", getSelectedNode());
                setSelectedNode(null);
            }
        }
        if (nodeListChanged) {
            fireNodeListChanged();

            if (CollectionUtils.isNotEmpty(nodesToRemove)) {
                for (Node currentNode : nodesToRemove) {
                    fireNodeListRemoved(currentNode);
                }
            }
        }
    }

    public void addNodeListListener(NodeListListener l) {
        nodeListListeners.add(l);
    }

    public void removeNodeListListener(NodeListListener l) {
        nodeListListeners.remove(l);
    }

    public void addServoPortListListener(PortListListener l) {
        servoPortListListeners.add(l);
    }

    public void addServoPortValueListener(PortValueListener l) {
        servoPortValueListeners.add(l);
    }

    public void addSoundPortListListener(PortListListener l) {
        soundPortListListeners.add(l);
    }

    public void addSwitchPortListListener(PortListListener l) {
        switchPortListListeners.add(l);
    }

    public void addSwitchPortListener(PortListener l) {
        switchPortListeners.add(l);
    }

    public void addLightPortListener(PortListener l) {
        lightPortListeners.add(l);
    }

    public void addBacklightPortListener(PortListener l) {
        backlightPortListeners.add(l);
    }

    public void addCvDefinitionListener(CvDefinitionListener l) {
        cvDefinitionListeners.add(l);
    }

    // public void addFeatureListener(FeatureListener l) {
    // featureListeners.add(l);
    // }

    private void fireAccessoryPendingChangesChanged() {
        if (SwingUtilities.isEventDispatchThread()) {
            for (AccessoryListListener l : accessoryListListeners) {
                l.pendingChangesChanged();
            }
        }
        else {
            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    for (AccessoryListListener l : accessoryListListeners) {
                        l.pendingChangesChanged();
                    }
                }
            });
        }
    }

    private void fireAccessoryChanged(int accessoryId) {
        for (AccessoryListListener l : accessoryListListeners) {
            l.accessoryChanged(accessoryId);
        }
    }

    private void fireAccessoryListChanged() {
        for (AccessoryListListener l : accessoryListListeners) {
            l.listChanged();
        }
    }

    private void fireAnalogPortListChanged() {
        notifyPortListListeners(analogPortListListeners);
    }

    private void fireBoosterCurrentChanged(int current) {
        for (BoosterStatusListener l : boosterStatusListeners) {
            l.currentChanged(current);
        }
    }

    private void fireBoosterMaximumCurrentChanged(int maximumCurrent) {
        for (BoosterStatusListener l : boosterStatusListeners) {
            l.maximumCurrentChanged(maximumCurrent);
        }
    }

    private void fireBoosterStatusChanged(BoosterStatus status) {
        for (BoosterStatusListener l : boosterStatusListeners) {
            l.stateChanged(status);
        }
    }

    private void fireBoosterTemperatureChanged(int temperature) {
        for (BoosterStatusListener l : boosterStatusListeners) {
            l.temperatureChanged(temperature);
        }
    }

    private void fireBoosterVoltageChanged(int voltage) {
        for (BoosterStatusListener l : boosterStatusListeners) {
            l.voltageChanged(voltage);
        }
    }

    private void fireFeedbackPortAddressesChanged(
        final FeedbackPort port, final Collection addresses) {
        // verify that listeners always called from AWT-thread
        if (SwingUtilities.isEventDispatchThread()) {
            for (PortListener l : feedbackPortListeners) {
                ((FeedbackPortListener) l).addressesChanged(port, addresses);
            }
        }
        else {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    for (PortListener l : feedbackPortListeners) {
                        ((FeedbackPortListener) l).addressesChanged(port, addresses);
                    }
                }
            });
        }
    }

    private void fireFeedbackPortConfidenceChanged(
        final FeedbackPort port, final boolean freeze, final boolean signal, final boolean valid) {
        // verify that listeners always called from AWT-thread
        if (SwingUtilities.isEventDispatchThread()) {
            for (PortListener l : feedbackPortListeners) {
                ((FeedbackPortListener) l).confidenceChanged(port, freeze, signal, valid);
            }
        }
        else {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    for (PortListener l : feedbackPortListeners) {
                        ((FeedbackPortListener) l).confidenceChanged(port, freeze, signal, valid);
                    }
                }
            });
        }
    }

    private void fireFeedbackPortSpeedChanged(final FeedbackPort port, final int address, final int speed) {
        // verify that listeners always called from AWT-thread
        if (SwingUtilities.isEventDispatchThread()) {
            for (PortListener l : feedbackPortListeners) {
                ((FeedbackPortListener) l).speedChanged(port, address, speed);
            }
        }
        else {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    for (PortListener l : feedbackPortListeners) {
                        ((FeedbackPortListener) l).speedChanged(port, address, speed);
                    }
                }
            });
        }
    }

    private void fireFeedbackPortListChanged() {
        notifyPortListListeners(feedbackPortListListeners);
    }

    private void fireFeedbackPortStatusChanged(Port port, FeedbackPortStatus status) {
        notifyPortStatusListeners(feedbackPortListeners, port, status);
    }

    private void fireFeedbackPortDynStatesChanged(
        final FeedbackPort port, final Collection dynStates) {
        // verify that listeners always called from AWT-thread
        if (SwingUtilities.isEventDispatchThread()) {
            for (PortListener l : feedbackPortListeners) {
                ((FeedbackPortListener) l).dynStatesChanged(port, dynStates);
            }
        }
        else {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    for (PortListener l : feedbackPortListeners) {
                        ((FeedbackPortListener) l).dynStatesChanged(port, dynStates);
                    }
                }
            });
        }
    }

    private void fireFlagListChanged() {
    }

    private void fireInputPortStatusChanged(Port port, InputPortStatus status) {
        notifyPortStatusListeners(inputPortListeners, port, status);
    }

    private  void notifyPortStatusListeners(
        final Collection> listeners, final Port port, final T status) {
        if (SwingUtilities.isEventDispatchThread()) {
            for (PortListener l : listeners) {
                l.statusChanged(port, status);
            }
        }
        else {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    for (PortListener l : listeners) {
                        l.statusChanged(port, status);
                    }
                }
            });
        }
    }

    private  void notifyPortConfigListeners(
        final Collection> listeners, final Port port) {
        if (SwingUtilities.isEventDispatchThread()) {
            for (PortListener l : listeners) {
                l.configChanged(port);
            }
        }
        else {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    for (PortListener l : listeners) {
                        l.configChanged(port);
                    }
                }
            });
        }
    }

    private void fireInputPortListChanged() {
        notifyPortListListeners(inputPortListListeners);
    }

    private void fireLightPortListChanged() {
        notifyPortListListeners(lightPortListListeners);
    }

    private void fireBacklightPortListChanged() {
        notifyPortListListeners(backlightPortListListeners);
    }

    private void notifyPortListListeners(final Collection listeners) {
        if (SwingUtilities.isEventDispatchThread()) {
            for (PortListListener l : listeners) {
                l.listChanged();
            }
        }
        else {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    for (PortListListener l : listeners) {
                        l.listChanged();
                    }
                }
            });
        }
    }

    private  void notifyPortValueListeners(
        final Collection> listeners, final Port port) {
        if (SwingUtilities.isEventDispatchThread()) {
            for (PortValueListener l : listeners) {
                l.valueChanged(port);
            }
        }
        else {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    for (PortValueListener l : listeners) {
                        l.valueChanged(port);
                    }
                }
            });
        }
    }

    private void fireBacklightPortValueChanged(final BacklightPort port) {
        notifyPortValueListeners(backlightPortValueListeners, port);
    }

    private void fireMacroPendingChangesChanged() {
        if (SwingUtilities.isEventDispatchThread()) {
            for (MacroListListener l : macroListListeners) {
                l.pendingChangesChanged();
            }
        }
        else {
            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    for (MacroListListener l : macroListListeners) {
                        l.pendingChangesChanged();
                    }
                }
            });
        }
    }

    private void fireMacroChanged() {
        if (SwingUtilities.isEventDispatchThread()) {
            for (MacroListListener l : macroListListeners) {
                l.macroChanged();
            }
        }
        else {
            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    for (MacroListListener l : macroListListeners) {
                        l.macroChanged();
                    }
                }
            });
        }
    }

    private void fireMacroListChanged() {
        if (SwingUtilities.isEventDispatchThread()) {
            for (MacroListListener l : macroListListeners) {
                l.listChanged();
            }
        }
        else {
            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    for (MacroListListener l : macroListListeners) {
                        l.listChanged();
                    }
                }
            });
        }
    }

    private void fireMotorPortListChanged() {
        notifyPortListListeners(motorPortListListeners);
    }

    private void fireNodeChanged() {
        Collection listeners = Collections.unmodifiableCollection(nodeListListeners);
        for (NodeListListener l : listeners) {
            l.nodeChanged();
        }
    }

    private void fireNodeListChanged() {
        LOGGER.debug("Notify the listeners that the node list has changed.");
        Collection listeners = Collections.unmodifiableCollection(nodeListListeners);
        for (NodeListListener l : listeners) {
            l.listChanged();
        }
    }

    private void fireNodeListAdded(Node node) {
        LOGGER.debug("Notify the listeners that the node list has added a node.");
        Collection listeners = Collections.unmodifiableCollection(nodeListListeners);
        for (NodeListListener l : listeners) {
            l.listNodeAdded(node);
        }
    }

    private void fireNodeListRemoved(Node node) {
        LOGGER.debug("Notify the listeners that the node list has removed a node.");
        Collection listeners = Collections.unmodifiableCollection(nodeListListeners);
        for (NodeListListener l : listeners) {
            l.listNodeRemoved(node);
        }
    }

    private void fireNodeStateChanged() {
        Collection listeners = Collections.unmodifiableCollection(nodeListListeners);
        for (NodeListListener l : listeners) {
            l.nodeStateChanged();
        }
    }

    private void fireServoPortListChanged() {
        notifyPortListListeners(servoPortListListeners);
    }

    private void fireServoPortValueChanged(final ServoPort port) {
        notifyPortValueListeners(servoPortValueListeners, port);
    }

    private void fireSoundPortListChanged() {
        notifyPortListListeners(soundPortListListeners);
    }

    private void fireSwitchPortListChanged() {
        notifyPortListListeners(switchPortListListeners);
    }

    private void fireCvDefinitionChanged() {
        notifyCvDefinitionListeners(cvDefinitionListeners);
    }

    private void notifyCvDefinitionListeners(final Collection listeners) {
        if (SwingUtilities.isEventDispatchThread()) {
            for (CvDefinitionListener l : listeners) {
                l.cvDefinitionChanged();
            }
        }
        else {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    for (CvDefinitionListener l : listeners) {
                        l.cvDefinitionChanged();
                    }
                }
            });
        }
    }

    public Accessory getSelectedAccessory() {
        return selectedAccessory;
    }

    public List getAnalogPorts() {
        LOGGER.debug("Get analog ports.");
        synchronized (analogPorts) {
            if (getSelectedNode() != null && CollectionUtils.isNotEmpty(getSelectedNode().getGenericPorts())) {
                // fetch the analog ports from the generic ports
                LOGGER.trace("Get the analog ports from the generic ports.");

                analogPorts.clear();
                analogPorts.addAll(getSelectedNode().getAnalogPorts());

                // set the port labels
                applyPortLabels(getSelectedNode(), DefaultApplicationContext.KEY_ANALOGPORT_LABELS, analogPorts);
            }
            else {
                LOGGER.trace("The selected port has no generic ports.");
            }

            LOGGER.debug("Return number of analogPorts: {}", analogPorts.size());
            return Collections.unmodifiableList(analogPorts);
        }
    }

    public int getBoosterCurrent() {
        return boosterCurrent;
    }

    public int getBoosterMaximumCurrent() {
        return boosterMaximumCurrent;
    }

    public BoosterStatus getBoosterStatus() {
        return boosterStatus;
    }

    public int getBoosterTemperature() {
        return boosterTemperature;
    }

    public int getBoosterVoltage() {
        return boosterVoltage;
    }

    public List getFeedbackPorts() {
        synchronized (feedbackPorts) {
            return Collections.unmodifiableList(feedbackPorts);
        }
    }

    public List getFlags() {
        return Collections.unmodifiableList(flags);
    }

    public List getInputPorts() {
        LOGGER.debug("Get input ports.");
        synchronized (inputPorts) {
            if (getSelectedNode() != null && CollectionUtils.isNotEmpty(getSelectedNode().getGenericPorts())) {
                // fetch the input ports from the generic ports
                LOGGER.trace("Get the input ports from the generic ports.");

                inputPorts.clear();
                inputPorts.addAll(getSelectedNode().getInputPorts());

                // set the port labels
                applyPortLabels(getSelectedNode(), DefaultApplicationContext.KEY_INPUTPORT_LABELS, inputPorts);
            }
            else {
                LOGGER.trace("The selected port has no generic ports.");
            }

            LOGGER.debug("Return number of inputPorts: {}", inputPorts.size());
            return Collections.unmodifiableList(inputPorts);
        }
    }

    public List getEnabledInputPorts() {
        synchronized (inputPorts) {
            List enabledPorts = new LinkedList<>();
            for (InputPort port : inputPorts) {
                if (port.isEnabled()) {
                    enabledPorts.add(port);
                }
            }
            LOGGER.debug("Get the enabled input ports: {}", enabledPorts);
            return Collections.unmodifiableList(enabledPorts);
        }
    }

    public List getLightPorts() {
        LOGGER.debug("Get light ports.");
        synchronized (lightPorts) {
            if (getSelectedNode() != null && CollectionUtils.isNotEmpty(getSelectedNode().getGenericPorts())) {
                // fetch the light ports from the generic ports
                LOGGER.trace("Get the light ports from the generic ports.");

                lightPorts.clear();
                lightPorts.addAll(getSelectedNode().getLightPorts());

                // set the port labels
                applyPortLabels(getSelectedNode(), DefaultApplicationContext.KEY_LIGHTPORT_LABELS, lightPorts);
            }
            else {
                LOGGER.trace("The selected port has no generic ports.");
            }

            LOGGER.debug("Return number of lightPorts: {}", lightPorts.size());
            return Collections.unmodifiableList(lightPorts);
        }
    }

    public List getBacklightPorts() {
        LOGGER.debug("Get backlight ports.");
        synchronized (backlightPorts) {
            if (getSelectedNode() != null && CollectionUtils.isNotEmpty(getSelectedNode().getGenericPorts())) {
                // fetch the backlight ports from the generic ports
                LOGGER.trace("Get the backlight ports from the generic ports.");

                backlightPorts.clear();
                backlightPorts.addAll(getSelectedNode().getBacklightPorts());

                // set the port labels
                applyPortLabels(getSelectedNode(), DefaultApplicationContext.KEY_BACKLIGHTPORT_LABELS, backlightPorts);
            }
            else {
                LOGGER.trace("The selected port has no generic ports.");
            }

            LOGGER.debug("Return number of backlightPorts: {}", backlightPorts.size());
            return Collections.unmodifiableList(backlightPorts);
        }
    }

    public List getMotorPorts() {
        LOGGER.debug("Get motor ports.");
        synchronized (motorPorts) {
            if (getSelectedNode() != null && CollectionUtils.isNotEmpty(getSelectedNode().getGenericPorts())) {
                // fetch the motor ports from the generic ports
                LOGGER.trace("Get the motor ports from the generic ports.");

                motorPorts.clear();
                motorPorts.addAll(getSelectedNode().getMotorPorts());

                // set the port labels
                applyPortLabels(getSelectedNode(), DefaultApplicationContext.KEY_MOTORPORT_LABELS, motorPorts);
            }
            else {
                LOGGER.trace("The selected port has no generic ports.");
            }

            LOGGER.debug("Return number of motorPorts: {}", motorPorts.size());
            return Collections.unmodifiableList(motorPorts);
        }
    }

    /**
     * @return the selected node instance
     */
    public Node getSelectedNode() {
        synchronized (nodeLock) {
            return selectedNode;
        }
    }

    public Collection getNodes() {
        LOGGER.trace("Get the nodes.");
        synchronized (nodes) {
            return Collections.unmodifiableCollection(nodes);
        }
    }

    public List getServoPorts() {
        LOGGER.debug("Get servo ports.");
        synchronized (servoPorts) {
            if (getSelectedNode() != null && CollectionUtils.isNotEmpty(getSelectedNode().getGenericPorts())) {
                // fetch the switch ports from the generic ports
                LOGGER.trace("Get the servo ports from the generic ports.");

                servoPorts.clear();
                servoPorts.addAll(getSelectedNode().getServoPorts());

                // set the port labels
                applyPortLabels(getSelectedNode(), DefaultApplicationContext.KEY_SERVOPORT_LABELS, servoPorts);
            }
            else {
                LOGGER.trace("The selected port has no generic ports.");
            }

            LOGGER.debug("Return number of servoPorts: {}", servoPorts.size());
            return Collections.unmodifiableList(servoPorts);
        }
    }

    public List getSoundPorts() {
        LOGGER.debug("Get sound ports.");
        synchronized (soundPorts) {
            if (getSelectedNode() != null && CollectionUtils.isNotEmpty(getSelectedNode().getGenericPorts())) {
                // fetch the sound ports from the generic ports
                LOGGER.trace("Get the sound ports from the generic ports.");

                soundPorts.clear();
                soundPorts.addAll(getSelectedNode().getSoundPorts());

                // set the port labels
                applyPortLabels(getSelectedNode(), DefaultApplicationContext.KEY_SOUNDPORT_LABELS, soundPorts);
            }
            else {
                LOGGER.trace("The selected port has no generic ports.");
            }

            LOGGER.debug("Return number of soundPorts: {}", soundPorts.size());
            return Collections.unmodifiableList(soundPorts);
        }
    }

    public StatusModel getStatusModel() {
        return statusModel;
    }

    private > void applyPortLabels(Node node, String labelKey, List ports) {
        ChildLabels portLabels = (ChildLabels) DefaultApplicationContext.getInstance().get(labelKey);
        if (portLabels != null) {
            for (T port : ports) {
                // set the label
                port.setLabel(portLabels.getLabel(node.getNode().getUniqueId(), port.getId()));
            }
        }
        else {
            LOGGER.warn("No port labels available for labelKey: {}", labelKey);
        }
    }

    public List getSwitchPorts() {
        LOGGER.debug("Get switch ports.");
        synchronized (switchPorts) {
            if (getSelectedNode() != null && CollectionUtils.isNotEmpty(getSelectedNode().getGenericPorts())) {
                // fetch the switch ports from the generic ports
                LOGGER.trace("Get the switch ports from the generic ports.");

                switchPorts.clear();
                switchPorts.addAll(getSelectedNode().getSwitchPorts());

                // set the port labels
                applyPortLabels(getSelectedNode(), DefaultApplicationContext.KEY_SWITCHPORT_LABELS, switchPorts);
            }
            else {
                LOGGER.trace("The selected port has no generic ports.");
            }

            LOGGER.debug("Return number of switchPorts: {}", switchPorts.size());
            return Collections.unmodifiableList(switchPorts);
        }
    }

    public List getEnabledSwitchPorts() {
        synchronized (switchPorts) {
            List enabledPorts = new LinkedList<>();
            for (SwitchPort port : switchPorts) {
                if (port.isEnabled()) {
                    enabledPorts.add(port);
                }
            }
            return Collections.unmodifiableList(enabledPorts);
        }
    }

    @Override
    public boolean isFlatPortModel() {
        if (getSelectedNode() != null) {
            return getSelectedNode().getNode().isPortFlatModelAvailable();
        }
        return false;
    }

    public void replaceAccessory(Accessory accessory) {
        synchronized (accessories) {

            Accessory prev = accessories.get(accessory.getId());
            if (prev != null) {
                prev.removePropertyChangeListener(accessoryPendingChangesListener);
            }

            accessories.set(accessory.getId(), accessory);

            accessory.addPropertyChangeListener(accessoryPendingChangesListener);
        }
        fireAccessoryListChanged();
        setSelectedAccessory(accessory);
    }

    /**
     * Returns the currently selected macro.
     * 
     * @return the currently selected macro
     */
    public Macro getSelectedMacro() {
        return selectedMacro;
    }

    /**
     * Set the selected macro.
     * 
     * @param macro
     *            the selected macro
     */
    public void setSelectedMacro(Macro macro) {

        if (selectedMacro != null && MacroSaveState.PENDING_CHANGES.equals(selectedMacro.getMacroSaveState())) {
            // log warning
            LOGGER.warn("The current macro has pending changes.");
        }

        this.selectedMacro = macro;
        fireMacroChanged();
    }

    /**
     * Set the macros of the current node.
     * 
     * @param macros
     *            the macros
     */
    public void setMacros(Collection macros) {
        synchronized (this.macros) {
            // remove existing property change listener
            for (Macro macro : this.macros) {
                macro.removePropertyChangeListener(Macro.PROPERTY_PENDING_CHANGES, macroPendingChangesListener);
            }

            // clear references to existing macros
            this.macros.clear();
            if (macros != null) {
                // ... and add new macros
                this.macros.addAll(macros);
            }

            // add property change listener to new macros
            for (Macro macro : this.macros) {
                macro.addPropertyChangeListener(Macro.PROPERTY_PENDING_CHANGES, macroPendingChangesListener);
            }
        }
        fireMacroListChanged();
    }

    public List getMacros() {
        synchronized (macros) {
            return Collections.unmodifiableList(macros);
        }
    }

    /**
     * Replace the macro with the provided macro.
     * 
     * @param macro
     *            the new macro
     * @throws PropertyVetoException
     */
    public void replaceMacro(Macro macro) {
        LOGGER.info("Replace the macro: {}", macro);

        synchronized (macros) {

            // remove existing property change listener
            Macro existingMacro = macros.get(macro.getId());
            if (existingMacro != null) {
                existingMacro.removePropertyChangeListener(Macro.PROPERTY_PENDING_CHANGES, macroPendingChangesListener);
            }

            // keep the name of the old macro
            macro.setLabel(existingMacro.getLabel());

            macros.set(macro.getId(), macro);

            // add property change listener to new macro
            macro.addPropertyChangeListener(Macro.PROPERTY_PENDING_CHANGES, macroPendingChangesListener);
        }

        fireMacroListChanged();
        setSelectedMacro(macro);
    }

    /**
     * Set the selected accessory.
     * 
     * @param accessory
     *            the selected accessory
     */
    public void setSelectedAccessory(Accessory accessory) {
        if (selectedAccessory != null && selectedAccessory.hasPendingChanges()) {
            // log warning
            LOGGER.warn("The current accessory has pending changes.");
        }

        this.selectedAccessory = accessory;
        fireAccessoryChanged((accessory != null ? accessory.getId() : -1));
    }

    public List getAccessories() {
        synchronized (accessories) {
            return Collections.unmodifiableList(accessories);
        }
    }

    public ArrayListModel getAccessoriesListModel() {
        return accessories;
    }

    public void setAccessories(Collection accessories) {
        synchronized (this.accessories) {
            LOGGER.info("Set accessories: {}", accessories);

            // remove existing property change listener
            for (Accessory accessory : this.accessories) {
                accessory.removePropertyChangeListener(accessoryPendingChangesListener);
            }

            this.accessories.clear();
            if (accessories != null) {
                this.accessories.addAll(accessories);
            }

            // add property change listener to new accessory
            for (Accessory accessory : this.accessories) {
                accessory.addPropertyChangeListener(accessoryPendingChangesListener);
            }
        }
        // reset the accessory
        setSelectedAccessory(null);

        fireAccessoryListChanged();
    }

    public void setAnalogPorts(Collection analogPorts) {
        synchronized (this.analogPorts) {
            this.analogPorts.clear();
            if (analogPorts != null) {
                this.analogPorts.addAll(analogPorts);
            }
        }
        fireAnalogPortListChanged();
    }

    public void setAnalogPortConfig(int portNumber, Map> portConfig) {
        // synchronize because the backlightPorts can be accessed from different threads
        try {
            AnalogPort analogPort = null;
            synchronized (this.analogPorts) {
                if (analogPorts != null) {
                    LOGGER.info("Set analogPort config for portNumber: {}", portNumber);
                    analogPort = this.analogPorts.get(portNumber);
                    analogPort.setPortConfigX(portConfig);
                }
            }

            if (analogPort != null) {
                fireAnalogPortConfigChanged(analogPort);
            }
        }
        catch (Exception ex) {
            LOGGER.warn("Set analogport config failed for portNumber: {}", portNumber, ex);
        }
    }

    private void fireAnalogPortConfigChanged(Port port) {
        notifyPortConfigListeners(analogPortListeners, port);
    }

    public void setBoosterCurrent(int current) {

        // set the last current update time
        setLastCurrentUpdate(System.currentTimeMillis());

        if (current != this.boosterCurrent) {
            LOGGER.debug("Booster current has changed, new: {}, old: {}", current, boosterCurrent);
            this.boosterCurrent = current;
            fireBoosterCurrentChanged(current);
        }
        else {
            LOGGER.trace("Current is equal, do not send change notification.");
        }
    }

    /**
     * @return the lastCurrentUpdate
     */
    public long getLastCurrentUpdate() {
        return lastCurrentUpdate;
    }

    /**
     * @param lastCurrentUpdate
     *            the lastCurrentUpdate to set
     */
    public void setLastCurrentUpdate(long lastCurrentUpdate) {
        this.lastCurrentUpdate = lastCurrentUpdate;
    }

    public void setBoosterMaximumCurrent(int maximumCurrent) {
        LOGGER.info("Set the new maximum current value: {}, previous: {}", maximumCurrent, boosterMaximumCurrent);
        // if (maximumCurrent != this.boosterMaximumCurrent) {
        this.boosterMaximumCurrent = maximumCurrent;
        fireBoosterMaximumCurrentChanged(maximumCurrent);
        // }
    }

    public void setBoosterStatus(BoosterStatus status) {
        if (status != this.boosterStatus) {
            this.boosterStatus = status;
            fireBoosterStatusChanged(status);
        }
    }

    public void setBoosterTemperature(int temperature) {
        if (temperature != this.boosterTemperature) {
            this.boosterTemperature = temperature;
            fireBoosterTemperatureChanged(temperature);
        }
    }

    public void setBoosterVoltage(int voltage) {
        if (voltage != this.boosterVoltage) {
            this.boosterVoltage = voltage;
            fireBoosterVoltageChanged(voltage);
        }
    }

    public void setFeedbackPortAddresses(int detectorNumber, Collection addresses) {
        if (detectorNumber < getFeedbackPorts().size()) {
            FeedbackPort port = getFeedbackPorts().get(detectorNumber);

            port.setAddresses(addresses);
            fireFeedbackPortAddressesChanged(port, addresses);
        }
    }

    public void setFeedbackPortConfidence(int detectorNumber, boolean freeze, boolean signal, boolean valid) {
        final List ports = getFeedbackPorts();

        for (int index = 0; index < ports.size(); index++) {
            final FeedbackPort port = ports.get(index);

            port.setFreeze(freeze);
            port.setSignal(signal);
            port.setValid(valid);
            fireFeedbackPortConfidenceChanged(port, freeze, signal, valid);
        }
    }

    public void setFeedbackPorts(Collection feedbackPorts) {
        LOGGER.debug("Set the feedback ports, size: {}", (feedbackPorts != null ? feedbackPorts.size() : 0));
        synchronized (this.feedbackPorts) {
            this.feedbackPorts.clear();
            if (feedbackPorts != null) {
                this.feedbackPorts.addAll(feedbackPorts);
            }
        }
        fireFeedbackPortListChanged();
    }

    /**
     * Set the speed on the current detector if the address matches.
     * 
     * @param detectorNumber
     *            the detector number
     * @param address
     *            the address to search
     * @param speed
     *            the speed value
     */
    public void setFeedbackPortSpeed(int detectorNumber, int address, int speed) {
        if (detectorNumber < getFeedbackPorts().size()) {
            FeedbackPort port = getFeedbackPorts().get(detectorNumber);

            if (port != null) {
                Collection addresses = port.getAddresses();
                // check if the current detector has addresses and set the speed if the address matches
                if (addresses != null) {
                    for (FeedbackAddressData addressData : addresses) {
                        if (address == addressData.getAddress()) {
                            addressData.setSpeed(speed);
                            fireFeedbackPortSpeedChanged(port, address, speed);
                        }
                    }
                }
            }
        }
    }

    public void setFeedbackPortStatus(int detectorNumber, FeedbackPortStatus status) {
        LOGGER.debug("feedback port status, detector number: {}, status: {}", detectorNumber, status);
        if (detectorNumber < getFeedbackPorts().size()) {
            FeedbackPort port = getFeedbackPorts().get(detectorNumber);

            port.setStatus(status);
            fireFeedbackPortStatusChanged(port, status);
        }
    }

    public void setFeedbackPortDynStates(int detectorNumber, List dynStates) {
        if (detectorNumber < getFeedbackPorts().size()) {
            FeedbackPort port = getFeedbackPorts().get(detectorNumber);

            port.setDynStates(dynStates);
            fireFeedbackPortDynStatesChanged(port, dynStates);
        }
    }

    public void setFlags(Collection flags) {
        // synchronize because the flags can be accessed from different threads
        synchronized (this.flags) {
            this.flags.clear();
            if (flags != null) {
                this.flags.addAll(flags);
            }
        }
        fireFlagListChanged();
    }

    public void setInputPorts(Collection inputPorts) {
        // synchronize because the inputPorts can be accessed from different threads
        synchronized (this.inputPorts) {
            this.inputPorts.clear();
            if (inputPorts != null) {
                this.inputPorts.addAll(inputPorts);
            }
            LOGGER.info("Added inputPorts: {}", inputPorts);
        }
        fireInputPortListChanged();
    }

    public void setInputPortStatus(final int keyNumber, int keyState) {

        synchronized (this.inputPorts) {

            // support the flat model
            if (getSelectedNode() != null && getSelectedNode().getNode().isPortFlatModelAvailable()) {
                // make sure the input ports are available
                if (CollectionUtils.isNotEmpty(getInputPorts())) {

                    InputPort inputPort = CollectionUtils.find(inputPorts, new Predicate() {
                        @Override
                        public boolean evaluate(InputPort port) {
                            return port.getId() == keyNumber;
                        }
                    });

                    LOGGER.info("Found input port {} to set the keyState: {}", inputPort, keyState);

                    if (inputPort != null) {
                        InputPortStatus status = (keyState == 1 ? InputPortStatus.ON : InputPortStatus.OFF);

                        inputPort.setStatus(status);
                        fireInputPortStatusChanged(inputPort, status);
                    }
                    else {
                        LOGGER.warn("No input port in flat port model available for keyNumber: {}", keyNumber);
                    }
                }
            }
            else {

                if (getInputPorts().size() > keyNumber) {
                    InputPort port = getInputPorts().get(keyNumber);
                    InputPortStatus status = (keyState == 1 ? InputPortStatus.ON : InputPortStatus.OFF);

                    port.setStatus(status);
                    fireInputPortStatusChanged(port, status);
                }
                else {
                    LOGGER.warn("No input port available for keyNumber: {}", keyNumber);
                }
            }
        }
    }

    public void setInputPortConfig(int portNumber, Map> portConfig) {
        // synchronize because the inputPorts can be accessed from different threads
        try {
            InputPort inputPort = null;
            synchronized (this.inputPorts) {
                if (inputPorts != null) {
                    LOGGER.info("Set inputPort config for portNumber: {}", portNumber);
                    inputPort = this.inputPorts.get(portNumber);
                    inputPort.setPortConfigX(portConfig);
                }
            }
            if (inputPort != null) {
                fireInputPortConfigChanged(inputPort);
            }
        }
        catch (Exception ex) {
            LOGGER.warn("Set inputPort config failed for portNumber: {}", portNumber, ex);
        }
    }

    private void fireInputPortConfigChanged(Port port) {
        notifyPortConfigListeners(inputPortListeners, port);
    }

    public void setLightPorts(Collection lightPorts) {
        // synchronize because the lightPorts can be accessed from different threads
        synchronized (this.lightPorts) {
            this.lightPorts.clear();
            if (lightPorts != null) {
                this.lightPorts.addAll(lightPorts);
            }
        }
        fireLightPortListChanged();
    }

    public void setLightPortConfig(int portNumber, Map> portConfig) {
        // synchronize because the lightPorts can be accessed from different threads
        try {
            LightPort lightPort = null;
            synchronized (this.lightPorts) {
                if (lightPorts != null) {
                    LOGGER.info("Set lightport config for portNumber: {}", portNumber);
                    lightPort = this.lightPorts.get(portNumber);
                    lightPort.setPortConfigX(portConfig);
                }
            }
            if (lightPort != null) {
                fireLightPortConfigChanged(lightPort);
            }
        }
        catch (Exception ex) {
            LOGGER.warn("Set lightport config failed for portNumber: {}", portNumber, ex);
        }
    }

    private void fireLightPortConfigChanged(Port port) {
        notifyPortConfigListeners(lightPortListeners, port);
    }

    public void setBacklightPorts(Collection backlightPorts) {
        // synchronize because the backlightPorts can be accessed from different threads
        synchronized (this.backlightPorts) {
            this.backlightPorts.clear();
            if (backlightPorts != null) {
                this.backlightPorts.addAll(backlightPorts);
            }
        }
        fireBacklightPortListChanged();
    }

    public void setBacklightPortConfig(int portNumber, Map> portConfig) {
        // synchronize because the backlightPorts can be accessed from different threads
        try {
            BacklightPort backlightPort = null;
            synchronized (this.backlightPorts) {
                if (backlightPorts != null) {
                    backlightPort = this.backlightPorts.get(portNumber);

                    if (!backlightPort.isAdjusting()) {
                        backlightPort.setPortConfigX(portConfig);
                    }
                    else {
                        LOGGER.info("Ignore changed config during adjusting backlight value.");
                        backlightPort = null;
                    }
                }
            }
            if (backlightPort != null) {
                fireBacklightPortConfigChanged(backlightPort);
            }
        }
        catch (Exception ex) {
            LOGGER.warn("Set backlightport config failed for portNumber: {}", portNumber, ex);
        }
    }

    private void fireBacklightPortConfigChanged(Port port) {
        notifyPortConfigListeners(backlightPortListeners, port);
    }

    public void setBacklightPortValue(int portNumber, int portValue) {
        if (getBacklightPorts().size() > portNumber) {
            BacklightPort port = getBacklightPorts().get(portNumber);

            int oldValue = port.getValue();
            if (oldValue != portValue) {
                port.setValue(portValue, false);

                fireBacklightPortValueChanged(port);
            }
        }
    }

    public void setMotorPorts(Collection motorPorts) {
        // synchronize because the motorPorts can be accessed from different threads
        synchronized (this.motorPorts) {
            this.motorPorts.clear();
            if (motorPorts != null) {
                this.motorPorts.addAll(motorPorts);
            }
        }
        fireMotorPortListChanged();
    }

    /**
     * Set the selected node instance
     * 
     * @param node
     *            the selected node instance
     */
    public void setSelectedNode(Node node) {
        LOGGER.warn("Set the selected node in the main model: {}", node);

        synchronized (nodeLock) {

            if (node != null && node.equals(selectedNode)) {
                LOGGER.info("The selected node has not changed.");
                return;
            }
            this.selectedNode = node;

            // clear the cached node values
            clearCachedNodeValues();
        }
        fireNodeChanged();
    }

    private void clearCachedNodeValues() {
        LOGGER.info("Clear the cached node values.");

        boosterCurrent = 0;
        boosterMaximumCurrent = 0;
        boosterTemperature = 0;
        boosterVoltage = 0;
    }

    /**
     * Clear the cached nodes.
     */
    public void clearNodes() {
        setNodes(null);
        setSelectedNode(null);
    }

    public void setNodes(Collection nodes) {
        LOGGER.debug("Set the nodes: {}", nodes);
        synchronized (this.nodes) {
            this.nodes.clear();
            if (nodes != null) {
                this.nodes.addAll(nodes);
            }
        }
        fireNodeListChanged();
    }

    /**
     * Set the servo ports
     * 
     * @param servoPorts
     *            the new servo ports.
     */
    public void setServoPorts(Collection servoPorts) {
        // synchronize because the servoPorts can be accessed from different threads
        synchronized (this.servoPorts) {
            this.servoPorts.clear();
            if (servoPorts != null) {
                this.servoPorts.addAll(servoPorts);
            }
        }
        fireServoPortListChanged();
    }

    public void setServoPortConfig(int portNumber, Map> portConfig) {
        // synchronize because the servoPorts can be accessed from different threads
        try {
            synchronized (this.servoPorts) {
                if (servoPorts != null) {
                    this.servoPorts.get(portNumber).setPortConfigX(portConfig);
                }
            }
            fireServoPortListChanged();
        }
        catch (Exception ex) {
            LOGGER.warn("Set servoport config failed for portNumber: {}", portNumber, ex);
        }
    }

    public void setServoPortValue(int portNumber, int portValue) {
        if (getServoPorts().size() > portNumber) {
            ServoPort port = getServoPorts().get(portNumber);

            int oldValue = port.getValue();
            if (oldValue != portValue) {
                port.setValue(portValue);

                fireServoPortValueChanged(port);
            }
        }
    }

    public void setSoundPorts(Collection soundPorts) {
        synchronized (this.soundPorts) {
            this.soundPorts.clear();
            if (soundPorts != null) {
                this.soundPorts.addAll(soundPorts);
            }
        }
        fireSoundPortListChanged();
    }

    public void setSwitchPorts(Collection switchPorts) {
        synchronized (this.switchPorts) {
            LOGGER.info("Set the new switch ports: {}", switchPorts);
            this.switchPorts.clear();
            if (switchPorts != null) {
                this.switchPorts.addAll(switchPorts);
            }
        }
        fireSwitchPortListChanged();
    }

    public void setSwitchPortConfig(int portNumber, Map> portConfig) {
        // synchronize because the switchPorts can be accessed from different threads
        try {
            synchronized (this.switchPorts) {
                if (switchPorts != null) {
                    this.switchPorts.get(portNumber).setPortConfigX(portConfig);
                }
            }
            fireSwitchPortListChanged();
        }
        catch (Exception ex) {
            LOGGER.warn("Set switchport config failed for portNumber: {}", portNumber, ex);
        }
    }

    public void setSwitchPortStatus(final int portNumber, int keyState) {

        synchronized (switchPorts) {
            // support the flat model
            if (getSelectedNode() != null && getSelectedNode().getNode().isPortFlatModelAvailable()) {
                // make sure the input ports are available
                if (CollectionUtils.isNotEmpty(getSwitchPorts())) {

                    SwitchPort switchPort = CollectionUtils.find(switchPorts, new Predicate() {
                        @Override
                        public boolean evaluate(SwitchPort port) {
                            return port.getId() == portNumber;
                        }
                    });

                    if (switchPort != null) {
                        SwitchPortStatus status = (keyState == 1 ? SwitchPortStatus.ON : SwitchPortStatus.OFF);
                        LOGGER.debug("SwitchPort status has changed, port: {}, status: {}", switchPort, status);
                        switchPort.setStatus(status);
                        fireSwitchPortStatusChanged(switchPort, status);
                    }
                    else {
                        LOGGER.warn("No switch port in flat port model available for portNumber: {}", portNumber);
                    }
                }
            }
            else {

                if (portNumber < switchPorts.size()) {
                    SwitchPort port = switchPorts.get(portNumber);
                    SwitchPortStatus status = (keyState == 1 ? SwitchPortStatus.ON : SwitchPortStatus.OFF);
                    LOGGER.debug("SwitchPort status has changed, port: {}, status: {}", port, status);
                    port.setStatus(status);
                    fireSwitchPortStatusChanged(port, status);
                }
                else {
                    LOGGER.warn("No switch port available for portNumber: {}", portNumber);
                }
            }
        }
    }

    public void setLightPortStatus(final int portNumber, int portState) {

        synchronized (lightPorts) {
            // support the flat model
            if (getSelectedNode() != null && getSelectedNode().getNode().isPortFlatModelAvailable()) {
                // make sure the input ports are available
                if (CollectionUtils.isNotEmpty(getLightPorts())) {

                    LightPort lightPort = CollectionUtils.find(lightPorts, new Predicate() {
                        @Override
                        public boolean evaluate(LightPort port) {
                            return port.getId() == portNumber;
                        }
                    });

                    if (lightPort != null) {
                        LightPortEnum type = LightPortEnum.valueOf(ByteUtils.getLowByte(portState));
                        LightPortStatus status = LightPortStatus.valueOf(type);

                        LOGGER.debug("LightPort status has changed, port: {}, status: {}", lightPort, status);
                        lightPort.setStatus(status);
                        fireLightPortStatusChanged(lightPort, status);
                    }
                    else {
                        LOGGER.warn("No input port in flat port model available for portNumber: {}", portNumber);
                    }
                }
            }
            else {

                if (portNumber < lightPorts.size()) {
                    LightPort port = lightPorts.get(portNumber);

                    LightPortEnum type = LightPortEnum.valueOf(ByteUtils.getLowByte(portState));
                    LightPortStatus status = LightPortStatus.valueOf(type);

                    LOGGER.debug("LightPort status has changed, port: {}, status: {}", port, status);
                    port.setStatus(status);
                    fireLightPortStatusChanged(port, status);
                }
                else {
                    LOGGER.warn("No input port available for portNumber: {}", portNumber);
                }
            }
        }
    }

    private void fireSwitchPortStatusChanged(Port port, SwitchPortStatus status) {
        notifyPortStatusListeners(switchPortListeners, port, status);
    }

    private void fireLightPortStatusChanged(Port port, LightPortStatus status) {
        notifyPortStatusListeners(lightPortListeners, port, status);
    }

    public void setIdentifyState(Node node, IdentifyState identifyState) {
        LOGGER.debug("setIdentifyState, node: {}, identifyState: {}", node, identifyState);
        node.setIdentifyState(identifyState);
        fireNodeStateChanged();
    }

    public void setErrorState(Node node, SysErrorEnum sysError, byte[] reasonData) {
        LOGGER.error("setErrorState, node: {}, sysError: {}", node, sysError);
        node.setErrorState(sysError, reasonData);
        fireNodeStateChanged();
    }

    public void setNodeHasError(Node node, boolean nodeHasError) {
        LOGGER.debug("setErrorState, node: {}, nodeHasError: {}", node, nodeHasError);
        node.setNodeHasError(nodeHasError);
        fireNodeStateChanged();
    }

    public void setCvDefinition(VendorCvData vendorCV) {
        LOGGER.info("Set the CV definition: {}", vendorCV);
        // synchronized (vendorCVLock) {
        // this.vendorCvData = vendorCV;
        // }
        fireCvDefinitionChanged();
    }

    public VendorCvData getVendorCV() {
        synchronized (vendorCVLock) {
            // return vendorCvData;
            VendorCvData vendorCvData = null;
            if (selectedNode != null) {
                vendorCvData = selectedNode.getVendorCV();
            }
            return vendorCvData;
        }
    }

    /**
     * @return the features
     */
    public List getFeatures() {
        synchronized (featuresLock) {
            return features;
        }
    }

    /**
     * @param features
     *            the features to set
     */
    public void setFeatures(List features) {
        synchronized (featuresLock) {
            this.features = new LinkedList(features);
        }

        fireFeaturesChanged();
    }

    private void fireFeaturesChanged() {
        // TODO check how we can use this ... currently unused
        // the problem is, that we must trigger the reload of the feedback ports
        // in the MainController to get all values correct published to the
        // displaying components
    }

    public boolean isCvDefinitionAvailable() {

        // check if the cv definition is available
        synchronized (vendorCVLock) {

            if (selectedNode != null) {
                return (selectedNode.getVendorCV() != null);
            }
            return false;
            // return (vendorCvData != null);
        }
    }

    /**
     * @return the configurationVariables
     */
    public List getConfigurationVariables() {
        synchronized (configVarsLock) {
            return configurationVariables;
        }
    }

    /**
     * @param configurationVariables
     *            the configurationVariables to set
     */
    public void setConfigurationVariables(List configurationVariables) {
        synchronized (configVarsLock) {
            this.configurationVariables = new LinkedList();
            if (configurationVariables != null) {
                this.configurationVariables.addAll(configurationVariables);
            }
        }

        fireConfigurationVariablesChanged();
    }

    /**
     * @param configurationVars
     *            the configurationVariable values to update
     */
    public void updateConfigurationVariableValues(List configurationVars) {
        // iterate over the collection of stored variables in the model and update the values.
        // After that notify the tree and delete the new values that are now stored in the node
        synchronized (configVarsLock) {
            for (ConfigurationVariable updatedCV : configurationVars) {
                int index = configurationVariables.indexOf(updatedCV);
                LOGGER.debug("The index of the stored value: {}", index);
                if (index > -1) {
                    ConfigurationVariable storedCV = configurationVariables.get(index);
                    storedCV.setValue(updatedCV.getValue());
                    storedCV.setTimeout(updatedCV.isTimeout());
                }
                else {
                    LOGGER.info("Add new CV because the updated CV was not found in the stored CV values: {}",
                        updatedCV);

                    configurationVariables.add(updatedCV);
                }
            }

            LOGGER.info("Number of stored CV: {}", configurationVariables.size());
        }

        fireConfigurationVariablesChanged();
    }

    private void fireConfigurationVariablesChanged() {
        notifyConfigurationVariableValueListeners(cvDefinitionListeners);
    }

    private void notifyConfigurationVariableValueListeners(final Collection listeners) {
        if (SwingUtilities.isEventDispatchThread()) {
            for (CvDefinitionListener l : listeners) {
                l.cvDefinitionValuesChanged();
            }
        }
        else {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    for (CvDefinitionListener l : listeners) {
                        l.cvDefinitionValuesChanged();
                    }
                }
            });
        }
    }

    /**
     * Update all port lists with the values from the model
     */
    public void updatePortLists() {
        LOGGER.info("updatePortLists.");

        // TODO clear the caches

        // notify the listeners
        fireAnalogPortListChanged();
        fireBacklightPortListChanged();
        fireFeedbackPortListChanged();
        fireInputPortListChanged();
        fireLightPortListChanged();
        fireMotorPortListChanged();
        fireServoPortListChanged();
        fireSoundPortListChanged();
        fireSwitchPortListChanged();
    }

    public void signalInitialLoadFinished() {
        LOGGER.info("The initial load has finished.");
        initalLoadFinished.set(true);
    }

    public void signalResetInitialLoadFinished() {
        LOGGER.info("The initial load is reset.");
        initalLoadFinished.set(false);
    }

    public boolean isInitialLoadFinished() {
        return initalLoadFinished.get();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy