/*
 * Copyright 2017 the original author or authors.
 *
 * 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.springframework.cloud.skipper.shell.command.support;

import java.io.File;
import java.io.FileReader;
import java.io.Reader;
import java.util.List;
import java.util.stream.Collectors;

import org.jline.reader.LineReader;
import org.jline.reader.Parser;

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.shell.Input;
import org.springframework.shell.InputProvider;
import org.springframework.shell.Shell;
import org.springframework.shell.jline.DefaultShellApplicationRunner;
import org.springframework.shell.jline.DefaultShellApplicationRunner.JLineInputProvider;
import org.springframework.shell.jline.FileInputProvider;
import org.springframework.shell.jline.PromptProvider;
import org.springframework.util.StringUtils;

/**
 * Skipper related {@link ApplicationRunner} used in shell to customise
 * behaviour order to pass in command args, if given, directly to shell
 * and exit.
 *
 * @author Janne Valkealahti
 *
 */
@Order(DefaultShellApplicationRunner.PRECEDENCE - 5)
public class SkipperShellApplicationRunner implements ApplicationRunner {

	private final LineReader lineReader;
	private final PromptProvider promptProvider;
	private final Parser parser;
	private final Shell shell;

	/**
	 * Instantiates a new skipper shell application runner.
	 *
	 * @param lineReader the line reader
	 * @param promptProvider the prompt provider
	 * @param parser the parser
	 * @param shell the shell
	 */
	public SkipperShellApplicationRunner(LineReader lineReader, PromptProvider promptProvider, Parser parser,
			Shell shell) {
		this.lineReader = lineReader;
		this.promptProvider = promptProvider;
		this.parser = parser;
		this.shell = shell;
	}

	@Override
	public void run(ApplicationArguments args) throws Exception {
		// if we have args, assume one time run
		if (args.getSourceArgs().length > 0) {
			CommandInputProvider inputProvider = new CommandInputProvider(
					StringUtils.arrayToDelimitedString(args.getSourceArgs(), " "));
			shell.run(inputProvider);
			return;
		}

		// otherwise, fallback to what DefaultShellApplicationRunner would do
		List<File> scriptsToRun = args.getNonOptionArgs().stream()
				.filter(s -> s.startsWith("@"))
				.map(s -> new File(s.substring(1)))
				.collect(Collectors.toList());
		if (scriptsToRun.isEmpty()) {
			InputProvider inputProvider = new JLineInputProvider(lineReader, promptProvider);
			shell.run(inputProvider);
		}
		else {
			for (File file : scriptsToRun) {
				try (Reader reader = new FileReader(file);
						FileInputProvider inputProvider = new FileInputProvider(reader, parser)) {
					shell.run(inputProvider);
				}
			}
		}
	}

	/**
	 * {@link InputProvider} which gives a single input to shell.
	 */
	private static class CommandInputProvider implements InputProvider {

		private String command;
		private boolean done;

		CommandInputProvider(String command) {
			this.command = command;
		}

		@Override
		public Input readInput() {
			// we can only give single input as otherwise
			// shell will start to loop command. thus use a simple
			// flag to return null next time.
			if (!done) {
				done = true;
				return () -> command;
			}
			return null;
		}
	}
}

@@ -738,32 +738,60 @@
 java.io.Reader;%0A
+import java.util.ArrayList;%0A
 import java.util
@@ -2555,39 +2555,299 @@
 n%0A%09%09
-if (args.getSourceArgs().length
+ArrayList%3CString%3E argsToShellCommand = new ArrayList%3C%3E();%0A%09%09for (String arg : args.getSourceArgs()) %7B%0A%09%09%09// consider client connection options as non command args%0A%09%09%09if (!arg.contains(%22spring.cloud.skipper.client%22)) %7B%0A%09%09%09%09argsToShellCommand.add(arg);%0A%09%09%09%7D%0A%09%09%7D%0A%09%09if (argsToShellCommand.size()
  %3E 0
@@ -2937,13 +2937,18 @@
 ils.
-array
+collection
 ToDe
@@ -2965,32 +2965,30 @@
 ing(args
-.getSourceArgs()
+ToShellCommand
 , %22 %22));

Whitelist all args having spring.cloud.skipper.client