package net.ranides.assira.reflection.impl;

import net.ranides.asm.ClassReader;

import net.ranides.assira.generic.SerializationUtils;
import net.ranides.assira.reflection.*;

import java.io.IOException;
import java.io.Serializable;
import java.nio.file.Files;
import java.nio.file.Path;

/**
 * Default implementation of IClassLoader.
 *
 * It is serializable class, recreates loader using {@code IClassLoader.getInstance(name)}
 */
public class AClassLoader extends ClassLoader implements IClassLoader, Serializable {

    private final String name;

    protected AClassLoader(String name) {
        super();
        this.name = name;
    }

    protected AClassLoader(String name, ClassLoader parent) {
        super(parent);
        this.name = name;
    }

    protected AClassLoader(String name, IClassLoader parent) {
        super(parent.reflective());
        this.name = name;
    }

    @Override
    public ClassLoader reflective() {
        return this;
    }

    public String name() {
        return name;
    }

    @Override
    public final IClass<?> defineIClass(Path path) throws IOException {
        return defineIClass(Files.readAllBytes(path));
    }

    @Override
    public final IClass<?> defineIClass(byte[] bytecode) {
        String classname = new ClassReader(bytecode).getClassName().replace('/', '.');
        return defineIClass(classname, bytecode);
    }

    @Override
    public final IClass<?> defineIClass(String name, byte[] bytecode) {
        return defineIClass(name, bytecode, 0, bytecode.length);
    }

    @Override
    public IClass<?> defineIClass(String name, byte[] bytecode, int off, int len) {
        return IClass.typeinfo(defineClass(name, bytecode, off, len));
    }

    protected Object writeReplace() {
        final String cName = this.name;
        return SerializationUtils.proxy(() -> IClassLoader.getInstance(cName));
    }

}
