/*
 * Copyright 2006-2019 DLR, Germany
 * 
 * SPDX-License-Identifier: EPL-1.0
 * 
 * https://rcenvironment.de/
 */

package de.rcenvironment.core.command.spi;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import de.rcenvironment.core.command.api.CommandExecutionService;
import de.rcenvironment.core.command.common.CommandException;
import de.rcenvironment.core.utils.common.StringUtils;
import de.rcenvironment.core.utils.common.textstream.TextOutputReceiver;

/**
 * Common base class for {@link TextOutputReceiver}s that display {@link CommandExecutionService} results in an interactive command shell.
 * Could be expanded with more common methods/features in the future.
 * 
 * Subclasses must implement {@link #addOutput(String)}, and may optionally override {@link #onStart()} and {@link #onFinished()}.
 * 
 * @author Robert Mischke
 */
public abstract class AbstractInteractiveCommandConsole implements TextOutputReceiver {

    private final CommandExecutionService commandExecutionService;

    private final Log log = LogFactory.getLog(getClass());

    private String commandPrefix;

    public AbstractInteractiveCommandConsole(CommandExecutionService commandExecutionService) {
        // default: no command prefix
        this(commandExecutionService, "");
    }

    public AbstractInteractiveCommandConsole(CommandExecutionService commandExecutionService, String commandPrefix) {
        this.commandExecutionService = commandExecutionService;
        this.commandPrefix = commandPrefix;
    }

    @Override
    public void onStart() {
        // empty default implementation; override as needed
    }

    @Override
    public abstract void addOutput(String line);

    @Override
    public void onFinished() {
        // empty default implementation; override as needed
    }

    @Override
    // note: made final to avoid accidental "custom" implementations; only make non-final if there is a good reason - misc_ro
    public final void onFatalError(Exception e) {
        if (e instanceof CommandException) {
            CommandException ce = (CommandException) e;
            switch (ce.getType()) {
            case SYNTAX_ERROR:
                // do not log anything
                // log.info(StringUtils.format("Syntax error in command \"%s\"; message=%s", ce.getCommandString(), ce.getMessage()));
                if (ce.getMessage() != null) {
                    addOutput(StringUtils.format("Syntax error: %s", ce.getMessage()));
                    addOutput(StringUtils.format("Use \"%shelp\" to see all available commands.", commandPrefix));
                } else {
                    addOutput(StringUtils.format("Syntax error. Use \"%shelp\" to see all available commands.", commandPrefix));
                }
                break;
            case UNKNOWN_COMMAND:
                // do not log anything
                addOutput(StringUtils.format("Unknown command \"%s\". Use \"%shelp\" to see all available commands.",
                    ce.getCommandString(), commandPrefix));
                break;
            case EXECUTION_ERROR:
                log.warn(StringUtils.format("Error executing command \"%s\"; message=%s", ce.getCommandString(), ce.getMessage()));
                if (ce.getMessage() != null) {
                    addOutput(StringUtils.format("Error executing command \"%s\": %s", ce.getCommandString(), ce.getMessage()));
                } else {
                    addOutput(StringUtils.format("Error executing command \"%s\". "
                        + "No message text available; check the log file for more information.", ce.getCommandString()));
                }
                break;
            case HELP_REQUESTED:
                // TODO backwards compatibility hack; pass prefix as parameter instead - misc_ro
                boolean useCommandPrefix = commandPrefix != null && !commandPrefix.isEmpty();
                commandExecutionService.printHelpText(useCommandPrefix, ce.shouldPrintDeveloperHelp(), this);
                break;
            default:
                // should never happen
                log.error("Unhandled CommandException sub-type", e);
                addOutput("Internal error: Unhandled CommandException sub-type (" + e.toString() + ")");
            }
        } else {
            log.info("Error during command execution", e);
            addOutput("Error during command execution (" + e.toString() + "); check log file for details");
        }
    }
}
