/*
 * Copyright 2020 ETSI
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its contributors 
 *    may be used to endorse or promote products derived from this software without 
 *    specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package fr.mines_stetienne.ci.saref;

import java.io.Console;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import fr.mines_stetienne.ci.saref.SAREFPipeline.Mode;

/**
 *
 * @author Maxime Lefrançois, Omar Qawasmeh
 *
 */
public class CLIExecution implements SAREFCredentialsProvider {

	private static final Logger LOG = LoggerFactory.getLogger(CLIExecution.class);

	private static final String ARG_IGNORE_EXAMPLES = "e";
	private static final String ARG_IGNORE_EXAMPLES_LONG = "no-examples";
	private static final String ARG_IGNORE_EXAMPLES_MAN = "Do not check examples";

	private static final String ARG_IGNORE_SITE = "s";
	private static final String ARG_IGNORE_SITE_LONG = "no-site";
	private static final String ARG_IGNORE_SITE_MAN = "Do not generate the static portal";

	private static final String ARG_IGNORE_TERMS = "t";
	private static final String ARG_IGNORE_TERMS_LONG = "no-terms";
	private static final String ARG_IGNORE_TERMS_MAN = "Do not generate the static portal for terms";

	private static final Options OPTIONS = new Options()
			.addOption(ARG_IGNORE_EXAMPLES, ARG_IGNORE_EXAMPLES_LONG, false, ARG_IGNORE_EXAMPLES_MAN)
			.addOption(ARG_IGNORE_TERMS, ARG_IGNORE_TERMS_LONG, false, ARG_IGNORE_TERMS_MAN)
			.addOption(ARG_IGNORE_SITE, ARG_IGNORE_SITE_LONG, false, ARG_IGNORE_SITE_MAN);

	private static final Console console = System.console();
	
	public SAREFPipeline getSAREFPipeline(String[] args) throws RuntimeException {
		if (args.length == 0) {
			displayHelp(-1);
		}

		final Mode mode;
		final boolean ignoreExamples;
		final boolean ignoreTerms;
		final boolean ignoreSite;
		final File directory;

		try {
			switch (args[0]) {
			case "develop":
				mode = Mode.DEVELOP;
				break;
			case "prerelease-portal":
				mode = Mode.PRERELEASE_PORTAL;
				break;
			case "release-portal":
				mode = Mode.RELEASE_PORTAL;
				break;
			case "release":
				mode = Mode.RELEASE;
				break;
			case "clean":
				mode = Mode.CLEAN;
				break;
			case "help":
				displayHelp(0);
				throw new RuntimeException();
			default:
				LOG.error(String.format("<mode> %s is invalid. Valid modes are develop, portal, prerelease-portal, release-portal, help.", args[0]));
				displayHelp(-1);
				throw new RuntimeException();
			}
			
			DefaultParser commandLineParser = new DefaultParser();
			String[] options = Arrays.copyOfRange(args, 1, args.length);
			CommandLine cl = commandLineParser.parse(OPTIONS, options, true);
			
			String dirName = "";
			if(!cl.getArgList().isEmpty()) {
				if(cl.getArgList().size()>1) {
					LOG.error("There should be at most one <target>.");
					displayHelp(-1);
					throw new RuntimeException();
				}
				dirName = cl.getArgList().get(0);
			}
			directory = new File(dirName).getCanonicalFile();
			if (!directory.isDirectory()) {
				LOG.error("The directory does not exist " + directory);
				System.exit(-1);
			}

			ignoreExamples = cl.hasOption(ARG_IGNORE_EXAMPLES);
			ignoreTerms = cl.hasOption(ARG_IGNORE_TERMS);
			ignoreSite = cl.hasOption(ARG_IGNORE_SITE);

			return new SAREFPipeline(this, directory, mode, ignoreExamples, ignoreTerms, ignoreSite);
		} catch (IOException | ParseException ex) {
			LOG.debug("Exception while parsing arguments", ex);
			throw new RuntimeException();
		}
	}

	private void displayHelp(int returnCode) {
		try {
			String helpHeader = IOUtils.toString(
					CLIExecution.class.getClassLoader().getResourceAsStream("cli/helpHeader.txt"), StandardCharsets.UTF_8);
			String helpCmdLineSyntax = IOUtils.toString(
					CLIExecution.class.getClassLoader().getResourceAsStream("cli/helpCmdLineSyntax.txt"),
					StandardCharsets.UTF_8);
			String helpFooter = IOUtils.toString(
					CLIExecution.class.getClassLoader().getResourceAsStream("cli/helpFooter.txt"), StandardCharsets.UTF_8);
			HelpFormatter formatter = new HelpFormatter();
			formatter.printHelp(helpCmdLineSyntax, helpHeader, OPTIONS, helpFooter);
			System.exit(returnCode);
		} catch (IOException ex) {
			LOG.debug("Exception while displaying help", ex);
			throw new RuntimeException();
		}
	}

	@Override
	public String getUsername(String hostName) {
		if (console != null) {
			return console.readLine(SAREF.getMessage(MESSAGE.account_name.toString(), hostName));
		} else if (System.getenv("GITLAB_CI") != null) {
			LOG.info("using username 'gitlab-ci-token'");
			return "gitlab-ci-token";
		} else {
			LOG.warn(SAREF.getMessage(MESSAGE.account_name_empty.toString(), hostName));
			return "";
		}
	}

	@Override
	public char[] getPassword(String hostName) {
		if (console != null) {
			return console.readPassword(SAREF.getMessage(MESSAGE.account_password.toString(), hostName));
		} else if (System.getenv("GITLAB_CI") != null) {
			LOG.info("using password environment variable GITLAB_CI");
			return System.getenv("CI_JOB_TOKEN").toCharArray();
		} else {
			LOG.warn(SAREF.getMessage(MESSAGE.account_password_empty.toString(), hostName));
			return "".toCharArray();
		}
	}

}
