package com.agricraft.agricore.util;

import com.agricraft.agricore.core.AgriCore;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import org.reflections.Reflections;
import org.reflections.scanners.ResourcesScanner;

public class ResourceHelper {
    /**
     * Copies all resources in the class path matching the given name predicate, as well as the file structure predicate to a new directory
     *
     * @param nameFilter the predicate for the file name
     * @param dirFilter the predicate for the file (directory) structure
     * @param toFunction function specifying the destination where each file should be copied to
     * @param overwrite specifies if files which already exist should be overwritten or not
     */
    public static void copyResources(Predicate<String> nameFilter, Predicate<String> dirFilter, Function<String, Path> toFunction, boolean overwrite) {
        ResourceHelper helper = new ResourceHelper();
        helper.findResources(nameFilter).stream()
                .filter(dirFilter)
                .forEach(r -> helper.copyResource(r, toFunction.apply(r), overwrite)
                );
    }

    /**
     * Reflections instance used to find jsons
     */
    private final Reflections reflections;

    /**
     * The Reflections object can use quite some memory, therefore we instantiate a new one when we need it,
     * and discard it afterwards
     */
    protected ResourceHelper() {
        this.reflections = new Reflections(null, new ResourcesScanner());
    }

    /**
     * Finds all resources in the class path matching the given predicate
     * @param nameFilter file name predicate
     * @return set of all filenames matching the name filter
     */
    protected Set<String> findResources(Predicate<String> nameFilter) {
        return this.reflections.getResources(nameFilter::test);
    }

    /**
     * Copies a file from inside the jar to the specified location outside the
     * jar, retaining the file name. The default copy action is to not overwrite
     * an existing file.
     *
     * @param from the location of the internal resource.
     * @param to the location to copy the resource to.
     * @param overwrite if the copy task should overwrite existing files.
     */
    protected void copyResource(String from, Path to, boolean overwrite) {
        try {
            if (overwrite || !Files.exists(to)) {
                Files.createDirectories(to.getParent());
                Files.copy(this.getResourceAsStream(from), to, StandardCopyOption.REPLACE_EXISTING);
            }
        } catch (Exception e) {
            AgriCore.getLogger("AgriCraft").error(
                    "Unable to copy Jar resource: \"{0}\" to: \"{1}\"!",
                    from,
                    to
            );
            e.printStackTrace();
        }
    }

    /**
     * Retrieves the requested resource by using the current thread's class
     * loader or the AgriCore class loader.
     *
     * @param location the location of the desired resource stream.
     * @return the resource, as a stream.
     */
    protected InputStream getResourceAsStream(String location) {
        InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(location);
        return in != null ? in : ResourceHelper.class.getResourceAsStream(location);
    }

}

@@ -104,16 +104,76 @@
 Stream;%0A
+import java.net.MalformedURLException;%0Aimport java.net.URL;%0A
 import j
@@ -256,24 +256,79 @@
 CopyOption;%0A
+import java.util.Collection;%0Aimport java.util.Objects;%0A
 import java.
@@ -410,16 +410,85 @@
 dicate;%0A
+import java.util.stream.Collectors;%0Aimport java.util.stream.Stream;%0A%0A
 import o
@@ -564,16 +564,66 @@
 Scanner;
+%0Aimport org.reflections.util.ConfigurationBuilder;
 %0A%0Apublic
@@ -793,32 +793,85 @@
 irectory%0A     *%0A
+     * @param pathStream stream of all paths to scan%0A
      * @param na
@@ -1210,32 +1210,57 @@
 d copyResources(
+Stream%3CPath%3E pathStream, 
 Predicate%3CString
@@ -1409,16 +1409,39 @@
 eHelper(
+collectURLs(pathStream)
 );%0A     
@@ -1604,33 +1604,919 @@
 erwrite)
+);
 %0A    
-            
+%7D%0A%0A    /**%0A     * Collects URLs from a stream of paths%0A     * Will catch Exceptions and log them in case of an invalid path%0A     *%0A     * @param pathStream stream of all paths to scan%0A     * @return a collection of URLs representing the paths (except the invalid ones)%0A     */%0A    private static Collection%3CURL%3E collectURLs(Stream%3CPath%3E pathStream) %7B%0A        return pathStream.map(Path::toUri)%0A                .map(uri -%3E %7B%0A                    URL url = null;%0A                    try %7B%0A                        url = uri.toURL();%0A                    %7D catch (MalformedURLException e) %7B%0A                        AgriCore.getLogger(%22AgriCraft%22).error(%22Unable to scan path%22);%0A                        AgriCore.getLogger(%22AgriCraft%22).trace(e);%0A                    %7D%0A                    return url;%0A                %7D)%0A                .filter(Objects::nonNull)%0A                .collect(Collectors.toList()
 );%0A    %7D
@@ -2811,16 +2811,36 @@
 eHelper(
+Collection%3CURL%3E urls
 ) %7B%0A    
@@ -2882,35 +2882,150 @@
 ons(
-null, new ResourcesScanner(
+%0A                new ConfigurationBuilder()%0A                        .addScanners(new ResourcesScanner())%0A                        .addUrls(urls
 ));%0A

Configure Resource Helper to use a predefined Collection of URLs