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

org.bidib.wizard.mvc.position.model.FeedbackPositionModel Maven / Gradle / Ivy

There is a newer version: 2.0.29
Show newest version
package org.bidib.wizard.mvc.position.model;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.function.IntFunction;
import java.util.stream.Stream;

import javax.swing.SwingUtilities;

import org.apache.commons.collections4.CollectionUtils;
import org.bidib.jbidibc.core.schema.bidibbase.BaseLabel;
import org.bidib.jbidibc.messages.enums.PositionLocationEnum;
import org.bidib.jbidibc.messages.utils.ByteUtils;
import org.bidib.wizard.api.model.NodeInterface;
import org.bidib.wizard.api.model.PositionAddressData;
import org.bidib.wizard.api.model.PositionFeedbackPort;
import org.bidib.wizard.api.model.RfBasisNode;
import org.bidib.wizard.api.model.listener.PortListListener;
import org.bidib.wizard.model.status.FeedbackPortStatus;
import org.bidib.wizard.mvc.position.controller.FeedbackPositionStatusChangeProvider;
import org.bidib.wizard.mvc.position.model.listener.FeedbackPositionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jgoodies.binding.beans.Model;

public class FeedbackPositionModel extends Model implements FeedbackPositionStatusChangeProvider {

    private static final long serialVersionUID = 1L;

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

    public static final String PROPERTY_PORT_LIST = "portList";

    public static final String PROPERTY_RFBASIS_NODES = "rfBasisNodes";

    private PropertyChangeListener pclFeedbackPorts;

    private final List feedbackPositionListeners = new LinkedList<>();

    private List portList = new LinkedList<>();

    private final List portListListeners = new LinkedList<>();

    private List rfBasisNodes = new LinkedList<>();

    private long uniqueId;

    private final PropertyChangeListener pclBaseNumber;

    private final IntFunction labelFunction;

    public FeedbackPositionModel(final IntFunction labelFunction) {
        LOGGER.info("Create new instance of FeedbackPositionModel.");
        this.labelFunction = labelFunction;

        pclFeedbackPorts = new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                LOGGER.debug("Property has changed, evt: {}", evt);
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {

                        for (PortListListener listener : portListListeners) {
                            LOGGER.debug("Notify listener that the ports have changed: {}", listener);
                            listener.listChanged();
                        }
                    }
                });
            }
        };

        addPropertyChangeListener(pclFeedbackPorts);

        pclBaseNumber = new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                LOGGER.info("The base number has changed on node: {}", evt.getSource());
                if (evt.getSource() instanceof NodeInterface) {
                    NodeInterface rfBasisNode = (NodeInterface) evt.getSource();
                    checkForSingleOrMasterBasis(rfBasisNode);
                }
            }
        };
    }

    private void checkForSingleOrMasterBasis(final NodeInterface rfBasisNode) {
        int baseNumber = rfBasisNode.getBaseNumber();
        LOGGER.info("Set the base number on the rfBasisNode: {}", baseNumber);

        if (baseNumber == 0 || baseNumber == 1) {
            LOGGER.info("This is the single or master basis.");

            long uniqueId = rfBasisNode.getUniqueId();
            LOGGER.info("Set the uniqueId in the feedbackPositionModel: {}", ByteUtils.formatHexUniqueId(uniqueId));
            setNodeUnique(uniqueId);
        }
    }

    /**
     * Set the uniqueId of the single or master basis.
     * 
     * @param uniqueId
     *            the uniqueId
     */
    public void setNodeUnique(long uniqueId) {
        LOGGER.info("Set the uniqueId: {}", uniqueId);
        this.uniqueId = uniqueId;
    }

    private long getUniqueId() {
        return uniqueId;
    }

    public void addPosition(
        byte[] address, int decoderAddress, PositionLocationEnum locationType, int locationAddress,
        byte[] extendedData) {
        LOGGER
            .info("Add position, locationType: {}, locationAddress: {}, decoderAddress: {}", locationType,
                locationAddress, decoderAddress);

        synchronized (portList) {

            // try to find the previous assigned position for the decoder address
            Stream prevPort = portList.stream().filter(p -> {
                for (PositionAddressData ad : p.getAddresses()) {
                    if (decoderAddress == ad.getDecoderAddress()) {
                        return true;
                    }
                }
                return false;
            });
            long lastSeenTimestamp = System.currentTimeMillis();
            PositionAddressData positionAddressData = new PositionAddressData(decoderAddress, lastSeenTimestamp);
            prevPort.iterator().forEachRemaining(p -> {
                p.removeAddress(positionAddressData);
                if (!p.hasAddresses()) {
                    p.setStatus(FeedbackPortStatus.FREE);
                }
            });

            // search for existing location address in list
            Optional port =
                portList.stream().filter(p -> p.getId() == locationAddress).findFirst();
            if (port.isPresent()) {

                port.get().addAddress(positionAddressData);
                port.get().setStatus(FeedbackPortStatus.OCCUPIED);
            }
            else {
                PositionFeedbackPort newPort = new PositionFeedbackPort(locationAddress);

                if (getUniqueId() > 0) {
                    try {
                        BaseLabel label = labelFunction.apply(newPort.getId());
                        LOGGER.info("New port, id: {}, current label: {}", newPort.getId(), label);
                        newPort.setLabel(label != null ? label.getLabel() : null);
                    }
                    catch (Exception ex) {
                        LOGGER.warn("Set the label of the feedback position port failed.", ex);
                    }
                }
                else {
                    LOGGER.info("No feedbackPortLabels or no uniqueId.");
                }
                newPort.addAddress(positionAddressData);
                newPort.setStatus(FeedbackPortStatus.OCCUPIED);
                LOGGER.debug("Created new port to add to portList: {}", newPort);
                portList.add(newPort);
            }
        }

        firePropertyChange(PROPERTY_PORT_LIST, null, portList);
    }

    public List getPortList() {
        return portList;
    }

    /**
     * @return the rfBasisNodes
     */
    public List getRfBasisNodes() {
        synchronized (rfBasisNodes) {
            return Collections.unmodifiableList(rfBasisNodes);
        }
    }

    /**
     * @param rfBasisNodes
     *            the rfBasisNodes to set
     */
    public void setRfBasisNodes(List rfBasisNodes) {

        synchronized (rfBasisNodes) {
            this.rfBasisNodes.clear();
            if (CollectionUtils.isNotEmpty(rfBasisNodes)) {
                this.rfBasisNodes.addAll(rfBasisNodes);

                // add listener
                for (RfBasisNode rfBasisNode : rfBasisNodes) {
                    addBaseNumberListener(rfBasisNode);
                }
            }
        }

        firePropertyChange(PROPERTY_RFBASIS_NODES, null, this.rfBasisNodes);
    }

    /**
     * @param rfBasisNode
     *            the rfBasisNode to add
     */
    public void addRfBasisNode(final RfBasisNode rfBasisNode) {

        synchronized (rfBasisNodes) {
            this.rfBasisNodes.add(rfBasisNode);

            addBaseNumberListener(rfBasisNode);

            checkForSingleOrMasterBasis(rfBasisNode.getNode());
        }

        firePropertyChange(PROPERTY_RFBASIS_NODES, null, rfBasisNodes);
    }

    /**
     * @param rfBasisNode
     *            the rfBasisNode to remove
     */
    public void removeRfBasisNode(final RfBasisNode rfBasisNode) {
        synchronized (rfBasisNodes) {
            this.rfBasisNodes.remove(rfBasisNode);

            removeBaseNumberListener(rfBasisNode);
        }

        firePropertyChange(PROPERTY_RFBASIS_NODES, null, rfBasisNodes);
    }

    private void addBaseNumberListener(final RfBasisNode rfBasisNode) {
        rfBasisNode.getNode().addPropertyChangeListener(NodeInterface.PROPERTY_BASENUMBER, pclBaseNumber);
    }

    private void removeBaseNumberListener(final RfBasisNode rfBasisNode) {
        rfBasisNode.getNode().removePropertyChangeListener(NodeInterface.PROPERTY_BASENUMBER, pclBaseNumber);
    }

    @Override
    public void addFeedbackPortListener(final FeedbackPositionListener feedbackPositionListener) {
        feedbackPositionListeners.add(feedbackPositionListener);
    }

    @Override
    public void removeFeedbackPortListener(final FeedbackPositionListener feedbackPositionListener) {
        feedbackPositionListeners.remove(feedbackPositionListener);
    }

    @Override
    public void addPortListListener(PortListListener portListListener) {
        portListListeners.add(portListListener);
    }

    @Override
    public void removePortListListener(PortListListener portListListener) {
        portListListeners.remove(portListListener);
    }

    public void clearAddressesAndPortStatus() {

        synchronized (portList) {
            for (PositionFeedbackPort port : portList) {

                port.setStatus(FeedbackPortStatus.FREE);
                port.clear();
            }
        }
        firePropertyChange(PROPERTY_PORT_LIST, null, portList);
    }

    public void validatePositions(final List outdatedPorts, long timeout) {

        synchronized (portList) {

            for (PositionFeedbackPort port : portList) {

                if (port.getStatus() == FeedbackPortStatus.OCCUPIED) {
                    boolean outdated = port.isOutdated(timeout);
                    if (outdated) {
                        outdatedPorts.add(port);
                    }
                }
            }
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy