package com.matt.forgehax.util.mod.loader;

import com.google.common.collect.Lists;
import com.google.common.reflect.ClassPath;
import com.matt.forgehax.Globals;
import com.matt.forgehax.Helper;
import com.matt.forgehax.util.mod.BaseMod;
import net.minecraft.launchwrapper.Launch;

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import static com.matt.forgehax.Helper.getLog;

/**
 * Created on 5/16/2017 by fr1kin
 */
public class ForgeHaxModLoader implements Globals {

    public static Collection<Class<? extends BaseMod>> getClassesInPackage(String pack) {
        try {
            ClassPath classPath = ClassPath.from(getClassLoader());
            return filterClassInfo(classPath.getTopLevelClasses(pack));
        } catch (IOException e) {
            Helper.handleThrowable(e);
        }
        return Collections.emptyList();
    }

    @SuppressWarnings("unchecked")
    protected static Collection<Class<? extends BaseMod>> filterClassInfo(Collection<ClassPath.ClassInfo> input) {
        final List<Class<? extends BaseMod>> classes = Lists.newArrayList();
        input.forEach(info -> {
            try {
                Class<?> clazz = info.load();
                if(isClassValid(clazz)) {
                    classes.add((Class<? extends BaseMod>)clazz);
                } else
                    getLog().info(String.format("\"%s\" is not a valid class!", clazz.getSimpleName()));
            } catch (Exception e) {
                getLog().warn(String.format("[%s] '%s' is not a valid mod class: %s", e.getClass().getSimpleName(), info.getSimpleName(), e.getMessage()));
            }
        });
        return Collections.unmodifiableCollection(classes);
    }

    protected static boolean isClassValid(Class<?> clazz) {
        try {
            return (clazz.isAnnotationPresent(RegisterMod.class)
                    && BaseMod.class.isAssignableFrom(clazz)
                    && clazz.getDeclaredConstructor() != null);
        } catch (Throwable t) {
            return false;
        }
    }

    public static Collection<BaseMod> loadClasses(Collection<Class<? extends BaseMod>> classes) {
        List<BaseMod> mods = Lists.newArrayList();
        classes.forEach(clazz -> {
            try {
                mods.add(clazz.getDeclaredConstructor().newInstance());
            } catch (Exception e) {
                Helper.printStackTrace(e);
                getLog().warn(String.format("Failed to create a new instance of '%s': %s", clazz.getSimpleName(), e.getMessage()));
            }
        });
        return Collections.unmodifiableCollection(mods);
    }

    private static ClassLoader getClassLoader() {
        return Launch.classLoader;
    }
}

@@ -273,16 +273,52 @@
 .Launch;
+%0Aimport org.reflections.Reflections;
 %0A%0Aimport
@@ -420,16 +420,42 @@
 il.List;
+%0Aimport java.util.Objects;
 %0A%0Aimport
@@ -747,16 +747,19 @@
 from(get
+FML
 ClassLoa
@@ -762,24 +762,138 @@
 sLoader());%0A
+            Reflections reflections = new Reflections(pack);%0A            reflections.getSubTypesOf(Object.class);%0A
             
@@ -1448,30 +1448,8 @@
 zz))
- %7B%0A                   
  cla
@@ -1495,136 +1495,8 @@
 z);%0A
-                %7D else%0A                    getLog().info(String.format(%22%5C%22%25s%5C%22 is not a valid class!%22, clazz.getSimpleName()));%0A
     
@@ -1866,16 +1866,55 @@
     
-return (
+Objects.requireNonNull(clazz);%0A            if(!
 claz
@@ -1953,16 +1953,17 @@
 d.class)
+)
 %0A       
@@ -1971,23 +1971,88 @@
         
-    && 
+throw new Exception(%22missing @RegisterMod annotation%22);%0A            if(!
 BaseMod.
@@ -2080,16 +2080,17 @@
 m(clazz)
+)
 %0A       
@@ -2102,15 +2102,77 @@
     
-    && 
+throw new Exception(%22does not extend BaseMod class%22);%0A            if(
 claz
@@ -2202,49 +2202,244 @@
 r() 
-!
+=
 = null)
-;%0A        %7D catch (Throwable t) %7B
+%0A                throw new Exception(%22missing default constructor%22);%0A            return true;%0A        %7D catch (Throwable t) %7B%0A            getLog().warn(String.format(%22Invalid class %5C%22%25s%5C%22: %25s%22, clazz.getName(), t.getMessage()));
 %0A   
@@ -3083,24 +3083,27 @@
 ssLoader get
+FML
 ClassLoader(

debug messages for isClassValid