/*
 * Copyright 2017-2018 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
 *
 *      https://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.util.ArrayList;
import java.util.List;

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.shell.Input;
import org.springframework.shell.InputProvider;
import org.springframework.shell.Shell;
import org.springframework.shell.jline.InteractiveShellApplicationRunner;
import org.springframework.util.StringUtils;

/**
 * An {@link ApplicationRunner} implementation that determines if the shell should execute
 * in interactive mode or in a 'stand alone executable' mode. If any arguments are passed
 * in that do not have the prefix {@code spring.cloud.skipper.client}, 'stand alone
 * executeable' model will be activated and the arguments will be passed into the shell as
 * a command to execute and then exit.
 *
 * This {@link ApplicationRunner} has lower priority than
 * {@link InitializeConnectionApplicationRunner}.
 *
 * @see org.springframework.cloud.skipper.client.SkipperClientProperties
 *
 * @author Janne Valkealahti
 *
 */
@Order(InteractiveShellApplicationRunner.PRECEDENCE - 5)
public class InteractiveModeApplicationRunner implements ApplicationRunner {

	private final Shell shell;
	private final ConfigurableEnvironment environment;

	/**
	 * Construct a new InteractiveModeApplicationRunner, given the required shell components.
	 *
	 * @param shell the shell
	 * @param environment the environment
	 */
	public InteractiveModeApplicationRunner(Shell shell, ConfigurableEnvironment environment) {
		this.shell = shell;
		this.environment = environment;
	}

	@Override
	public void run(ApplicationArguments args) throws Exception {
		// if we have args, assume one time run
		ArrayList<String> argsToShellCommand = new ArrayList<>();
		for (String arg : args.getSourceArgs()) {
			// consider client connection options as non command args
			if (!arg.contains("spring.cloud.skipper.client")) {
				argsToShellCommand.add(arg);
			}
		}
		if (argsToShellCommand.size() > 0) {
			if (ShellUtils.hasHelpOption(args)) {
				// going into 'help' mode. HelpAwareShellApplicationRunner already
				// printed usage, we just force running just help.
				argsToShellCommand.clear();
				argsToShellCommand.add("help");
			}
		}

		if (!argsToShellCommand.isEmpty()) {
			InteractiveShellApplicationRunner.disable(environment);
			shell.run(new StringInputProvider(argsToShellCommand));
		}
	}

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

		private final List<String> commands;

		private boolean done;

		StringInputProvider(List<String> words) {
			this.commands = words;
		}

		@Override
		public Input readInput() {
			if (!done) {
				done = true;
				return new Input() {
					@Override
					public List<String> words() {
						return commands;
					}

					@Override
					public String rawText() {
						return StringUtils.collectionToDelimitedString(commands, " ");
					}
				};
			}
			else {
				return null;
			}
		}
	}
}