/*
 * Copyright (C) 2009 the original author(s).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.sonatype.gshell.execute;

import com.google.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.sonatype.gshell.branding.Branding;
import org.sonatype.gshell.command.CommandAction;
import org.sonatype.gshell.command.CommandContext;
import org.sonatype.gshell.command.CommandDocumenter;
import org.sonatype.gshell.command.CommandHelpSupport;
import org.sonatype.gshell.command.IO;
import org.sonatype.gshell.io.StreamJack;
import org.sonatype.gshell.notification.ErrorNotification;
import org.sonatype.gshell.notification.ResultNotification;
import org.sonatype.gshell.parser.CommandLineParser;
import org.sonatype.gshell.parser.CommandLineParser.CommandLine;
import org.sonatype.gshell.registry.CommandResolver;
import org.sonatype.gshell.shell.Shell;
import org.sonatype.gshell.shell.ShellHolder;
import org.sonatype.gshell.util.Arguments;
import org.sonatype.gshell.util.PropertiesJack;
import org.sonatype.gshell.util.Strings;
import org.sonatype.gshell.util.cli2.CliProcessor;
import org.sonatype.gshell.util.cli2.OpaqueArguments;
import org.sonatype.gshell.util.i18n.PrefixingMessageSource;
import org.sonatype.gshell.util.pref.PreferenceProcessor;
import org.sonatype.gshell.vars.Variables;

import static org.sonatype.gshell.vars.VariableNames.LAST_RESULT;

/**
 * The default {@link org.sonatype.gshell.execute.CommandExecutor} component.
 *
 * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
 * @since 2.0
 */
public class CommandExecutorImpl
    implements CommandExecutor
{
    private final Logger log = LoggerFactory.getLogger(getClass());

    private final CommandResolver resolver;

    private final CommandLineParser parser;

    private final CommandDocumenter documenter;

    @Inject
    public CommandExecutorImpl(final CommandResolver resolver, final CommandLineParser parser, final CommandDocumenter documenter) {
        assert resolver != null;
        this.resolver = resolver;
        assert parser != null;
        this.parser = parser;
        assert documenter != null;
        this.documenter = documenter;
    }

    public Object execute(final Shell shell, final String line) throws Exception {
        assert shell != null;
        assert line != null;

        if (line.trim().length() == 0) {
            log.trace("Ignoring empty line");
            return null;
        }

        final Shell lastShell = ShellHolder.set(shell);

        CommandLine cl = parser.parse(line);

        try {
            return cl.execute(shell, this);
        }
        catch (ErrorNotification n) {
            // Decode the error notification
            Throwable cause = n.getCause();

            if (cause instanceof Exception) {
                throw (Exception) cause;
            }
            else if (cause instanceof Error) {
                throw (Error) cause;
            }
            else {
                throw n;
            }
        }
        finally {
            ShellHolder.set(lastShell);
        }
    }

    public Object execute(final Shell shell, final Object... args) throws Exception {
        assert shell != null;
        assert args != null;

        return execute(shell, String.valueOf(args[0]), Arguments.shift(args));
    }

    public Object execute(final Shell shell, final String name, final Object[] args) throws Exception {
        assert shell != null;
        assert name != null;
        assert args != null;

        log.debug("Executing ({}): [{}]", name, Strings.join(args, ", "));

        CommandAction command = resolver.resolveCommand(name);

        MDC.put(CommandAction.class.getName(), name);

        final Shell lastShell = ShellHolder.set(shell);
        final IO io = shell.getIo();

        StreamJack.maybeInstall(io.streams);
//        PropertiesJack.maybeInstall(System.getProperties());

        Object result = null;
        try {
            boolean execute = true;

            PreferenceProcessor pp = new PreferenceProcessor();
            Branding branding = ShellHolder.get().getBranding();
            pp.setBasePath(branding.getPreferencesBasePath());
            pp.addBean(command);
            pp.process();

            if (!(command instanceof OpaqueArguments)) {
                CliProcessor clp = new CliProcessor();
                clp.addBean(command);
                clp.setMessages(new PrefixingMessageSource(command.getMessages(), CommandDocumenter.COMMAND_DOT));
                CommandHelpSupport help = new CommandHelpSupport();
                clp.addBean(help);

                // Process the arguments
                clp.process(Arguments.toStringArray(args));

                // Render command-line usage
                if (help.displayHelp) {
                    documenter.renderUsage(command, io);
                    result = CommandAction.Result.SUCCESS;
                    execute = false;
                }
            }

            if (execute) {
                try {
                    result = command.execute(new CommandContext()
                    {
                        public Shell getShell() {
                            return shell;
                        }

                        public Object[] getArguments() {
                            return args;
                        }

                        public IO getIo() {
                            return io;
                        }

                        public Variables getVariables() {
                            return shell.getVariables();
                        }
                    });
                }
                catch (ResultNotification n) {
                    result = n.getResult();
                }
            }
        }
        finally {
            io.flush();

            StreamJack.deregister();

//            PropertiesJack.deregister();

            ShellHolder.set(lastShell);

            MDC.remove(CommandAction.class.getName());
        }

        shell.getVariables().set(LAST_RESULT, result);

        log.debug("Result: {}", result);

        return result;
    }
}
@@ -1511,56 +1511,8 @@
 ts;%0A
-import org.sonatype.gshell.util.PropertiesJack;%0A
 impo
@@ -4346,71 +4346,8 @@
 ms);
-%0A//        PropertiesJack.maybeInstall(System.getProperties());
 %0A%0A  
@@ -6311,52 +6311,8 @@
 );%0A%0A
-//            PropertiesJack.deregister();%0A%0A
     

Drop PropertiesJack stuff for now