/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2021 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * 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.jboss.installer.validators;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.jboss.installer.core.LanguageUtils;
import org.jboss.installer.core.ValidationResult;

import java.nio.file.Path;
import java.util.Collection;

public abstract class PathValidator {
    public static final int FILENAME_LENGTH_LIMIT = 255;
    protected static final int EAP_RESERVED_PATH_LENGTH = 170;
    private final LanguageUtils langUtils;
    private final String prefix;

    public static final String NO_PATH_KEY = "no_path";
    public static final String INVALID_CHAR = "invalid_char";
    public static final String RESTRICTED_FILENAME = "restricted_filename";
    public static final String FILENAME_TOO_LONG = "filename_too_long";
    public static final String WARN_PATH_TOO_LONG = "path_too_long_warn";
    public static final String ERROR_PATH_TOO_LONG = "path_too_long_error";

    protected PathValidator(String prefix, LanguageUtils langUtils) {
        this.prefix = prefix;
        this.langUtils = langUtils;
    }

    public static PathValidator newInstance(String prefix, LanguageUtils langUtils) {
        if (SystemUtils.IS_OS_WINDOWS) {
            return new WindowsPathValidator(prefix, langUtils);
        } else {
            return new LinuxPathValidator(prefix, langUtils);
        }
    }

    public ValidationResult validate(String installPathText) {
        if (installPathText == null) {
            return ValidationResult.error(getErrorMessage(NO_PATH_KEY));
        }

        ValidationResult res = validateCharacters(installPathText);
        if (res.getResult() != ValidationResult.Result.OK) {
            return res;
        }

        final Path path = Path.of(installPathText).toAbsolutePath();
        res = validateFilenameLength(path);
        if (res.getResult() != ValidationResult.Result.OK) {
            return res;
        }

        res = validateAbsoluteLength(path);
        if (res.getResult() != ValidationResult.Result.OK) {
            return res;
        }

        return ValidationResult.ok();
    }

    protected String getErrorMessage(String key, String... args) {
        if (langUtils.hasString(prefix + "." + key)) {
            return langUtils.getString(prefix + "." + key, args);
        } else {
            return langUtils.getString("general.path_error." + key, args);
        }
    }

    protected abstract ValidationResult validateAbsoluteLength(Path path);

    private ValidationResult validateFilenameLength(Path path) {
        for (int i=0; i< path.getNameCount(); i++) {
            if (path.getName(i).toString().length() > FILENAME_LENGTH_LIMIT) {
                return ValidationResult.error(getErrorMessage(FILENAME_TOO_LONG));
            }
        }
        return ValidationResult.ok();
    }

    protected abstract ValidationResult validateCharacters(String installPathText);

    protected static String printIllegalCharacters(Collection<String> chars) {
        return StringEscapeUtils.escapeHtml3(StringUtils.join(chars, ", "));
    }

}
