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

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

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

import java.awt.Color;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.swing.SwingUtilities;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.bidib.jbidibc.core.enumeration.IdentifyState;
import org.bidib.jbidibc.core.enumeration.SysErrorEnum;
import org.bidib.jbidibc.core.node.ConfigurationVariable;
import org.bidib.jbidibc.core.utils.MessageUtils;
import org.bidib.jbidibc.core.utils.NodeUtils;
import org.bidib.jbidibc.exchange.vendorcv.NodeType;
import org.bidib.jbidibc.exchange.vendorcv.TemplateType;
import org.bidib.jbidibc.exchange.vendorcv.VendorCvData;
import org.bidib.wizard.locale.Resources;
import org.bidib.wizard.mvc.common.view.cvdefinition.CvDefinitionTreeTableModel;
import org.bidib.wizard.mvc.console.controller.ConsoleController;
import org.bidib.wizard.mvc.console.model.ConsoleModel;
import org.bidib.wizard.mvc.main.model.listener.NodeListener;
import org.bidib.wizard.mvc.main.view.cvdef.CvNode;
import org.bidib.wizard.mvc.main.view.cvdef.DeviceNode;
import org.bidib.wizard.mvc.main.view.panel.CvDefinitionTreeHelper;
import org.bidib.wizard.utils.XmlLocaleUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Node implements LabelAware, PropertyChangeListener {
    private static final long serialVersionUID = 1L;

    private static final Logger LOGGER = LoggerFactory.getLogger(Node.class);

    private final Collection listeners = new LinkedList();

    private Boolean addressMessagesEnabled;

    private Boolean commandStation = Boolean.FALSE;

    private Boolean railComPlusAvailable = Boolean.FALSE;

    private Boolean pomUpdateAvailable = Boolean.FALSE;

    private Boolean booster = Boolean.FALSE;

    private Boolean dccStartEnabled;

    private Boolean externalStartEnabled;

    private Boolean feedbackMessagesEnabled;

    private IdentifyState identifyState;

    private SysErrorEnum sysError;

    private byte[] reasonData;

    private boolean isStall;

    private Boolean keyMessagesEnabled;

    private String label;

    private final org.bidib.jbidibc.core.Node node;

    private int storableMacroCount;

    private boolean updatable;

    private boolean bootloaderNode;

    private boolean nodeHasError;

    private VendorCvData vendorCV;

    private DeviceNode cvRootNode;

    private CvDefinitionTreeTableModel treeModel;

    private List configVariables;

    private Map cvNumberToNodeMap;

    private List genericPorts = new LinkedList<>();

    private List analogPorts = new LinkedList<>();

    private List backlightPorts = new LinkedList<>();

    private List inputPorts = new LinkedList<>();

    private List lightPorts = new LinkedList<>();

    private List motorPorts = new LinkedList<>();

    private List servoPorts = new LinkedList<>();

    private List soundPorts = new LinkedList<>();

    private List switchPorts = new LinkedList<>();

    /**
     * Create a new node with the associated bidib node.
     * 
     * @param node
     *            the bidib node is mandatory
     * @throws IllegalArgumentException
     *             if the bidib node is null
     */
    public Node(org.bidib.jbidibc.core.Node node) {
        if (node == null) {
            throw new IllegalArgumentException("The node must not be null!");
        }
        this.node = node;
    }

    public long getUniqueId() {
        return node.getUniqueId();
    }

    public void addNodeListener(NodeListener l) {
        listeners.add(l);
    }

    public void removeNodeListener(NodeListener l) {
        listeners.remove(l);
    }

    public Boolean isAddressMessagesEnabled() {
        return addressMessagesEnabled;
    }

    public void setAddressMessagesEnabled(Boolean addressMessagesEnabled) {
        this.addressMessagesEnabled = addressMessagesEnabled;
        fireAddressMessagesEnabledChanged(addressMessagesEnabled);
    }

    public Boolean isBooster() {
        return booster;
    }

    public void setBooster(Boolean booster) {
        this.booster = booster;
    }

    public Boolean isCommandStation() {
        return commandStation;
    }

    public void setCommandStation(Boolean commandStation) {
        this.commandStation = commandStation;
    }

    public Boolean isRailComPlusAvailable() {
        return railComPlusAvailable;
    }

    public void setRailComPlusAvailable(Boolean railComPlusAvailable) {
        LOGGER.info("Set railComPlusAvailable: {}", railComPlusAvailable);
        this.railComPlusAvailable = railComPlusAvailable;
        fireRailComPlusAvailableChanged(railComPlusAvailable);
    }

    public Boolean isPomUpdateAvailable() {
        return pomUpdateAvailable;
    }

    public void setPomUpdateAvailable(Boolean pomUpdateAvailable) {
        LOGGER.info("Set pomUpdateAvailable: {}", pomUpdateAvailable);
        this.pomUpdateAvailable = pomUpdateAvailable;
        firePomUpdateAvailableChanged(pomUpdateAvailable);
    }

    public Boolean isDccStartEnabled() {
        return dccStartEnabled;
    }

    public void setDccStartEnabled(Boolean dccStartEnabled) {
        this.dccStartEnabled = dccStartEnabled;
        fireDccStartEnabledChanged(dccStartEnabled);
    }

    public Boolean isExternalStartEnabled() {
        return externalStartEnabled;
    }

    public void setExternalStartEnabled(Boolean externalStartEnabled) {
        this.externalStartEnabled = externalStartEnabled;
        fireExternalStartEnabledChanged(externalStartEnabled);
    }

    public Boolean isFeedbackMessagesEnabled() {
        return feedbackMessagesEnabled;
    }

    public void setFeedbackMessagesEnabled(Boolean feedbackMessagesEnabled) {
        this.feedbackMessagesEnabled = feedbackMessagesEnabled;
        fireFeedbackMessagesEnabledChanged(feedbackMessagesEnabled);
    }

    public IdentifyState getIdentifyState() {
        return identifyState;
    }

    public void setIdentifyState(IdentifyState identifyState) {
        this.identifyState = identifyState;
        fireIdentifyStateChanged(identifyState);
    }

    public void setErrorState(final SysErrorEnum sysError, final byte[] reasonData) {
        this.sysError = sysError;
        this.reasonData = reasonData;
        fireSysErrorChanged(sysError);

        // notify the console
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                // ensure console is visible
                ConsoleController.ensureConsoleVisible();
                try {
                    String reason = MessageUtils.formatSysError(getNode().getAddr(), sysError, reasonData);
                    // add line
                    ConsoleModel.getConsoleModel().addConsoleLine(Color.red,
                        String.format("The node %s is set to error state: %s", Node.this.toString(), reason));
                }
                catch (Exception ex) {
                    LOGGER.warn("Add new error line to console failed, sysError: {}, reasonData: {}", sysError,
                        reasonData, ex);
                }
            }
        });
    }

    public SysErrorEnum getErrorState() {
        return sysError;
    }

    public byte[] getReasonData() {
        return reasonData;
    }

    /**
     * @return the node has the reset required flag set
     */
    public boolean isNodeHasRestartPendingError() {
        return SysErrorEnum.BIDIB_ERR_RESET_REQUIRED.equals(sysError);
    }

    public Boolean isKeyMessagesEnabled() {
        return keyMessagesEnabled;
    }

    public void setKeyMessagesEnabled(Boolean keyMessagesEnabled) {
        this.keyMessagesEnabled = keyMessagesEnabled;
        fireKeyMessagesEnabledChanged(keyMessagesEnabled);
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
        fireLabelChanged(label);
    }

    public org.bidib.jbidibc.core.Node getNode() {
        return node;
    }

    public int getStorableMacroCount() {
        return storableMacroCount;
    }

    public void setStorableMacroCount(int storableMacroCount) {
        this.storableMacroCount = storableMacroCount;
    }

    /**
     * @return the genericPorts
     */
    public List getGenericPorts() {
        return Collections.unmodifiableList(genericPorts);
    }

    /**
     * @param genericPorts
     *            the genericPorts to set
     */
    public void setGenericPorts(List genericPorts) {

        synchronized (this.genericPorts) {
            LOGGER.info("Set the generic ports on the node: {}", this);

            // remove property change listener
            for (GenericPort port : this.genericPorts) {
                port.removePropertyChangeListener(this);
            }

            // set the new generic ports
            this.genericPorts.clear();
            this.genericPorts.addAll(genericPorts);

            // add property change listener
            for (GenericPort port : this.genericPorts) {
                port.addPropertyChangeListener(this);
            }

            clearPortCache();
        }
    }

    public void clearPortCache() {
        LOGGER.info("Clear the port cache on node: {}", this);

        synchronized (genericPorts) {
            // clear all cached ports
            switchPorts.clear();
            servoPorts.clear();
            inputPorts.clear();
            analogPorts.clear();
            lightPorts.clear();
            backlightPorts.clear();
            motorPorts.clear();
            soundPorts.clear();
        }
    }

    public List getAnalogPorts() {

        synchronized (genericPorts) {

            if (CollectionUtils.isEmpty(analogPorts)) {
                LOGGER.debug("Prepare the analog ports.");
                for (GenericPort genericPort : genericPorts) {
                    // fetch the values from the generic port
                    if (genericPort.isSupportsAnalogPort()) {
                        LOGGER.trace("The current port supports analog port: {}", genericPort);
                        AnalogPort analogPort = new AnalogPort(genericPort);
                        analogPort.setId(genericPort.getPortNumber());
                        analogPorts.add(analogPort);
                    }
                    else {
                        LOGGER.trace("The current port does not support analog port: {}", genericPort);
                    }
                }
                LOGGER.debug("Return the prepared analog ports: {}", analogPorts.size());
            }
            else {
                LOGGER.debug("Return the cached analog ports, size: {}", analogPorts.size());
            }

            return Collections.unmodifiableList(analogPorts);
        }
    }

    public List getSwitchPorts() {

        synchronized (genericPorts) {

            if (CollectionUtils.isEmpty(switchPorts)) {
                LOGGER.debug("Prepare the switch ports.");
                for (GenericPort genericPort : genericPorts) {
                    // fetch the values from the generic port
                    if (genericPort.isSupportsSwitchPort()) {
                        LOGGER.trace("The current port supports switch port: {}", genericPort);
                        SwitchPort switchPort = new SwitchPort(genericPort);
                        switchPort.setId(genericPort.getPortNumber());
                        switchPorts.add(switchPort);
                    }
                    else {
                        LOGGER.trace("The current port does not support switch port: {}", genericPort);
                    }
                }
                LOGGER.debug("Return the prepared switch ports: {}", switchPorts.size());
            }
            else {
                LOGGER.debug("Return the cached switch ports, size: {}", switchPorts.size());
            }

            return Collections.unmodifiableList(switchPorts);
        }
    }

    public List getLightPorts() {

        synchronized (genericPorts) {

            if (CollectionUtils.isEmpty(lightPorts)) {
                LOGGER.debug("Prepare the light ports.");
                for (GenericPort genericPort : genericPorts) {
                    // fetch the values from the generic port
                    if (genericPort.isSupportsLightPort()) {
                        LOGGER.trace("The current port supports light port: {}", genericPort);
                        LightPort lightPort = new LightPort(genericPort);
                        lightPort.setId(genericPort.getPortNumber());
                        lightPorts.add(lightPort);
                    }
                    else {
                        LOGGER.trace("The current port does not support light port: {}", genericPort);
                    }
                }
                LOGGER.debug("Return the prepared light ports: {}", lightPorts.size());
            }
            else {
                LOGGER.debug("Return the cached light ports, size: {}", lightPorts.size());
            }

            return Collections.unmodifiableList(lightPorts);
        }
    }

    public List getBacklightPorts() {

        synchronized (genericPorts) {

            if (CollectionUtils.isEmpty(backlightPorts)) {
                LOGGER.debug("Prepare the backlight ports.");
                for (GenericPort genericPort : genericPorts) {
                    // fetch the values from the generic port
                    if (genericPort.isSupportsBacklightPort()) {
                        LOGGER.trace("The current port supports backlight port: {}", genericPort);
                        BacklightPort backlightPort = new BacklightPort(genericPort);
                        backlightPort.setId(genericPort.getPortNumber());
                        backlightPorts.add(backlightPort);
                    }
                    else {
                        LOGGER.trace("The current port does not support backlight port: {}", genericPort);
                    }
                }
                LOGGER.debug("Return the prepared backlight ports: {}", backlightPorts.size());
            }
            else {
                LOGGER.debug("Return the cached backlight ports, size: {}", backlightPorts.size());
            }

            return Collections.unmodifiableList(backlightPorts);
        }
    }

    public List getInputPorts() {
        synchronized (genericPorts) {
            if (CollectionUtils.isEmpty(inputPorts)) {
                LOGGER.debug("Prepare the input ports.");
                for (GenericPort genericPort : genericPorts) {
                    // fetch the values from the generic port
                    if (genericPort.isSupportsInputPort()) {
                        LOGGER.trace("The current port supports input port: {}", genericPort);
                        InputPort inputPort = new InputPort(genericPort);
                        inputPort.setId(genericPort.getPortNumber());
                        inputPorts.add(inputPort);
                    }
                    else {
                        LOGGER.trace("The current port does not support input port: {}", genericPort);
                    }
                }
            }
            else {
                LOGGER.debug("Return the cached input ports, size: {}", inputPorts.size());
            }

            return Collections.unmodifiableList(inputPorts);
        }
    }

    public List getServoPorts() {

        synchronized (genericPorts) {
            if (CollectionUtils.isEmpty(servoPorts)) {
                LOGGER.debug("Prepare the servo ports.");
                for (GenericPort genericPort : genericPorts) {
                    // fetch the values from the generic port
                    if (genericPort.isSupportsServoPort()) {
                        LOGGER.trace("The current port supports servo port: {}", genericPort);
                        ServoPort servoPort = new ServoPort(genericPort);
                        servoPort.setId(genericPort.getPortNumber());
                        servoPorts.add(servoPort);
                    }
                    else {
                        LOGGER.trace("The current port does not support servo port: {}", genericPort);
                    }
                }
            }
            else {
                LOGGER.debug("Return the cached servo ports.");
            }
            return Collections.unmodifiableList(servoPorts);
        }
    }

    public List getMotorPorts() {

        synchronized (genericPorts) {

            if (CollectionUtils.isEmpty(motorPorts)) {
                LOGGER.debug("Prepare the motor ports.");
                for (GenericPort genericPort : genericPorts) {
                    // fetch the values from the generic port
                    if (genericPort.isSupportsMotorPort()) {
                        LOGGER.trace("The current port supports motor port: {}", genericPort);
                        MotorPort motorPort = new MotorPort(genericPort);
                        motorPort.setId(genericPort.getPortNumber());
                        motorPorts.add(motorPort);
                    }
                    else {
                        LOGGER.trace("The current port does not support motor port: {}", genericPort);
                    }
                }
                LOGGER.debug("Return the prepared motor ports: {}", motorPorts.size());
            }
            else {
                LOGGER.debug("Return the cached motor ports, size: {}", motorPorts.size());
            }

            return Collections.unmodifiableList(motorPorts);
        }
    }

    public List getSoundPorts() {

        synchronized (genericPorts) {

            if (CollectionUtils.isEmpty(soundPorts)) {
                LOGGER.debug("Prepare the sound ports.");
                for (GenericPort genericPort : genericPorts) {
                    // fetch the values from the generic port
                    if (genericPort.isSupportsSoundPort()) {
                        LOGGER.trace("The current port supports sound port: {}", genericPort);
                        SoundPort soundPort = new SoundPort(genericPort);
                        soundPort.setId(genericPort.getPortNumber());
                        soundPorts.add(soundPort);
                    }
                    else {
                        LOGGER.trace("The current port does not support sound port: {}", genericPort);
                    }
                }
                LOGGER.debug("Return the prepared sound ports: {}", soundPorts.size());
            }
            else {
                LOGGER.debug("Return the cached sound ports, size: {}", soundPorts.size());
            }

            return Collections.unmodifiableList(soundPorts);
        }
    }

    public boolean isUpdatable() {
        return updatable;
    }

    public void setUpdatable(boolean updatable) {
        this.updatable = updatable;
    }

    /**
     * @return the bootloaderNode
     */
    public boolean isBootloaderNode() {
        return bootloaderNode;
    }

    /**
     * @param bootloaderNode
     *            the bootloaderNode to set
     */
    public void setBootloaderNode(boolean bootloaderNode) {
        this.bootloaderNode = bootloaderNode;
    }

    /**
     * @return the nodeHasError
     */
    public boolean isNodeHasError() {
        return nodeHasError || (sysError != null && !SysErrorEnum.BIDIB_ERR_NONE.equals(sysError));
    }

    /**
     * @param ignoreSysError
     *            flag to allow ignore sys errors
     * @return node has error flag set
     */
    public boolean isNodeHasError(boolean ignoreSysError) {
        if (ignoreSysError) {
            return nodeHasError;
        }
        return isNodeHasError();
    }

    /**
     * @return the nodeHasSysError
     */
    public boolean isNodeHasSysError() {
        return (sysError != null && !SysErrorEnum.BIDIB_ERR_NONE.equals(sysError));
    }

    /**
     * @param nodeHasError
     *            the nodeHasError to set
     */
    public void setNodeHasError(boolean nodeHasError) {
        this.nodeHasError = nodeHasError;
        if (!nodeHasError) {
            setErrorState(null, null);
        }
    }

    /**
     * @param stall
     *            the stall flag to set
     */
    public void setNodeIsStall(final boolean stall) {
        LOGGER.warn("The node {} is stall: {}", node, stall);
        this.isStall = stall;

        // notify the console
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                // ensure console is visible
                ConsoleController.ensureConsoleVisible();

                // add line
                ConsoleModel.getConsoleModel().addConsoleLine(Color.black,
                    String.format("The node %s is %s", Node.this.toString(), stall ? "stall" : "not stall"));
            }
        });
    }

    /**
     * @return the stall flag
     */
    public boolean isNodeStall() {
        return isStall;
    }

    /**
     * @return the vendorCV
     */
    public VendorCvData getVendorCV() {
        return vendorCV;
    }

    /**
     * @param vendorCV
     *            the vendorCV to set
     */
    public void setVendorCV(VendorCvData vendorCV) {
        LOGGER.debug("Set the vendorCV: {}", vendorCV);
        this.vendorCV = vendorCV;
    }

    public CvDefinitionTreeTableModel getCvDefinitionTreeTableModel() {
        if (treeModel == null) {
            prepareVendorCVTree();
        }
        return treeModel;
    }

    public List getConfigVariables() {
        return configVariables;
    }

    public Map getCvNumberToNodeMap() {
        return cvNumberToNodeMap;
    }

    public void prepareVendorCVTree() {
        if (vendorCV == null) {
            LOGGER.info("No vendorCV definition available for node: {}", node);
            return;
        }
        LOGGER.info("Prepare the vendorCV tree for node: {}", node);

        cvRootNode = new DeviceNode(new Object[] { "root" });
        treeModel = new CvDefinitionTreeTableModel(cvRootNode);
        treeModel.setColumnIdentifiers(Arrays.asList(Resources.getString(getClass(), "column.cv"),
            Resources.getString(getClass(), "column.description"), Resources.getString(getClass(), "column.value"),
            Resources.getString(getClass(), "column.newvalue"), Resources.getString(getClass(), "column.mode")));

        cvNumberToNodeMap = new LinkedHashMap();

        List nodes = vendorCV.getVendorCV().getCVDefinition().getNode();

        Map templatesMap = new HashMap();
        if (vendorCV.getVendorCV().getTemplates() != null) {
            for (TemplateType template : vendorCV.getVendorCV().getTemplates().getTemplate()) {
                LOGGER.trace("Add template: {}", template.getName());
                templatesMap.put(template.getName(), template);
            }
            LOGGER.trace("Prepared templatesMap: {}", templatesMap.keySet());
        }
        else {
            LOGGER.info("No templates available.");
        }

        String lang = XmlLocaleUtils.getXmlLocale();
        configVariables =
            new CvDefinitionTreeHelper().addSubNodes(cvRootNode, nodes, treeModel, templatesMap, null, null, false,
                lang, cvNumberToNodeMap);
    }

    private void fireAddressMessagesEnabledChanged(Boolean isAddressMessagesEnabled) {
        for (NodeListener l : listeners) {
            l.addressMessagesEnabledChanged(isAddressMessagesEnabled);
        }
    }

    private void fireDccStartEnabledChanged(Boolean isDccStartEnabled) {
        for (NodeListener l : listeners) {
            l.dccStartEnabledChanged(isDccStartEnabled);
        }
    }

    private void fireRailComPlusAvailableChanged(Boolean railComPlusAvailable) {
        for (NodeListener l : listeners) {
            l.railComPlusAvailableChanged(railComPlusAvailable);
        }
    }

    private void firePomUpdateAvailableChanged(Boolean pomUpdateAvailable) {
        for (NodeListener l : listeners) {
            l.pomUpdateAvailableChanged(pomUpdateAvailable);
        }
    }

    private void fireExternalStartEnabledChanged(Boolean isExternalStartEnabled) {
        for (NodeListener l : listeners) {
            l.externalStartEnabledChanged(isExternalStartEnabled);
        }
    }

    private void fireFeedbackMessagesEnabledChanged(Boolean isFeedbackMessagesEnabled) {
        for (NodeListener l : listeners) {
            l.feedbackMessagesEnabledChanged(isFeedbackMessagesEnabled);
        }
    }

    private void fireIdentifyStateChanged(IdentifyState identifyState) {
        for (NodeListener l : listeners) {
            l.identifyStateChanged(identifyState);
        }
    }

    private void fireSysErrorChanged(SysErrorEnum sysError) {
        for (NodeListener l : listeners) {
            l.sysErrorChanged(sysError);
        }
    }

    private void fireKeyMessagesEnabledChanged(Boolean isKeyMessagesEnabled) {
        for (NodeListener l : listeners) {
            l.keyMessagesEnabledChanged(isKeyMessagesEnabled);
        }
    }

    private void fireLabelChanged(String label) {
        for (NodeListener l : listeners) {
            l.labelChanged(label);
        }
    }

    public boolean equals(Object other) {
        LOGGER.debug("equals, other: {}", other);
        if (other != null) {
            return ((Node) other).hashCode() == hashCode();
        }
        return false;
    }

    public int hashCode() {
        if (node != null) {
            return Long.valueOf(getNode().getUniqueId()).hashCode();
        }
        return super.hashCode();
    }

    public String toString() {
        String result = null;

        if (StringUtils.isNotBlank(label)) {
            result = label;
        }
        else {
            result = NodeUtils.getUniqueIdAsString(node.getUniqueId());
        }
        return result;
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        LOGGER.info("The property has been changed, name: {}, new value: {}", evt.getPropertyName(), evt.getNewValue());

        // TODO signal changes and error to UI
        switch (evt.getPropertyName()) {
            case GenericPort.PROPERTY_PORT_CONFIG_ERRORCODE:
                break;
            default:
                break;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy