/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * 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.jboss.installer;

import org.jboss.installer.core.LanguageUtils;
import org.jboss.installer.core.i18n.DefaultLanguageUtils;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Locale;
import java.util.Optional;

public class ArgumentsParser {

    public static final String VARIABLESFILE_ARGUMENT = "-variablesfile";
    public static final String OFFLINE_PATH_ARGUMENT = "-offline";
    public static final String COMMAND_SYNTAX_TEXT = String.format(
            "java -jar installer.jar [<INSTALLATION_SCRIPT> [%s <VARIABLES_FILE>]] [%s <path/to/the/repository>]",
            VARIABLESFILE_ARGUMENT, OFFLINE_PATH_ARGUMENT);
    public static final String COMMAND_SYNTAX_EXAMPLE = String.format("java -jar installer.jar auto.xml [%s auto.xml.variables]", VARIABLESFILE_ARGUMENT);
    public static final String CONSOLE_USAGE_KEY = "console.usage";
    public static final String CONSOLE_ERROR_TOO_MANY_ARGS = "console.error.too_many_args";
    public static final String CONSOLE_ERROR_MISSING_ARG_VALUE = "console.error.missing_arg_value";
    public static final String CONSOLE_ERROR_UNEXPECTED_ARG = "console.error.unexpected_arg";


    private LanguageUtils langUtils = new DefaultLanguageUtils.Builder().setLocale(Locale.getDefault()).build();

    public Arguments parse(String[] args) throws ArgumentsParsingException {
        final Arguments arguments = new Arguments();

        if (args.length == 0) {
            return arguments;
        }

        final Iterator<String> argumentIterator = Arrays.stream(args).iterator();

        final String arg = argumentIterator.next();
        if (arg.equals(OFFLINE_PATH_ARGUMENT)) {
            if (argumentIterator.hasNext()) {
                arguments.offlinePath = argumentIterator.next();
                if (!Files.exists(Path.of(arguments.offlinePath))) {
                    throw new ArgumentsParsingException(langUtils.getString("security_domain_screen.not_exists_error", arguments.offlinePath));
                }
            } else {
                throw new ArgumentsParsingException(langUtils.getString(CONSOLE_ERROR_MISSING_ARG_VALUE, OFFLINE_PATH_ARGUMENT));
            }
            if (argumentIterator.hasNext()) {
                throw new ArgumentsParsingException(langUtils.getString(CONSOLE_ERROR_UNEXPECTED_ARG, argumentIterator.next()));
            }
            return arguments;
        } else if (arg.startsWith("-")) {
            throw new ArgumentsParsingException(langUtils.getString(CONSOLE_ERROR_UNEXPECTED_ARG, arg));
        }
        arguments.automatedFile = arg;

        while (argumentIterator.hasNext()) {
            switch (argumentIterator.next()) {
                case VARIABLESFILE_ARGUMENT:
                    if (argumentIterator.hasNext()) {
                        arguments.variablesFile = argumentIterator.next();
                    } else {
                        throw new ArgumentsParsingException(langUtils.getString(CONSOLE_ERROR_MISSING_ARG_VALUE, VARIABLESFILE_ARGUMENT));
                    }
                    break;
                case OFFLINE_PATH_ARGUMENT:
                    if (argumentIterator.hasNext()) {
                        arguments.offlinePath = argumentIterator.next();
                        if (!Files.exists(Path.of(arguments.offlinePath))) {
                            throw new ArgumentsParsingException(langUtils.getString("security_domain_screen.not_exists_error", arguments.offlinePath));
                        }
                    } else {
                        throw new ArgumentsParsingException(langUtils.getString(CONSOLE_ERROR_MISSING_ARG_VALUE, OFFLINE_PATH_ARGUMENT));
                    }
                    break;
                default:
                    throw new ArgumentsParsingException(langUtils.getString(CONSOLE_ERROR_UNEXPECTED_ARG, arg));
            }
        }

        return arguments;
    }

    public void printUsage(String errorMessage) {
        System.out.println(errorMessage);
        System.out.println(langUtils.getString(CONSOLE_USAGE_KEY));
        System.out.println(COMMAND_SYNTAX_TEXT);
    }

    static class Arguments {
        private boolean console;
        private String automatedFile;
        private String variablesFile;
        private String offlinePath;

        boolean isAutomated() {
            return automatedFile != null;
        }

        boolean hasVariables() {
            return variablesFile != null;
        }

        boolean isOffline() {
            return offlinePath != null;
        }

        public String getAutomatedScript() {
            return automatedFile;
        }

        public Optional<String> getVariables() {
            return Optional.ofNullable(variablesFile);
        }

        public Optional<Path> getOfflinePath() {
            return Optional.ofNullable((offlinePath==null) ? null : Path.of(offlinePath));
        }
    }
}
