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

org.bidib.wizard.mvc.loco.controller.LocoController Maven / Gradle / Ivy

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

import java.awt.Window;
import java.util.BitSet;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.bidib.jbidibc.messages.AddressData;
import org.bidib.jbidibc.messages.enums.PositionLocationEnum;
import org.bidib.jbidibc.messages.exception.NoAnswerException;
import org.bidib.jbidibc.messages.helpers.Context;
import org.bidib.jbidibc.messages.helpers.DefaultContext;
import org.bidib.jbidibc.messages.utils.ProductUtils;
import org.bidib.jbidibc.messages.utils.ThreadFactoryBuilder;
import org.bidib.wizard.api.model.CommandStationNodeInterface;
import org.bidib.wizard.api.model.NodeInterface;
import org.bidib.wizard.api.model.NodeProvider;
import org.bidib.wizard.api.model.connection.AbstractMessageEvent;
import org.bidib.wizard.api.model.connection.BidibConnection;
import org.bidib.wizard.api.model.connection.event.OccupancyCvMessageEvent;
import org.bidib.wizard.api.model.connection.event.OccupancyDynStateMessageEvent;
import org.bidib.wizard.api.model.connection.event.OccupancyPositionMessageEvent;
import org.bidib.wizard.api.model.connection.event.OccupancySpeedMessageEvent;
import org.bidib.wizard.api.service.console.ConsoleColor;
import org.bidib.wizard.api.service.console.ConsoleService;
import org.bidib.wizard.api.service.core.LocoService;
import org.bidib.wizard.api.service.node.CommandStationService;
import org.bidib.wizard.client.common.uils.SwingUtils;
import org.bidib.wizard.client.common.view.WindowUtils;
import org.bidib.wizard.common.exception.ConnectionException;
import org.bidib.wizard.common.service.SettingsService;
import org.bidib.wizard.core.model.connection.ConnectionRegistry;
import org.bidib.wizard.core.model.connection.MessageEventConsumer;
import org.bidib.wizard.core.service.ConnectionService;
import org.bidib.wizard.model.loco.LocoModel;
import org.bidib.wizard.model.loco.listener.LocoModelListener;
import org.bidib.wizard.model.locolist.LocoListModel;
import org.bidib.wizard.model.status.CommandStationStatus;
import org.bidib.wizard.model.status.DirectionStatus;
import org.bidib.wizard.model.status.RfBasisMode;
import org.bidib.wizard.model.status.SpeedSteps;
import org.bidib.wizard.mvc.common.DialogRegistry;
import org.bidib.wizard.mvc.common.view.RegisteredDialog;
import org.bidib.wizard.mvc.common.view.ViewCloseListener;
import org.bidib.wizard.mvc.console.controller.ConsoleController;
import org.bidib.wizard.mvc.loco.model.LocoConfigModel;
import org.bidib.wizard.mvc.loco.view.LocoDialog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;

/**
 * The {@code LocoController} is a prototype bean and will be created per loco dialog instance.
 */
public class LocoController {
    private static final Logger LOGGER = LoggerFactory.getLogger(LocoController.class);

    private final CommandStationNodeInterface node;

    private final JFrame parent;

    private final LocoConfigModel locoConfigModel = new LocoConfigModel();

    // private LocoModel locoModel;

    private LocoDialog locoDialog;

    private LocoModelListener locoModelListener;

    @Autowired
    private ConnectionService connectionService;

    @Autowired
    private CommandStationService commandStationService;

    @Autowired
    private LocoService locoService;

    @Autowired
    private SettingsService settingsService;

    @Autowired
    private ConsoleService consoleService;

    private CompositeDisposable compDispMessages;

    private final NodeProvider nodeProvider;

    /**
     * worker to deactivate the dcc accessories
     */
    private /* final */ ScheduledExecutorService commandStationStatusWorker;

    private /* final */ ScheduledExecutorService commandStationSpeedWorker;

    private final DialogRegistry dialogRegistry;

    public LocoController(final CommandStationNodeInterface node, JFrame parent, final NodeProvider nodeProvider,
        DialogRegistry dialogRegistry) {
        this.node = node;
        this.parent = parent;
        this.nodeProvider = nodeProvider;
        this.dialogRegistry = dialogRegistry;

        this.compDispMessages = new CompositeDisposable();
    }

    /**
     * Start the loco controller.
     */
    public void start(
        final AddressData initialAddress, final SpeedSteps speedSteps, final LocoListModel locoListModel) {
        LOGGER.info("Current connectionService: {}", connectionService);

        Integer searchLocoAddress = null;
        if (locoListModel != null) {
            searchLocoAddress = locoListModel.getAddress();
        }
        else if (initialAddress != null) {
            searchLocoAddress = initialAddress.getAddress();
        }

        // check if a loco dialog with the same address exists
        if (CollectionUtils.isNotEmpty(dialogRegistry.getDialogRegistry())) {
            String searchKey = LocoDialog.prepareKey(searchLocoAddress);
            RegisteredDialog existingDialog =
                IterableUtils.find(dialogRegistry.getDialogRegistry(), new Predicate() {

                    @Override
                    public boolean evaluate(RegisteredDialog dialog) {
                        return searchKey.equals(dialog.getKey());
                    }
                });

            if (existingDialog != null) {
                LOGGER.info("Found existing dialog: {}", existingDialog);

                try {
                    if (SystemUtils.IS_OS_WINDOWS) {
                        WindowUtils.bringWindowToFront((Window) existingDialog);
                    }
                    else {
                        ((Window) existingDialog).toFront();
                    }
                }
                catch (Exception ex) {
                    LOGGER.warn("Bring the existing dialog to front failed.");
                }
                return;
            }
            else {
                LOGGER.info("No existing dialog found.");
            }
        }

        // initialize the controller

        if (ProductUtils.isRFBasisNode(node.getNode().getUniqueId())
            || ProductUtils.isSpeedometer(node.getNode().getUniqueId())) {
            LOGGER.info("The default speed steps for the decoders on the RF Basis Node or Speedometer is 128.");
            locoConfigModel
                .setSpeedSteps(
                    speedSteps != null ? speedSteps : settingsService.getWizardSettings().getLastSelectedSpeedSteps());
            locoConfigModel.setCarControlEnabled(true);
        }
        else {
            locoConfigModel
                .setSpeedSteps(
                    speedSteps != null ? speedSteps : settingsService.getWizardSettings().getLastSelectedSpeedSteps());
        }

        final LocoModel locoModel;

        if (locoListModel != null) {
            LOGGER.info("Create new locoModel with locoListModel: {}", locoListModel);
            // copy the values from the locoListModel to the locoModel
            locoModel = new LocoModel(locoListModel);

            locoConfigModel.setSpeedSteps(locoModel.getSpeedSteps());
        }
        else if (initialAddress != null) {
            LOGGER.info("Create new locoModel from the provided initial address: {}", initialAddress);

            final LocoListModel llm =
                this.locoService
                    .getOrCreateLoco(ConnectionRegistry.CONNECTION_ID_MAIN, this.node, initialAddress.getAddress());

            locoModel = new LocoModel(llm);
            locoConfigModel.setSpeedSteps(locoModel.getSpeedSteps());
        }
        else {
            LOGGER.info("Create new empty locoModel with default speedSteps.");
            locoModel = new LocoModel(null);
            locoModel.setSpeedSteps(locoConfigModel.getSpeedSteps());
        }

        prepareMessageMap(locoModel);

        try {
            final CompositeDisposable disp = new CompositeDisposable();

            Disposable dispConnStatus = connectionService.subscribeConnectionStatusChanges(connectionInfo -> {

                if (connectionInfo.getConnectionId().equals(ConnectionRegistry.CONNECTION_ID_MAIN)) {
                    LOGGER.info("Current state: {}", connectionInfo.getConnectionState());

                    switch (connectionInfo.getConnectionState().getActualPhase()) {
                        case CONNECTED:
                            LOGGER.info("The connection was opened.");

                            registerForMessages();

                            break;
                        case DISCONNECTED:
                            LOGGER.info("The connection was closed.");

                            compDispMessages.dispose();

                            if (locoDialog != null) {
                                locoDialog.close(LocoController.this.settingsService);

                                locoDialog = null;
                            }
                            disp.dispose();
                            break;
                        default:
                            break;
                    }
                }

            }, error -> {
                LOGGER.warn("The connection status change caused an error.", error);
            });
            disp.add(dispConnStatus);
        }
        catch (Exception ex) {
            LOGGER.warn("Register controller as node listener failed.", ex);
        }

        try {
            LOGGER.info("Check if the connection is connected already.");
            boolean isConnected = connectionService.isConnected(ConnectionRegistry.CONNECTION_ID_MAIN);
            if (isConnected) {
                registerForMessages();
            }
        }
        catch (Exception ex) {
            LOGGER.warn("Register for messages failed.", ex);
        }

        LOGGER.info("Create new instance of LocoDialog.");
        final LocoControlListener locoControlListener = new LocoControlListener() {

            @Override
            public void setSpeed(Integer speed, DirectionStatus direction) {
                // LOGGER.info("Set speed: {}, direction: {}", speed, direction);

                LocoController.this.setSpeed(locoModel, speed, direction);
            }

            @Override
            public void setFunction(int index, boolean value) {
                LOGGER.info("Set function is called, index: {}, value: {}", index, value);

                // Prepare the function group index
                int functionGroupIndex = 0;

                if (index < 5) {
                    functionGroupIndex = 0;
                }
                else if (index < 9) {
                    functionGroupIndex = 1;
                }
                else if (index < 13) {
                    functionGroupIndex = 2;
                }
                else if (index < 21) {
                    functionGroupIndex = 3;
                }
                else if (index < 29) {
                    functionGroupIndex = 4;
                }
                else {
                    LOGGER.warn("Function > 28 uses binary state operation.");

                    setBinaryState(index, value);
                    return;
                }

                BitSet activeFunctions = new BitSet(functionGroupIndex + 1);
                LOGGER.info("functions have changed, functionGroupIndex: {}", functionGroupIndex);
                activeFunctions.set(functionGroupIndex, true);

                if (locoModel.getAddress() == null) {
                    LOGGER.warn("No address available.");
                    return;
                }

                final Integer locoAddress = locoModel.getAddress();
                final SpeedSteps speedSteps = locoModel.getSpeedSteps();
                final DirectionStatus direction = locoModel.getDirection();
                final BitSet functions = new BitSet();
                functions.or(locoModel.getFunctions());
                functions.set(index, value);

                commandStationSpeedWorker.submit(() -> {
                    // create the context
                    final Context context = new DefaultContext();
                    registerActiveRfBasis(locoModel, context);

                    // count the CS_DRIVE messages that are sent
                    SwingUtils.executeInEDT(() -> locoModel.incCounterCsDrive());

                    commandStationService
                        .setSpeed(ConnectionRegistry.CONNECTION_ID_MAIN, node, locoAddress, speedSteps, null, direction,
                            activeFunctions, functions, context);
                });
            }

            @Override
            public void setBinaryState(int stateNumber, boolean value) {
                LOGGER
                    .info("Send the binary state, dccAddress: {}, stateNumber: {}, value: {}", locoModel.getAddress(),
                        stateNumber, value);

                if (locoModel.getAddress() == null) {
                    LOGGER.warn("No address available.");
                    return;
                }

                // we must send the binary state for the change of active RF base to all bases but the others
                // only to the selected base

                final Context context = new DefaultContext();

                boolean baseChanged = false;

                // special handling for cars
                if (locoConfigModel.isCarControlEnabled()) {

                    if (stateNumber < 512 || stateNumber > 517) {
                        // normal binary function operations --> send to active base
                        registerActiveRfBasis(locoModel, context);
                    }
                    else if (locoModel.getActiveBase() != null) {
                        // we must send the current speed and functions to the new basis before we switch to the new
                        // basis
                        int functionGroupIndex = 4;
                        BitSet activeFunctions = new BitSet(functionGroupIndex + 1);
                        LOGGER.debug("functions have changed, functionGroupIndex: {}", functionGroupIndex);
                        activeFunctions.set(0, functionGroupIndex, true);

                        LOGGER
                            .info(
                                "The active RF basis is switched. Send the current speed data to the new RF basis before switch the decoder to the new basis: {}",
                                locoModel.getActiveBase());

                        Integer speed = locoModel.getSpeed();
                        if (speed != null) {

                            // no speed conversion for stop and emergency stop
                            if (speed > 1) {
                                // for 14/28 speedSteps we must calc the value based on 128 speed steps
                                switch (locoModel.getSpeedSteps()) {
                                    case DCC28:
                                        speed = (speed * 127) / 28;
                                        break;
                                    case DCC14:
                                        speed = (speed * 127) / 14;
                                        break;
                                    default:
                                        break;
                                }
                            }
                        }

                        // let execute this in a worker
                        final Integer speedValue = speed;

                        final Integer locoAddress = locoModel.getAddress();
                        final SpeedSteps speedSteps = locoModel.getSpeedSteps();
                        final DirectionStatus direction = locoModel.getDirection();
                        final BitSet functions = locoModel.getFunctions();

                        commandStationSpeedWorker.submit(() -> {
                            registerActiveRfBasis(locoModel, context);

                            // count the CS_DRIVE messages that are sent
                            SwingUtils.executeInEDT(() -> locoModel.incCounterCsDrive());

                            commandStationService
                                .setSpeed(ConnectionRegistry.CONNECTION_ID_MAIN, node, locoAddress, speedSteps,
                                    speedValue, direction, activeFunctions, functions, context);
                        });

                        baseChanged = true;
                    }
                }

                if (baseChanged) {
                    LOGGER.info("Send the binary state to all bases because we change the active RF basis.");
                    final Integer locoAddress = locoModel.getAddress();

                    commandStationSpeedWorker.submit(() -> {
                        final Context localContext = new DefaultContext();

                        // count the CS_BIN_STATE messages that are sent
                        locoModel.incCounterCsBinState();

                        // set the binary state
                        commandStationService
                            .setBinaryState(ConnectionRegistry.CONNECTION_ID_MAIN, node, locoAddress, stateNumber,
                                value, localContext);
                    });
                }
                else {
                    final Integer locoAddress = locoModel.getAddress();

                    commandStationSpeedWorker.submit(() -> {
                        // count the CS_BIN_STATE messages that are sent
                        locoModel.incCounterCsBinState();

                        // set the binary state
                        commandStationService
                            .setBinaryState(ConnectionRegistry.CONNECTION_ID_MAIN, node, locoAddress, stateNumber,
                                value, context);
                    });
                }

                if (baseChanged && locoModel.getPrevActiveBase() != null
                    && locoModel.getPrevActiveBase() != RfBasisMode.SINGLE) {

                    final Integer locoAddress = locoModel.getAddress();
                    final SpeedSteps speedSteps = locoModel.getSpeedSteps();
                    final DirectionStatus direction = locoModel.getDirection();

                    commandStationSpeedWorker.submit(() -> {
                        LOGGER.info("Clear decoder from prev active base: {}", locoModel.getPrevActiveBase());
                        final Context localContext = new DefaultContext();
                        registerPrevActiveRfBasis(locoModel, localContext);

                        // count the CS_DRIVE messages that are sent
                        SwingUtils.executeInEDT(() -> locoModel.incCounterCsDrive());

                        commandStationService
                            .setSpeed(ConnectionRegistry.CONNECTION_ID_MAIN, node, locoAddress, speedSteps, null,
                                direction, null, null, localContext);

                        locoModel.resetPrevActiveBase();
                    });
                }
            }

            @Override
            public void setSpeedSteps(SpeedSteps speedSteps) {
                // LOGGER.info("Set the speedSteps: {}", speedSteps);

                LocoController.this.setSpeedSteps(locoModel, speedSteps);
            };

            @Override
            public void clearLoco() {

                if (locoModel.getAddress() == null) {
                    LOGGER.warn("No address available.");
                    return;
                }

                final Integer locoAddress = locoModel.getAddress();
                final SpeedSteps speedSteps = locoModel.getSpeedSteps();

                commandStationSpeedWorker.submit(() -> {
                    // create the context
                    final Context context = new DefaultContext();
                    registerActiveRfBasis(locoModel, context);

                    // count the CS_DRIVE messages that are sent
                    SwingUtils.executeInEDT(() -> locoModel.incCounterCsDrive());

                    commandStationService
                        .clearLoco(ConnectionRegistry.CONNECTION_ID_MAIN, node, locoAddress, speedSteps, context);
                });

            };
        };

        locoDialog =
            new LocoDialog(parent, locoModel, locoConfigModel, settingsService, locoControlListener,
                lm -> registerLocoModelListener(lm), newLocoAddress -> changeLocoAddress(locoModel, newLocoAddress));

        locoDialog.addViewCloseListener(new ViewCloseListener() {

            @Override
            public void close() {
                LOGGER.info("The locoView is closed.");
                // unregisterMessageListener(messageListener, communication);

                RegisteredDialog registeredDialog = null;
                // release locoView
                if (locoDialog != null) {
                    registeredDialog = locoDialog;
                    locoDialog = null;
                }

                if (locoModelListener != null) {
                    LOGGER.info("Remove locoModelListener from model.");
                    locoModel.removeLocoModelListener(locoModelListener);
                    locoModelListener = null;
                }

                locoModel.cleanup();

                unregisterView(registeredDialog);
            }
        });

        // // Register the loco dialog
        LOGGER.info("Register the LocoDialog in the dialog registry: {}", locoDialog);
        dialogRegistry.getDialogRegistry().add(locoDialog);

        // query the current state of the command station
        try {

            if (node.getCommandStationStatus() == null) {
                LOGGER.info("Subscribe to command station status changes.");
                final CompositeDisposable disp = new CompositeDisposable();

                Disposable dispCsState = node.subscribeSubjectCommandStationState(csState -> {

                    LOGGER.info("Current command station state: {}", csState);

                    // this will start the command station if it was stopped
                    if (CommandStationStatus.isOffState(csState)) {
                        LOGGER.info("Set the command station to status GO.");

                        if (commandStationStatusWorker == null) {
                            commandStationStatusWorker =
                                Executors
                                    .newScheduledThreadPool(1, new ThreadFactoryBuilder()
                                        .setNameFormat("commandStationStatusWorkers-thread-%d").build());
                        }

                        // Must not set the command station status from receiveQueueWorker !
                        commandStationStatusWorker.submit(() -> {

                            commandStationService
                                .setCommandStationState(ConnectionRegistry.CONNECTION_ID_MAIN, node,
                                    CommandStationStatus.GO);
                        });
                    }
                    disp.dispose();
                }, error -> {

                    LOGGER.warn("Get the current command station state failed.");
                    disp.dispose();
                }, () -> {
                    LOGGER.warn("Get the current command station state subscription has completed, node: {}", node);
                });
                disp.add(dispCsState);

                commandStationService.queryCommandStationState(ConnectionRegistry.CONNECTION_ID_MAIN, node);
            }
        }
        catch (Exception ex) {
            LOGGER.warn("Get command station state failed.", ex);
        }
    }

    public void registerLocoModelListener(final LocoModel locoModel) {
        LOGGER.info("Register the locoModel listener for locoModel: {}", locoModel);

        // TODO the locoModelListener must be assigned to the locoModel

        if (commandStationSpeedWorker == null) {

            commandStationSpeedWorker =
                Executors
                    .newScheduledThreadPool(1,
                        new ThreadFactoryBuilder().setNameFormat("commandStationSpeedWorkers-thread-%d").build());
        }
    }

    private void setSpeed(final LocoModel locoModel, Integer speed, DirectionStatus directionStatus) {
        LOGGER.info("Set loco speed: {}, direction: {}", speed, directionStatus);

        if (locoModel.getAddress() == null) {
            LOGGER.warn("No address available.");
            return;
        }

        // set the speed
        if (speed != null) {

            final Integer locoAddress = locoModel.getAddress();
            final SpeedSteps speedSteps = locoModel.getSpeedSteps();
            if (directionStatus != null) {
                locoModel.setDirection(directionStatus);
            }
            final DirectionStatus direction = locoModel.getDirection();

            // no speed conversion for stop and emergency stop
            if (speed > 1) {
                // for 14/28 speedSteps we must calc the value based on 128 speed steps
                switch (speedSteps) {
                    case DCC28:
                        speed = (speed * 127) / 28;
                        break;
                    case DCC14:
                        speed = (speed * 127) / 14;
                        break;
                    default:
                        break;
                }
            }

            LOGGER
                .info(
                    "The speed has changed in the locoModel. Send the new speed value: {}, direction: {}, address: {}, speedSteps: {}",
                    speed, direction, locoAddress, speedSteps);

            // let execute this in a worker
            final Integer speedValue = speed;

            commandStationSpeedWorker.submit(() -> {

                try {
                    // create the context
                    final Context context = new DefaultContext();
                    registerActiveRfBasis(locoModel, context);

                    // count the CS_DRIVE messages that are sent
                    SwingUtils.executeInEDT(() -> locoModel.incCounterCsDrive());

                    commandStationService
                        .setSpeed(ConnectionRegistry.CONNECTION_ID_MAIN, node, locoAddress, speedSteps, speedValue,
                            direction, null, null, context);
                }
                catch (NoAnswerException ex) {
                    LOGGER.warn("Set speed failed.", ex);

                    SwingUtilities.invokeLater(() -> {
                        ConsoleController.ensureConsoleVisible();
                        if (StringUtils.isNotBlank(ex.getMessage())) {
                            consoleService.addConsoleLine(ConsoleColor.red, ex.getMessage());
                        }
                        else {
                            consoleService.addConsoleLine(ConsoleColor.red, "Set speed failed.");
                        }
                    });
                }
                catch (Exception ex) {
                    LOGGER.warn("Set speed failed.", ex);
                }
            });
        }
        else {
            LOGGER.debug("No speed value in model.");
        }
    }

    private void setSpeedSteps(final LocoModel locoModel, final SpeedSteps speedSteps) {
        LOGGER.info("Set the speedSteps: {}, locoModel: {}", speedSteps, locoModel);
        locoModel.setSpeedSteps(speedSteps);
    }

    private void changeLocoAddress(final LocoModel locoModel, final Integer locoAddress) {
        LOGGER.info("Change the locoAddress: {}", locoAddress);

        if (locoAddress != null) {
            LocoListModel locoListModel =
                locoService.getOrCreateLoco(ConnectionRegistry.CONNECTION_ID_MAIN, node, locoAddress);
            locoModel.setLocoListModel(locoListModel);
        }
        else {
            // reset the loco
            locoModel.setLocoListModel(null);
        }

        // must reset the reported cell number
        locoModel.setReportedCellNumber(null);
    }

    private void registerForMessages() {
        LOGGER.info("Register for messages from the connection.");
        // register for messages from the connection
        try {
            BidibConnection connection = connectionService.find(ConnectionRegistry.CONNECTION_ID_MAIN);
            Disposable dispMessages = connection.getSubjectMessages().subscribe(msg -> {
                handleBidibMessageEvent(msg);
            });

            compDispMessages.add(dispMessages);
        }
        catch (ConnectionException ex) {
            LOGGER.warn("No connection found, register on messages is skipped.", ex);
        }
    }

    private final Map, MessageEventConsumer> messageActionMap =
        new HashMap<>();

    private void prepareMessageMap(final LocoModel locoModel) {
        LOGGER.info("Prepare the message map.");

        // occupancy
        messageActionMap.put(OccupancySpeedMessageEvent.class, (evt, node) -> {
            OccupancySpeedMessageEvent event = (OccupancySpeedMessageEvent) evt;

            // TODO this should be moved to DefaultLocoService

            // final AddressData addressData = event.getAddressData();
            // if (locoModel.getAddress() != null && addressData.getAddress() == locoModel.getAddress()) {
            // int speed = event.getSpeed();
            //
            // LOGGER.info("Update the reported speed: {}", speed);
            // SwingUtils.executeInEDT(() -> locoModel.setReportedSpeed(speed));
            // }
        });

        messageActionMap.put(OccupancyDynStateMessageEvent.class, (evt, node) -> {
            OccupancyDynStateMessageEvent event = (OccupancyDynStateMessageEvent) evt;
            final AddressData decoderAddress = event.getDecoderAddress();
            int dynNumber = event.getDynNumber();
            final int dynValue = event.getDynValue();

            LOGGER
                .info("dynState, decoderAddress: {}, dynNumber: {}, dynValue: {}", decoderAddress, dynNumber, dynValue);

            // TODO this should be moved to DefaultLocoService

            // TODO must check the address and the address of the selected node
            if (locoModel.getAddress() != null && decoderAddress.getAddress() == locoModel.getAddress()
                && dynNumber == 3) {
                // LOGGER.info("The dynState is forwarded to model");
                SwingUtils.executeInEDT(() -> locoModel.setDynStateEnergy(dynValue));
            }
            else {
                LOGGER.debug("The dynState ist not forwarded to model");
            }

        });

        messageActionMap.put(OccupancyCvMessageEvent.class, (evt, node) -> {
            OccupancyCvMessageEvent event = (OccupancyCvMessageEvent) evt;

            LOGGER.info("Received new occupancy CV event: {}", event);

            LOGGER.warn("The occupancy CV event is not processed and discarded: {}", event);
        });

        // add message events for occupancy position
        messageActionMap.put(OccupancyPositionMessageEvent.class, (evt, node) -> {
            OccupancyPositionMessageEvent event = (OccupancyPositionMessageEvent) evt;

            LOGGER.debug("Process the event: {}", event);

            // TODO this should be moved to DefaultLocoService

            if (event.getLocationType() == PositionLocationEnum.CELL_IDENTIFIER
                && (locoModel.getAddress() != null && event.getDecoderAddress() == locoModel.getAddress())) {

                SwingUtilities.invokeLater(() -> {
                    LOGGER.info("Update the cellIdentifier: {}", event);

                    locoModel.setReportedCellNumber(event.getLocationAddress());
                });
            }
            else {
                LOGGER.debug("Do not show position feedback with type: {}", event.getLocationType());
            }
        });
    }

    private void handleBidibMessageEvent(AbstractMessageEvent event) {
        LOGGER.debug("Handle the message event: {}", event);

        // let the action update the cached value in the node
        try {
            MessageEventConsumer action = messageActionMap.get(event.getClass());
            if (action != null) {
                action.accept(event, node.getNode());
            }
            else {
                LOGGER.debug("No message event action configured for event: {}", event);
            }
        }
        catch (Exception ex) {
            LOGGER.warn("Execute the message event action failed, node: {}, event: {}", node, event, ex);
        }
    }

    private void unregisterView(RegisteredDialog view) {

        if (view != null) {
            try {
                if (CollectionUtils.isNotEmpty(dialogRegistry.getDialogRegistry())) {
                    String searchKey = view.getKey();
                    RegisteredDialog existingDialog =
                        IterableUtils.find(dialogRegistry.getDialogRegistry(), new Predicate() {

                            @Override
                            public boolean evaluate(RegisteredDialog dialog) {
                                return searchKey.equals(dialog.getKey());
                            }
                        });

                    if (existingDialog != null) {
                        LOGGER.info("Found existing dialog to unregister: {}", existingDialog);

                        dialogRegistry.getDialogRegistry().remove(existingDialog);

                        LOGGER.info("Registry after remove: {}", dialogRegistry);
                    }
                }
            }
            catch (Exception ex) {
                LOGGER.warn("Unregister view failed: {}", view, ex);
            }
        }
        else {
            LOGGER.info("No view available to unregister.");
        }
    }

    /**
     * Register the active base in the context under the key {@code activeRfBasis}.
     * 
     * @param context
     *            the context
     */
    private void registerActiveRfBasis(final LocoModel locoModel, final Context context) {

        if (locoConfigModel.isCarControlEnabled() && locoModel.getActiveBase() != null
            && locoModel.getActiveBase() != RfBasisMode.SINGLE) {

            RfBasisMode activeRfBase = locoModel.getActiveBase();
            registerRfBasisInContext(context, activeRfBase);
        }
    }

    /**
     * Register the previous active base in the context under the key {@code activeRfBasis}.
     * 
     * @param context
     *            the context
     */
    private void registerPrevActiveRfBasis(final LocoModel locoModel, final Context context) {

        if (locoConfigModel.isCarControlEnabled() && locoModel.getPrevActiveBase() != null
            && locoModel.getPrevActiveBase() != RfBasisMode.SINGLE) {

            RfBasisMode prevActiveRfBase = locoModel.getPrevActiveBase();
            registerRfBasisInContext(context, prevActiveRfBase);
        }
    }

    private void registerRfBasisInContext(final Context context, final RfBasisMode rfBase) {

        context.unregister("activeRfBasis");

        if (rfBase.getBaseNumber() != null) {
            int activeBaseNumber = rfBase.getBaseNumber();

            final NodeInterface rfBasisNode = nodeProvider.getNodes().stream().filter(bidibNode -> {
                return (ProductUtils.isRFBasisNode(bidibNode.getUniqueId())
                    && bidibNode.getBaseNumber() == activeBaseNumber);
            }).findFirst().orElse(null);

            if (rfBasisNode != null) {
                LOGGER.info("Found the active rfBasisNode: {}", rfBasisNode);

                context.register("activeRfBasis", rfBasisNode.getNode());
            }
            else {
                LOGGER.warn("No active rfBasisNode found for activeBaseNumber: {}", activeBaseNumber);
            }
        }
        else {
            LOGGER.info("No base number for active rf base available.");
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy