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

org.bidib.wizard.mvc.pom.controller.PomProgrammerController Maven / Gradle / Ivy

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

import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.swing.JFrame;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.lang3.SystemUtils;
import org.bidib.jbidibc.messages.AddressData;
import org.bidib.jbidibc.messages.PomAddressData;
import org.bidib.jbidibc.messages.enums.AddressTypeEnum;
import org.bidib.jbidibc.messages.enums.CommandStationPom;
import org.bidib.jbidibc.messages.enums.CommandStationState;
import org.bidib.jbidibc.messages.enums.PomAcknowledge;
import org.bidib.jbidibc.messages.enums.PomAddressTypeEnum;
import org.bidib.jbidibc.messages.enums.PomOperation;
import org.bidib.jbidibc.messages.enums.PomProgState;
import org.bidib.jbidibc.messages.utils.ByteUtils;
import org.bidib.jbidibc.messages.utils.NodeUtils;
import org.bidib.wizard.api.locale.Resources;
import org.bidib.wizard.api.model.BoosterNodeInterface;
import org.bidib.wizard.api.model.CommandStationNodeInterface;
import org.bidib.wizard.api.model.NodeInterface;
import org.bidib.wizard.api.model.connection.AbstractMessageEvent;
import org.bidib.wizard.api.model.connection.event.CommandStationPomAcknowledgeMessageEvent;
import org.bidib.wizard.api.model.connection.event.CommandStationStateMessageEvent;
import org.bidib.wizard.api.model.connection.event.OccupancyCvMessageEvent;
import org.bidib.wizard.api.service.node.BoosterService;
import org.bidib.wizard.api.service.node.CommandStationService;
import org.bidib.wizard.client.common.view.WindowUtils;
import org.bidib.wizard.core.model.connection.ConnectionRegistry;
import org.bidib.wizard.core.model.connection.MessageAdapter;
import org.bidib.wizard.core.model.connection.MessageEventConsumer;
import org.bidib.wizard.core.service.ConnectionService;
import org.bidib.wizard.model.status.BoosterStatus;
import org.bidib.wizard.model.status.CommandStationStatus;
import org.bidib.wizard.mvc.common.DialogRegistry;
import org.bidib.wizard.mvc.common.view.RegisteredDialog;
import org.bidib.wizard.mvc.pom.controller.listener.PomProgrammerControllerListener;
import org.bidib.wizard.mvc.pom.model.CurrentAddressBeanModel;
import org.bidib.wizard.mvc.pom.model.PomProgrammerModel;
import org.bidib.wizard.mvc.pom.view.OperationAbortedException;
import org.bidib.wizard.mvc.pom.view.PomProgrammerView;
import org.bidib.wizard.mvc.pom.view.listener.PomProgrammerViewListener;
import org.oxbow.swingbits.dialog.task.CommandLink;
import org.oxbow.swingbits.dialog.task.TaskDialogs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.vlsolutions.swing.docking.DockingDesktop;

public class PomProgrammerController {
    private static final Logger LOGGER = LoggerFactory.getLogger(PomProgrammerController.class);

    private final Collection listeners =
        new LinkedList();

    private final JFrame parent;

    private final CommandStationNodeInterface node;

    private final int x;

    private final int y;

    private final PomProgrammerModel model = new PomProgrammerModel();

    private PomProgrammerView view;

    @Autowired
    private ConnectionService connectionService;

    @Autowired
    private BoosterService boosterService;

    @Autowired
    private CommandStationService commandStationService;

    private MessageAdapter messageAdapter;

    private static AtomicBoolean singleton = new AtomicBoolean();

    private final DialogRegistry dialogRegistry;

    public PomProgrammerController(final CommandStationNodeInterface node, final DialogRegistry dialogRegistry,
        JFrame parent, int x, int y) {
        this.parent = parent;
        this.dialogRegistry = dialogRegistry;
        this.node = node;
        this.x = x;
        this.y = y;
    }

    public static boolean isOpened() {
        return singleton.get();
    }

    private void setOpened(boolean opened) {
        singleton.set(opened);
    }

    public void addPomProgrammerControllerListener(PomProgrammerControllerListener l) {
        listeners.add(l);
    }

    private void fireClose() {
        for (PomProgrammerControllerListener l : listeners) {
            l.close();
        }

        // reset the opened flag
        setOpened(false);
    }

    private void fireSendRequest(PomAddressData decoderAddress, PomOperation operation, int cvNumber, int cvValue) {

        LOGGER
            .info("Send CV request, decoder addr: {}, operation: {}, cvNumber: {}, value: {}", decoderAddress,
                operation, cvNumber, cvValue);

        CommandStationPom opCode = CommandStationPom.valueOf(ByteUtils.getLowByte(operation.getType()));

        // clear the stored cv value in the programmer model
        model.clearCvValue();

        LOGGER.info("Prepared opCode: {}", opCode);

        for (PomProgrammerControllerListener l : listeners) {
            l.sendRequest(node, decoderAddress, opCode, cvNumber, cvValue);
        }
    }

    public void start(final DockingDesktop desktop, final AddressData initialAddress) {

        this.messageAdapter = new MessageAdapter(connectionService) {

            @Override
            protected void prepareMessageMap(
                Map, MessageEventConsumer> messageActionMap) {
                LOGGER.info("Prepare the message map.");

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

                    CommandStationState commandStationState = event.getCommandStationState();
                    byte[] address = event.getAddress();

                    LOGGER
                        .info("The command station state has changed, address: {}, state: {}", address,
                            commandStationState);

                    if (Arrays.equals(node.getNode().getAddr(), address)) {
                        LOGGER.info("The state of the selected command station node has changed.");

                        model.setCommandStationState(commandStationState);
                    }
                    else {
                        LOGGER.warn("Another command station has changed the state.");
                    }
                });

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

                    byte[] address = event.getAddress();
                    PomAddressData decoderAddress = event.getAddressData();
                    PomAcknowledge pomAcknowledge = event.getPomAcknowledge();

                    LOGGER
                        .info("POM ackn was received, node addr: {}, decoder address: {}, pomAcknowledge: {}", address,
                            decoderAddress, pomAcknowledge);

                    // TODO

                });

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

                    byte[] address = event.getAddress();
                    PomAddressData decoderAddress = event.getAddressData();
                    int cvNumber = event.getCvNumber();
                    int cvData = event.getCvValue();

                    LOGGER
                        .info("CV was received, node addr: {}, decoder address: {}, cvNumber: {}, cvData: {}", address,
                            decoderAddress, cvNumber, cvData);

                    updatePomProgState(PomProgState.POM_PROG_OKAY, decoderAddress, cvNumber, cvData);
                });
            }

            @Override
            protected void onDisconnect() {

                if (view != null) {
                    view.close();

                    view = null;
                }

                super.onDisconnect();
            }
        };
        messageAdapter.setNode(node.getNode());
        messageAdapter.start();

        // create the view
        final CurrentAddressBeanModel currentAddressBeanModel = new CurrentAddressBeanModel();
        if (initialAddress != null) {
            LOGGER.info("Set the provided initial address: {}", initialAddress);
            currentAddressBeanModel.setDccAddress(initialAddress.getAddress());

            AddressTypeEnum addressTypeEnum = initialAddress.getType();
            PomAddressTypeEnum addressType = null;
            switch (addressTypeEnum) {
                case ACCESSORY:
                    addressType = PomAddressTypeEnum.ACCESSORY;
                    break;
                case EXTENDED_ACCESSORY:
                    addressType = PomAddressTypeEnum.EXTENDED_ACCESSORY;
                    break;
                default:
                    addressType = PomAddressTypeEnum.LOCOMOTIVE;
                    break;
            }
            currentAddressBeanModel.setAddressType(addressType);
        }

        // check if a loco dialog with the same address exists
        // List dialogRegistry =
        // DefaultApplicationContext.getInstance().get(DefaultApplicationContext.KEY_DIALOGREGISTRY, List.class);
        if (currentAddressBeanModel.getDccAddress() != null) {

            if (CollectionUtils.isNotEmpty(dialogRegistry.getDialogRegistry())) {
                String searchKey = PomProgrammerView.prepareKey(currentAddressBeanModel.getDccAddress());
                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(existingDialog.getWindow());
                        }
                        else {
                            existingDialog.getWindow().toFront();
                        }
                        return;
                    }
                    catch (Exception ex) {
                        LOGGER.warn("Bring the existing dialog to front failed.");
                    }
                }
                else {
                    LOGGER.info("No existing dialog found.");
                }
            }
        }

        view = new PomProgrammerView(model, currentAddressBeanModel);
        view.addPomProgrammerViewListener(new PomProgrammerViewListener() {
            @Override
            public void close() {

                // compDispMessages.dispose();
                messageAdapter.dispose();

                RegisteredDialog registeredDialog = view;

                // unregister the dialog in the dialog registry
                unregisterView(registeredDialog);

                fireClose();
            }

            @Override
            public void sendRequest(PomAddressData decoderAddress, PomOperation operation, int cvNumber, int cvValue) {
                fireSendRequest(decoderAddress, operation, cvNumber, cvValue);
            }

            @Override
            public boolean sendCommandStationStateRequest(boolean activate) {
                LOGGER.info("Set the command station to active mode: {}", activate);

                // check if the command station is running and start command station if not in running mode
                final CommandStationStatus commandStationState =
                    commandStationService.queryCommandStationStateBlocking(ConnectionRegistry.CONNECTION_ID_MAIN, node);

                // query the boosters in the system
                List boostersToStart = new LinkedList<>();

                for (BoosterNodeInterface node : boosterService
                    .getBoosterNodes(ConnectionRegistry.CONNECTION_ID_MAIN)) {

                    LOGGER.info("+++ Query the booster state for node: {}", node);
                    BoosterStatus boosterState = node.getBoosterStatus();
                    LOGGER.info("+++ The current boosterState: {}", boosterState);
                    // if a booster has no power or is off because of short detected we must show an error
                    // message
                    if (boosterState == null) {
                        // TODO the booster state was not delivered -> show an error
                    }
                    else if (BoosterStatus.isOffState(boosterState)) {
                        LOGGER.info("The current booster is off: {}", node);

                        boostersToStart.add(node);
                    }
                }

                //
                if (CommandStationStatus.isOffState(commandStationState)
                    || CollectionUtils.isNotEmpty(boostersToStart)) {

                    // ask the user if he wants to activate the command station
                    List commandLinks = new LinkedList<>();
                    commandLinks
                        .add(new CommandLink(
                            Resources.getString(PomProgrammerController.class, "activate_booster_and_commandstation"),
                            Resources
                                .getString(PomProgrammerController.class, "activate_booster_and_commandstation.text")));
                    commandLinks
                        .add(new CommandLink(
                            Resources
                                .getString(PomProgrammerController.class, "do_not_activate_booster_and_commandstation"),
                            Resources
                                .getString(PomProgrammerController.class,
                                    "do_not_activate_booster_and_commandstation.text")));

                    if (SystemUtils.IS_OS_MAC_OSX) {
                        commandLinks
                            .add(
                                new CommandLink(Resources.getString(PomProgrammerController.class, "cancel_pom_dialog"),
                                    Resources.getString(PomProgrammerController.class, "cancel_pom_dialog.text")));
                    }

                    int choice =
                        TaskDialogs
                            .build(parent, Resources.getString(PomProgrammerController.class, "message-warn"),
                                Resources.getString(PomProgrammerController.class, "message"))
                            .title(Resources.getString(PomProgrammerController.class, "title")).choice(0, commandLinks);

                    LOGGER.info("User selected option: {}", choice);

                    switch (choice) {
                        case -1:
                            LOGGER.info("User cancelled pomConfirmDialog.");
                            throw new OperationAbortedException("User cancelled pomConfirmDialog.");
                        case 0:
                            if (NodeUtils.hasBoosterFunctions(node.getNode().getUniqueId())) {
                                LOGGER.info("Activate the booster!");
                                boosterService
                                    .setBoosterState(ConnectionRegistry.CONNECTION_ID_MAIN,
                                        node.getNode().getBoosterNode(), BoosterStatus.ON);
                            }
                            else {
                                LOGGER.info("The command station has no booster!");
                            }

                            LOGGER.info("Activate the command station!");
                            commandStationService
                                .setCommandStationState(ConnectionRegistry.CONNECTION_ID_MAIN, node,
                                    CommandStationStatus.GO_IGN_WD);

                            for (BoosterNodeInterface booster : boostersToStart) {
                                LOGGER.info("Start the booster: {}", booster);
                                boosterService
                                    .setBoosterState(ConnectionRegistry.CONNECTION_ID_MAIN,
                                        booster.getNode().getBoosterNode(), BoosterStatus.ON);
                            }
                            break;
                        case 1:
                            break;
                        case 2:
                            LOGGER.info("User cancelled pomConfirmDialog.");
                            throw new OperationAbortedException("User cancelled pomConfirmDialog.");
                        default:
                            break;
                    }

                    return true;
                }
                else {
                    LOGGER.info("Set the command station state: {}", commandStationState);
                    model
                        .setCommandStationState(
                            commandStationState != null ? commandStationState.getCommandStationState() : null);
                }
                return false;
            }
        });

        LOGGER.info("Initialize the view.");
        setOpened(true);

        view.showDialog(parent, x, y);

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

        LOGGER.info("The POM programmer dialog is now displayed.");
    }

    private void updatePomProgState(
        PomProgState pomProgState, PomAddressData decoderAddress, int cvNumber, int cvValue) {
        model.updatePomProgResult(pomProgState, decoderAddress, cvNumber, cvValue);
    }

    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.");
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy