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

import static net.ranides.assira.junit.NewAssert.*;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;

import org.junit.Test;

import net.ranides.assira.ContractTesters;
import net.ranides.assira.io.uri.*;
import net.ranides.assira.text.IOStrings;
import net.ranides.assira.trace.ExceptionUtils;

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

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

    private static URI uri(String scheme, String file) {
        return new URIBuilder(ContractTesters.JAR_TEST.toURI() + "!/" + file).scheme(scheme).build();
    }

    private static URI uri(String scheme, String file, String charset) {
        return new URIBuilder(ContractTesters.JAR_TEST.toURI() + "!/" + file).scheme(scheme).param("charset", charset).build();
    }

    @Test
    public void testTime() throws URISyntaxException, IOException {
        URI uri1 = uri("jar", "text");
        URI uri2 = uri("jar", "text/info.txt");
        URI uri3 = uri("jar:file", "text/info.txt");

        URIHandle handle1 = re.resolve(uri1);
        URIHandle handle2 = re.resolve(uri2);
        URIHandle handle3 = re.resolve(uri3);

        assertNotNull(handle1.time(URITime.MODIFIED));
        assertNotNull(handle2.time(URITime.MODIFIED));
        assertNotNull(handle3.time(URITime.MODIFIED));

        assertThrows(UnsupportedOperationException.class, () -> {
            handle1.time(URITime.ACCESSED);
        });
        assertThrows(UnsupportedOperationException.class, () -> {
            handle1.time(URITime.CREATED);
        });
        assertThrows(UnsupportedOperationException.class, () -> {
            handle1.time(URITime.META_MODIFIED);
        });


        assertThrows(UnsupportedOperationException.class, () -> {
            handle2.time(URITime.ACCESSED);
        });
        assertThrows(UnsupportedOperationException.class, () -> {
            handle2.time(URITime.CREATED);
        });
        assertThrows(UnsupportedOperationException.class, () -> {
            handle2.time(URITime.META_MODIFIED);
        });


        handle1.close();
        handle2.close();
    }

    @Test
    public void testParent() throws IOException {
        URIHandle handle = re.resolve(uri("jar", "text/info.txt"));

        assertTrue(handle.uri().toString().endsWith("!/text/info.txt"));
        assertTrue(handle.parent().uri().toString().endsWith("!/text"));
        assertTrue(handle.parent().parent().uri().toString().endsWith("!/"));
        assertTrue(handle.parent().parent().parent().uri().toString().endsWith("!/"));

        handle.close();
    }

    @Test
    public void testSize() throws URISyntaxException, IOException {
        try(URIHandle handle = re.resolve(uri("jar","text/info.txt"))) {
            assertEquals(11, handle.size());
        }
        try(URIHandle handle = re.resolve(uri("jar","text"))) {
            assertEquals(1, handle.size());
        }
        try(URIHandle handle = re.resolve(uri("jar","net/ranides/assira/test"))) {
            assertEquals(7, handle.size());
        }

    }

    @Test
    public void testBasic() throws URISyntaxException, IOException {

        URI uri1 = uri("jar", "");
        URI uri2 = uri("jar", "text");
        URI uri3 = uri("jar", "text/info.txt");
        URI uri4 = uri("jar", "net/ranides/assira/test");
        URI uri5 = uri("jar", "not-found");
        URI uri6 = uri("jar", "text/info.txt", "UTF-8");

        URIHandle handle1 = re.resolve(uri1);
        URIHandle handle2 = re.resolve(uri2);
        URIHandle handle3 = re.resolve(uri3);
        URIHandle handle4 = re.resolve(uri4);
        URIHandle handle5 = re.resolve(uri5);
        URIHandle handle6 = re.resolve(uri6);

        assertEquals(11, handle3.size());
        assertEquals(URIFlags.collect(URIFlags.READABLE, URIFlags.FILE, URIFlags.BINARY, URIFlags.SIZE), handle3.flags());
        assertEquals("Hello world", IOStrings.read(handle3.reader()));

        assertEquals(11, handle6.size());
        assertEquals(URIFlags.collect(URIFlags.READABLE, URIFlags.FILE, URIFlags.TEXT, URIFlags.SIZE), handle6.flags());
        assertEquals("Hello world", IOStrings.read(handle6.reader()));

        assertEquals(Arrays.asList("META-INF/", "indir/", "net/", "text/"), handle1.scan().map(f-> asName(f)).sort().list());
        assertEquals(Arrays.asList("META-INF/", "indir/", "net/", "text/"), handle3.parent().parent().scan().map(f-> asName(f)).sort().list());
        assertEquals(Arrays.asList("text/info.txt"), handle2.scan().map(f-> asName(f)).sort().list());
        assertThrows(IOException.class, ()->{
            handle3.scan().list();
        });
        assertEquals(7, handle4.scan().map(f-> asName(f)).size());

        assertEquals(URIFlags.collect(URIFlags.DIR), handle2.flags());
        assertEquals(1, handle2.size());
        assertTrue(handle2.exists());

        assertEquals(URIFlags.collect(), handle5.flags());
        assertFalse(handle5.exists());

        handle1.close();
        handle2.close();
        handle3.close();
        handle4.close();
        handle5.close();
    }

    private String asName(URIHandle handle) {
        try {
            return handle.uri().toString().split("!/")[1];
//            return URIUtils.getParam(handle.uri(), "file").get();
        } catch (IOException e) {
            throw ExceptionUtils.rethrow(e);
        }
    }

}