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

import org.junit.Test;

import net.ranides.assira.io.uri.URIBuilder;
import net.ranides.assira.io.uri.URIFlags;
import net.ranides.assira.io.uri.URIHandle;
import net.ranides.assira.io.uri.URITime;
import net.ranides.assira.text.IOStrings;
import net.ranides.assira.trace.ExceptionUtils;

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

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

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

    private static URIHandle resolve(URI uri) throws IOException {
        return new CFileHandler().resolve(uri);
    }

    private static URIBuilder uri(String file) {
        return new URIBuilder(new File(file).toURI());
    }

    @Test
    public void testTime() throws URISyntaxException, IOException {
        URI uri1 = uri("../assira.test/src/main/resources/text").build();
        URI uri2 = uri("../assira.test/src/main/resources/text/info.txt").build();

        URIHandle handle1 = resolve(uri1);
        URIHandle handle2 = resolve(uri2);

        assertNotNull(handle1.time(URITime.MODIFIED));
        assertNotNull(handle1.time(URITime.ACCESSED));
        assertNotNull(handle1.time(URITime.CREATED));

        assertNotNull(handle2.time(URITime.MODIFIED));
        assertNotNull(handle2.time(URITime.ACCESSED));
        assertNotNull(handle2.time(URITime.CREATED));


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

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

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

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

        URI uri1 = uri("..").build();
        URI uri2 = uri("../assira.test/src/main/resources/text").build();
        URI uri3 = uri("../assira.test/src/main/resources/text/info.txt").build();
        URI uri4 = uri("../assira.test/src/main/java/net/ranides/assira/test").build();
        URI uri5 = uri("not-found").build();
        URI uri6 = uri("../assira.test/src/main/resources/text/info.txt").param("charset","UTF-8").build();

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

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

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

        assertTrue("Invalid number of files inside root directory", handle1.scan().size() > 20);
        assertEquals(Arrays.asList("indir","text"), handle3.parent().parent().scan().map(f-> asName(f)).sort().list());
        assertEquals(Arrays.asList("info.txt"), handle2.scan().map(f-> asName(f)).sort().list());
        assertThrows(IOException.class, ()->{
            handle3.scan().list();
        });
        assertEquals(8, handle4.scan().map(f-> asName(f)).size());

        assertEquals(URIFlags.collect(READABLE, WRITABLE, EXECUTE, EXISTS, DIR, BINARY), handle2.flags());
        assertEquals(1, handle2.size());
        assertEquals(8, handle4.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.file().getName().toString();
        } catch (IOException e) {
            throw ExceptionUtils.rethrow(e);
        }
    }

}