package com.moebuff.discord.reflect;

import com.moebuff.discord.utils.URLUtils;
import com.moebuff.discord.utils.UnhandledException;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ClassUtils;

import java.io.File;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 类型工具
 *
 * @author muto
 * @see ClassUtils
 */
public class ClassKit {
    /**
     * 创建一个新实例，本质上就是调用构造方法。如果被创建的类尚未初始化，则初始化这个类。此封装便于类型转换。
     *
     * @param c    对象的类型
     * @param args 将作为变量传递给构造方法调用的对象数组；
     *             基本类型的值被包装在适当类型的包装器对象（如 Float 中的 float）中。
     *             如果该参数存在，则调用对应的构造方法。
     * @return 此对象所表示的类的一个新分配的实例。
     * @throws UnhandledException 如果此 Class 表示一个抽象类、接口、数组类、基本类型或 void； 或者该类没有
     *                            null 构造方法； 或者由于其他某种原因导致实例化失败。
     * @see ConstructorKit#newInstance(Constructor, Object...)
     */
    public static <T> T newInstance(Class<T> c, Object... args) {
        if (ArrayUtils.isEmpty(args)) {
            try {
                return c.newInstance();
            } catch (InstantiationException e) {
                throw new UnhandledException(e);
            } catch (IllegalAccessException e) {
                Constructor<T> ctor0 = ConstructorKit.getConstructor(c);
                return ConstructorKit.newInstance(ctor0);
            }
        }
        Class<?>[] parameterTypes = ClassUtils.toClass(args);
        Constructor<T> ctor = ConstructorKit.getConstructor(c, parameterTypes);
        return ConstructorKit.newInstance(ctor, args);
    }

    public static Class[] getClasses(String pkg) {
        return getClasses(pkg, false);
    }

    public static Class[] getClasses(String pkg, boolean deep) {
        Set<Class> classes = new HashSet<>();
        ClassLoader loader = LoaderUtil.getThreadContextClassLoader();

        URL url = loader.getResource(pkg.replace(".", "/"));
        if (url != null) {
            String protocol = url.getProtocol();

            if ("file".equals(protocol)) {
                classes = getClasses(url.getPath(), pkg, deep);
            } else if ("jar".equals(protocol)) {
                classes = getClasses(URLUtils.getJarFile(url), pkg, deep);
            }
        }
        return classes.toArray(new Class[classes.size()]);
    }

    private static Set<Class> getClasses(String path, final String pkg, final boolean deep) {
        final Set<Class> classes = new HashSet<>();
        File[] list = new File(path).listFiles(pathname -> {
            boolean isDir = pathname.isDirectory();

            if (isDir && deep) {
                Set<Class> child = getClasses(pathname.getPath(), pkg, true);
                classes.addAll(child);
            }
            return !isDir;
        });

        if (list != null) {
            String name;
            Class clazz;
            for (File f : list) {
                name = f.getName();
                if (!name.endsWith(".class") || name.contains("$")) {
                    continue;//排除非法的类文件
                }

                name = FilenameUtils.getBaseName(name);
                name = String.format("%s.%s", pkg, name);
                clazz = LoaderUtil.loadClass(name, true);
                classes.add(clazz);
            }
        }
        return classes;
    }

    private static Set<Class> getClasses(JarFile file, String pkg, boolean deep) {
        Set<Class> classes = new HashSet<>();
        Enumeration<JarEntry> enumeration = file.entries();
        while (enumeration.hasMoreElements()) {
            JarEntry entry = enumeration.nextElement();
            if (entry.isDirectory()) continue;

            String name = entry.getName();
            String path = FilenameUtils.getPathNoEndSeparator(name).replace("/", ".");
            name = FilenameUtils.getName(name);
            if (!name.endsWith(".class") || name.contains("$")
                    || !path.startsWith(pkg)) {
                continue;
            }

            name = FilenameUtils.getBaseName(name);
            name = String.format("%s.%s", pkg, name);
            Class clazz = LoaderUtil.loadClass(name, true);
            if (deep || path.replace(pkg, "").isEmpty()) {
                classes.add(clazz);
            }
        }
        return classes;
    }
}

@@ -1802,32 +1802,174 @@
  false);%0A    %7D%0A%0A
+    /**%0A     * %E8%8E%B7%E5%8F%96%E6%8C%87%E5%AE%9A%E5%8C%85%E4%B8%8B%E7%9A%84%E7%B1%BB%E9%9B%86%E5%90%88%E3%80%82%E8%8B%A5%E8%A6%81%E6%B7%B1%E5%85%A5%E5%AD%90%E5%8C%85%E8%AF%B7%E5%B0%86 deep %E8%AE%BE%E7%BD%AE%E4%B8%BA true%0A     *%0A     * @param pkg  %E5%8C%85%E5%90%8D%0A     * @param deep %E4%B8%BAtrue%EF%BC%8C%E5%85%81%E8%AE%B8%E9%80%92%E5%BD%92%E5%AD%90%E5%8C%85%0A     * @return %E6%8C%87%E5%AE%9A%E5%8C%85%E4%B8%8B%E7%9A%84%E7%B1%BB%E9%9B%86%E5%90%88%0A     */%0A
     public stati
@@ -4260,33 +4260,95 @@
 ;%0A            %7D%0A
-%0A
+            if (deep %7C%7C path.replace(pkg, %22%22).isEmpty()) %7B%0A    
             name
@@ -4387,32 +4387,36 @@
 e);%0A            
+   
+ 
 name = String.fo
@@ -4433,32 +4433,36 @@
 s%22, pkg, name);%0A
+    
             Clas
@@ -4509,67 +4509,8 @@
 e);%0A
-            if (deep %7C%7C path.replace(pkg, %22%22).isEmpty()) %7B%0A
     

add javadoc