package com.atlassian.bitbucket.installer.validation;

import com.atlassian.bitbucket.installer.InstallationException;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;

import java.io.File;
import java.util.Set;
import java.util.function.Function;

public class EmptyDirectoryValidationStrategy implements DirectoryValidationStrategy {

    private static final Set<String> FILESYSTEM_METADATA = ImmutableSet.of(".DS_Store", "lost+found", ".snapshot");
    private final Set<String> directoryWhitelist;
    private final Function<File, InstallationException> failedFactory;

    public EmptyDirectoryValidationStrategy(Set<String> directoryWhitelist, Function<File, InstallationException> failedFactory) {
        this.directoryWhitelist = Sets.union(ImmutableSet.copyOf(directoryWhitelist), FILESYSTEM_METADATA);
        this.failedFactory = failedFactory;
    }

    /**
     * Validates that the provided {@link java.io.File} is a directory, that it is accessible and that it
     * is either empty or it contains only directories which have been whitelisted
     * @param directory The directory to test
     * @throws HardValidationException if the {@link java.io.File} is a file, if it cannot be accessed,
     * if it contains directories which have not been whitelisted.
     * @throws SoftValidationException if the directory is not empty
     */
    public void validate(File directory) {
        if (directory.exists()) {
            if (directory.isFile()) {
                throw new HardValidationException(HardValidationException.ERROR_DIRECTORY_FILE);
            } else  {
                String[] contents = directory.list();
                if (contents == null) {
                    throw new HardValidationException(HardValidationException.ERROR_DIRECTORY_ACCESS);
                }
                validateWhitelist(directory);

                Set<String> filteredContents = Sets.filter(ImmutableSet.copyOf(contents),
                        input -> !directoryWhitelist.contains(input));

                if (!filteredContents.isEmpty()) {
                    throw failedFactory.apply(directory);
                }
            }
        }
    }

    private void validateWhitelist(File directory) {
        for (String directoryName : directoryWhitelist) {
            File whitelistedDirectory = new File(directory, directoryName);
            if (whitelistedDirectory.exists() && !whitelistedDirectory.isDirectory()) {
                throw new HardValidationException(HardValidationException.ERROR_INVALID_CONTENTS);
            }
        }
    }
}
