package net.ranides.assira.io.uri.impl;

import net.ranides.assira.ContractTesters;
import net.ranides.assira.io.uri.URIFlags;
import net.ranides.assira.io.uri.URIHandle;
import net.ranides.assira.io.uri.URIResolver;
import net.ranides.assira.reflection.util.ClassUtils;
import net.ranides.assira.text.ResolveFormatUtils;
import net.ranides.assira.text.StringUtils;
import net.ranides.assira.trace.ExceptionUtils;
import org.junit.Test;

import java.io.IOException;
import java.net.*;
import java.util.Arrays;
import java.util.List;

import static net.ranides.assira.io.uri.URIFlags.*;
import static net.ranides.assira.junit.NewAssert.*;

/**
 * @author msieron
 */
public class CClassPathHandlerTest {

    private static final URIResolver re = new URIResolver()
        .register(CClassPathHandler.class)
        .register(CJarHandler.class)
        .register(CFileHandler.class);

    @Test
    public void testScan() throws IOException, URISyntaxException {
        List<String> expected2 = Arrays.asList(
            "/test-classes/reflective/constructors/1.txt",
            "/test-classes/reflective/constructors/2.txt",
            "/test-classes/reflective/constructors/3.txt",
            "/test-classes/reflective/constructors/4.txt",
            "/test-classes/reflective/constructors/5.txt"
        );
        List<String> expected3 = Arrays.asList(
            "net/ranides/assira/test/Type1.class",
            "net/ranides/assira/test/Type2.class",
            "net/ranides/assira/test/Type3.class",
            "net/ranides/assira/test/Type4.class",
            "net/ranides/assira/test/TypeLoader1.class",
            "net/ranides/assira/test/TypeLoader2.class",
            "net/ranides/assira/test/TypeLoader3.class"
        );

        ClassLoader prev = Thread.currentThread().getContextClassLoader();
        try {
            ClassLoader loader = ClassUtils.loader(ClassUtils.loader(), ContractTesters.JAR_TEST.getCanonicalFile());
            Thread.currentThread().setContextClassLoader(loader);

            assertThrows(e -> e instanceof IOException && e.getMessage().contains("not found"), () -> {
                re.resolve("cp://notfound").scan().map(this::jarname).list();
            });

            URIHandle handle1 = re.resolve("cp://indir");
            URIHandle handle2 = re.resolve("cp://reflective/constructors");
            URIHandle handle3 = re.resolve("cp://net/ranides/assira/test");
            URIHandle handle4 = re.resolve("cp://net/ranides/assira/test/Type1.class");

            assertEquals("[indir/1.txt, indir/2.txt, indir/3.txt, indir/info.txt]", handle1.scan().map(this::jarname).sort().list().toString());

            assertEquals(expected2, handle2.scan().map(this::filename).sort().list());

            assertEquals(expected3, handle3.scan().map(this::jarname).sort().list());

            assertEquals(URIFlags.collect(READABLE, FILE, BINARY, SIZE), handle4.flags());
            byte[] array = new byte[4];
            assertEquals(4, handle4.istream().read(array));
            assertEquals("CA FE BA BE", ResolveFormatUtils.vformat("{0,hex,stream}", array));
        } finally {
            Thread.currentThread().setContextClassLoader(prev);
        }

    }

    private void printme(URIHandle handler) {
        try {
            System.out.println(" - " + handler.uri());
        } catch (IOException e) {
            throw ExceptionUtils.rethrow(e);
        }
    }

    private String filename(URIHandle f) {
        try {
            return StringUtils.after(f.uri().toString(), "/target");
        } catch (IOException cause) {
            throw ExceptionUtils.rethrow(cause);
        }
    }

    private String jarname(URIHandle f) {
        try {
            return f.uri().toString().split("!/")[1];
        } catch (IOException cause) {
            throw ExceptionUtils.rethrow(cause);
        }
    }

}