package brooklyn.cli;

import brooklyn.cli.commands.BrooklynCommand;
import brooklyn.cli.commands.DeployCommand;
import brooklyn.cli.commands.HelpCommand;
import brooklyn.cli.commands.VersionCommand;
import brooklyn.cli.commands.UndeployCommand;
import brooklyn.cli.commands.CatalogEntitiesCommand;
import brooklyn.cli.commands.CatalogPoliciesCommand;
import brooklyn.cli.commands.ListApplicationsCommand;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import org.iq80.cli.Cli;
import org.iq80.cli.Help;
import org.iq80.cli.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.PrintStream;

public class Client {

    // Error codes
    public static final int PARSE_ERROR = 1;
    public static final int EXECUTION_ERROR = 2;

    public static final Logger LOG = LoggerFactory.getLogger(Client.class);

    private PrintStream out;
    private PrintStream err;

    public Client() {
        this.out = System.out;
        this.err = System.err;
    }

    public Client(PrintStream out, PrintStream err) {
        this.out = out;
        this.err = err;
    }

    public static void main(String...args) {
        Client client = new Client();
        client.run(args);
    }

    public final void run(String...args) {
        Cli<BrooklynCommand> parser = buildCli();
        try {
            LOG.debug("Parsing command line arguments: {}", args);
            BrooklynCommand command = parser.parse(args);
            command.setOut(out);
            command.setErr(err);
            LOG.debug("Executing command: {}", command);
            command.call();
        } catch (ParseException pe) { // looks like the user typed it wrong
            System.err.println("Parse error: " + pe.getMessage()); // display error
            System.err.println(getUsageInfo(parser)); // display cli help
            System.exit(PARSE_ERROR);
        } catch (Exception e) { // unexpected error during command execution
            LOG.error("Execution error: {}\n{}" + e.getMessage(), e.getStackTrace());
            System.err.println("Execution error: " + e.getMessage());
            e.printStackTrace();
            System.exit(EXECUTION_ERROR);
        }
    }

    @VisibleForTesting
    static Cli<BrooklynCommand> buildCli() {
        @SuppressWarnings({ "unchecked" })
        Cli.CliBuilder<BrooklynCommand> builder = Cli.buildCli("brooklyn", BrooklynCommand.class)
                .withDescription("Brooklyn CLI client")
                .withDefaultCommand(HelpCommand.class)
                .withCommands(
                        HelpCommand.class,
                        VersionCommand.class,
                        DeployCommand.class,
                        UndeployCommand.class,
                        ListApplicationsCommand.class,
                        CatalogEntitiesCommand.class,
                        CatalogPoliciesCommand.class
                );
        return builder.build();
    }

    static String getUsageInfo(Cli<BrooklynCommand> parser) {
        StringBuilder help = new StringBuilder();
        help.append("\n");
        Help.help(parser.getMetadata(), ImmutableList.of("brooklyn"),help);
        help.append("See 'brooklyn help <command>' for more information on a specific command.");
        return help.toString();
    }

}

@@ -675,16 +675,41 @@
 tStream;
+%0Aimport java.util.Arrays;
 %0A%0Apublic
@@ -725,16 +725,93 @@
 ient %7B%0A%0A
+    public static final Logger LOG = LoggerFactory.getLogger(Client.class);%0A%0A
     // E
@@ -925,79 +925,31 @@
    p
-ublic static final Logger LOG = LoggerFactory.getLogger(Client.class);%0A
+rivate PrintStream out;
 %0A   
@@ -961,36 +961,37 @@
 ate PrintStream 
-out;
+err;%0A
 %0A    private Pri
@@ -983,39 +983,71 @@
     private 
-PrintStream err
+static Cli%3CBrooklynCommand%3E parser = buildCli()
 ;%0A%0A    publi
@@ -1332,84 +1332,26 @@
     
-client.run(args);%0A    %7D%0A%0A    public final void run(String...args) %7B%0A
+try %7B%0A    
         
 Cli%3C
@@ -1350,415 +1350,177 @@
     
-Cli%3CBrooklynCommand%3E parser = buildCli();%0A        try %7B%0A            LOG.debug(%22Parsing command line arguments: %7B%7D%22, args);%0A            BrooklynCommand command = parser.parse(args);%0A            command.setOut(out);%0A            command.setErr(err);%0A            LOG.debug(%22Executing command: %7B%7D%22, command);%0A            command.call();%0A        %7D catch (ParseException pe) %7B // looks like the user typed it wrong
+client.run(args);%0A        %7D catch (ParseException pe) %7B // looks like the user typed it wrong%0A            LOG.error(%22Error parsing command %22+ Arrays.toString(args), pe);
 %0A   
@@ -1817,67 +1817,58 @@
 r(%22E
-xecution error: %7B%7D%5Cn%7B%7D%22 + e.getMessage(), e.getStackTrace()
+rror executing command %22+ Arrays.toString(args), e
 );%0A 
@@ -1940,41 +1940,8 @@
 ));%0A
-            e.printStackTrace();%0A
     
@@ -1991,24 +1991,343 @@
    %7D%0A    %7D%0A%0A
+    public final void run(String...args) throws Exception %7B%0A        LOG.debug(%22Parsing command line arguments: %7B%7D%22, args);%0A        BrooklynCommand command = parser.parse(args);%0A        command.setOut(out);%0A        command.setErr(err);%0A        LOG.debug(%22Executing command: %7B%7D%22, command);%0A        command.call();%0A    %7D%0A%0A
     @Visible

Add a run() method to Client + a few other improvements to make things more testable