/*
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.io.uri.impl;

import net.ranides.assira.collection.prototype.GenericMapBuilder;
import net.ranides.assira.credentials.UserProperty;
import net.ranides.assira.credentials.UserStoreList;
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.io.uri.URITime;
import net.ranides.assira.junit.JCategories;
import net.ranides.assira.text.Charsets;
import net.ranides.assira.text.IOStrings;
import org.junit.Test;
import org.junit.experimental.categories.Category;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Duration;
import java.time.Instant;

import static net.ranides.assira.io.uri.URIFlags.BINARY;
import static net.ranides.assira.io.uri.URIFlags.EXISTS;
import static net.ranides.assira.io.uri.URIFlags.FILE;
import static net.ranides.assira.io.uri.URIFlags.READABLE;
import static net.ranides.assira.io.uri.URIFlags.SEEK;
import static net.ranides.assira.io.uri.URIFlags.SIZE;
import static net.ranides.assira.io.uri.URIFlags.TEXT;
import static net.ranides.assira.junit.NewAssert.assertEquals;
import static net.ranides.assira.junit.NewAssert.assertThrows;
import static net.ranides.assira.junit.NewAssert.assertTrue;

/**
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
@Category(JCategories.Online.class)
public class CHTTPHandlerTest {

    @Test
    public void testDynamicList() throws IOException, URISyntaxException {
        
        URI uri = new URI("http://maven.ranides.net/net/ranides/assira/0.58/");
        URIHandle handle1 = resolve(uri);
        
        assertEquals(uri, handle1.uri());
        assertEquals(Charsets.UTF8, handle1.charset());
        assertEquals(true, handle1.exists());
        assertEquals(URIFlags.constant(READABLE, EXISTS, FILE, TEXT), handle1.flags());
        assertEquals("HTML PUBLIC \"-//W3C//DTD HTML 3", IOStrings.read(handle1.istream(10,40), handle1.charset()));
        
        URIHandle handle2 = resolve(uri);
        String content = IOStrings.read(handle2.reader());
        assertTrue(content.contains("<title>Index of /net/ranides/assira/0.58</title>"));
        assertEquals(Instant.now(), handle2.time(URITime.MODIFIED), Duration.ofMinutes(60));
        assertEquals(content.length(), handle2.size());
        
        URIHandle handle3 = resolve(uri);
        assertEquals(-1, handle3.size());

    }
    
    @Test
    public void testStaticText() throws IOException, URISyntaxException {
        URI uri = new URI("https://ranides.net/googlecc30a00851b96b06.html");
        URIHandle handle1 = resolve(uri);

        assertEquals(uri, handle1.uri());
        assertEquals(Charsets.UTF8, handle1.charset());
        assertEquals(true, handle1.exists());
        assertEquals(URIFlags.constant(READABLE, EXISTS, FILE, TEXT, SIZE, SEEK), handle1.flags());
        assertEquals("fication: google", IOStrings.read(handle1.istream(16,31), handle1.charset()));
        assertThrows(IOException.class, ()->{
            IOStrings.read(handle1.reader());
        });
        
        URIHandle handle2 = resolve(uri);
        assertEquals(53, IOStrings.read(handle2.reader()).length());
        assertEquals(Instant.parse("2012-10-26T12:57:36Z"), handle2.time(URITime.MODIFIED));
        assertThrows(IOException.class, ()->{
            handle2.time(URITime.ACCESSED);
        });
        assertEquals(53, handle2.size());
    }

    @Test
    public void testPassword() throws IOException, URISyntaxException {
        URIResolver.DEFAULT.users(new UserStoreList()
            .add(GenericMapBuilder.<String>hash()
                .put(UserProperty.ACCOUNT, "utf8test")
                .put(UserProperty.LOGIN, "utf8test")
                .put(UserProperty.PASSWORD, "końrybakoń")
                .map()
            )
            .add(GenericMapBuilder.<String>hash()
                .put(UserProperty.ACCOUNT, "tester")
                .put(UserProperty.LOGIN, "tester")
                .put(UserProperty.PASSWORD, "tester")
                .map()
            )
        );

        URI uri1 = new URI("http://tester@sandbox.ranides.net/pass/");
        assertTrue(resolve(uri1).text(Charsets.UTF8).contains("<title>Index of /pass</title>"));

        URI uri2 = new URI("http://utf8test@sandbox.ranides.net/pass/");
        assertTrue(resolve(uri2).text(Charsets.UTF8).contains("<title>Index of /pass</title>"));

        URI uri3 = new URI("http://unknown@sandbox.ranides.net/pass/");
        assertThrows(e -> e.getMessage().contains("401"), () -> {
            resolve(uri3).text(Charsets.UTF8).contains("<title>Index of /pass</title>");
        });
    }
    
    @Test
    public void testNotFound() throws IOException, URISyntaxException {
        URI uri = new URI("http://maven.ranides.net/net/ranides/assira/0.58/assira-0.58.po");
        URIHandle handle = resolve(uri);
        
        assertEquals(uri, handle.uri());
        assertEquals(Charsets.UTF8, handle.charset());
        assertEquals(false, handle.exists());
        assertEquals(URIFlags.constant(FILE, TEXT, SIZE), handle.flags());
        assertEquals(Instant.now(), handle.time(URITime.MODIFIED), Duration.ofMinutes(60));
        
        assertThrows(IOException.class, ()->{
            handle.size();
        });
        
        assertThrows(FileNotFoundException.class, ()->{
            IOStrings.read(handle.istream(10,15), handle.charset());
        });
        
        assertThrows(FileNotFoundException.class, ()->{
            IOStrings.read(handle.reader());
        });
    }
    
    @Test
    public void testDynamicPage() throws IOException, URISyntaxException {
        URI uri = new URI("http://info.ranides.net/");
        URIHandle handle1 = resolve(uri);
        assertEquals(URIFlags.constant(READABLE, EXISTS, FILE, TEXT), handle1.flags());
        assertEquals("/DTD XHTML 1.0 Trans", IOStrings.read(handle1.istream(30, 50), Charsets.UTF8));
        assertEquals(-1, handle1.size());
        
        URIHandle handle2 = resolve(uri);
        assertTrue(IOStrings.read(handle2.reader()).contains("This program is free software;"));
        assertEquals(-1, handle2.size());
        
        assertTrue(IOStrings.read(resolve(uri).reader(Charsets.UTF8)).contains("This program is free software;"));
    }

    private static URIHandle resolve(URI uri) throws IOException {
        return new CHTTPHandler().resolve(uri);
    }
    
    @Test
    public void testBinary() throws IOException, URISyntaxException {   
        URI uri = new URI("http://maven.ranides.net/net/ranides/assira/0.58/assira-0.58.jar.sha1");
        URIHandle handle1 = resolve(uri);
        
        assertEquals(uri, handle1.uri());
        assertThrows(IOException.class, ()->{
            handle1.charset();
        });
        assertThrows(IOException.class, ()->{
            handle1.reader();
        });
        assertEquals(true, handle1.exists());
        assertEquals(URIFlags.constant(READABLE, EXISTS, FILE, BINARY, SIZE, SEEK), handle1.flags());
        assertEquals(Instant.parse("2013-03-08T01:58:30Z"), handle1.time(URITime.MODIFIED));
        assertEquals(40, handle1.size());
        
        URIHandle handle2 = resolve(uri);
        assertEquals("61b37c0973bc00bd33606a2f5050e64baec3a7df", IOStrings.read(handle2.istream(), Charsets.US_ASCII));
        
        URIHandle handle3 = resolve(uri);
        assertEquals("61b37c0973bc00bd33606a2f5050e64baec3a7df", IOStrings.read(handle3.reader(Charsets.US_ASCII)));
    }
    
    @Test
    public void testError() throws IOException, URISyntaxException { 
        URIHandle handle1 = resolve(new URI("http://m.maven.ranides.net/"));
        assertEquals(URIFlags.constant(FILE), handle1.flags());
        
        URIHandle handle2 = resolve(new URI("http://no.domain/"));
        assertEquals(URIFlags.constant(FILE), handle2.flags());
    }
    
    @Test
    public void testCopy() throws IOException, URISyntaxException {
        URI uri = new URI("http://maven.ranides.net/net/ranides/assira/0.58/assira-0.58.jar.sha1");
        URIHandle input = resolve(uri);
        File file = File.createTempFile("CHttpHandler", ".test");
        file.deleteOnExit();
        URIHandle target = new CFileHandler().resolve(file.toURI());

        input.copy(target);
        assertEquals("61b37c0973bc00bd33606a2f5050e64baec3a7df",IOStrings.read(file, Charsets.UTF8));
    }
    
    @Test
    public void testMove() throws IOException, URISyntaxException {
        URIHandle src = resolve(new URI("http://maven.ranides.net/net/ranides/assira/0.58/assira-0.58.jar.sha1"));
        URIHandle dst = resolve(new URI("http://maven.ranides.net/net/ranides/assira/0.58/assira-0.58.jar.sha1m"));
        assertThrows(IOException.class, ()->{
            src.move(dst);
        });
    }
    
}
