/*
 * Copyright (c) 2004-2017, by Alex Leigh.
 * All rights reserved.
 *
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE
 * The copyright notice above does not evidence any
 * actual or intended publication of such source code.
 */

package lc.mecha.io;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashSet;
import java.util.Set;

/**
 * Utility methods for interacting with files.
 *
 * @author Alex Leigh
 */
public class FileUtil {
    /**
     * Recursively scan a path and return the relative paths to all of its directories and files.
     * <p>
     * Any of dirs, leavecs, and files may be <code>null</code>.
     */
    public static Set<Path> scanRecursively(Set<Path> dirs, Set<Path> leaves, Set<Path> files, Path root) throws IOException {
        Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                if (dir.equals(root)) return FileVisitResult.CONTINUE;
                if (dirs != null) dirs.add(root.relativize(dir));
                if (leaves != null && Files.list(dir).noneMatch(d -> Files.isDirectory(d))) {
                    leaves.add(root.relativize(dir));
                }
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                if (files != null) files.add(root.relativize(file));
                return FileVisitResult.CONTINUE;
            }
        });

        return files;
    }

    /**
     * Find all the directories in the given path. This method does not recurse.
     */
    public static void findDirectories(Set<Path> dirs, Path root) {
        for (File f : root.toFile().listFiles()) {
            if (f.isDirectory()) dirs.add(f.toPath());
        }
    }


    /**
     * For the given directory, find all the leaf directories. The method will recurse.
     */
    public static Set<Path> findLeafDirectories(Path root) throws IOException {
        HashSet<Path> folders = new HashSet<>();

        Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                //If there is no subDir --> add it to your list
                if (Files.list(dir).noneMatch(d -> Files.isDirectory(d))) {
                    folders.add(dir);
                }
                return FileVisitResult.CONTINUE;
            }
        });

        return folders;
    }

    /**
     * Create a new temporary directory. When the VM is shut down, the directory and any contents will be
     * recursively removed.
     */
    public static File createTmpDirectory(String prefix, String suffix) throws IOException {
        File f = File.createTempFile(prefix, suffix);
        f.delete();
        f.mkdirs();

        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                FileUtils.deleteDirectory(f);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }));

        return f;
    }
}
