package org.bdware.sc.engine;

import wrp.jdk.nashorn.api.scripting.ClassFilter;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

public class YJSClassLoader extends URLClassLoader {
    ClassFilter classFilter;
    File libDir = null;
    List<String> toLoad = new ArrayList<>();

    public YJSClassLoader(ClassLoader parent, ClassFilter cf) {
        super(new URL[]{}, parent);
        classFilter = cf;
    }

    @Override
    public Class<?> findClass(final String fullName) throws ClassNotFoundException {
        if (classFilter != null && !classFilter.exposeToScripts(fullName)) {
            throw new ClassNotFoundException(fullName);
        }
        return super.findClass(fullName);
    }

    public Class<?> defineStubClass(String name, byte[] bytes) {
        return defineClass(name, bytes, 0, bytes.length);
    }

    public void loadJar(InputStream inputStream, String path) {
        String fileName = unzipLibrary(inputStream, path);
        try {
            super.addURL(new File(fileName).toURI().toURL());
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private byte[] asByteArray(InputStream in) {
        try {
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            byte[] buff = new byte[1024];

            for (int len = 0; (len = in.read(buff)) > 0; ) {
                bo.write(buff, 0, len);
            }
            return bo.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public String unzipLibrary(InputStream inputStream, String name) {
        try {
            if (libDir == null) {
                libDir = new File(System.getProperty("java.io.tmpdir"), "yjscontract_" + System.currentTimeMillis());
                libDir.mkdirs();
            }
            File f = new File(libDir, name);
            f.createNewFile();
            toLoad.add(f.getAbsolutePath());
            FileOutputStream fout = new FileOutputStream(f);
            byte[] buff = new byte[1024 * 100];
            for (int k = 0; (k = inputStream.read(buff)) > 0; ) {
                fout.write(buff, 0, k);
            }
            fout.close();
            return f.getAbsolutePath();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "/dev/null";
    }

    private void addDirToPath(String s) {
        try {
         //   System.out.println("[YJSClassloader] addtopath:" + s);
            Field field = ClassLoader.class.getDeclaredField("sys_paths");
            field.setAccessible(true);
            String[] path = (String[]) field.get(null);
            String[] temp = new String[path.length + 1];
            System.arraycopy(path, 0, temp, 0, path.length);
            temp[path.length] = s;
            field.set(null, temp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void loadLibraries() {
        if (libDir != null)
            addDirToPath(libDir.getAbsolutePath());
    }

}
