package nl.hsac.fitnesse.fixture.util;

import org.junit.After;
import org.junit.Test;

import java.net.BindException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

public class HttpServerTest {
    private static final String PATH = "/unitTestPath";
    public static final int MIN_EPHEMERAL_PORT = 49152;

    private HttpResponse response = new HttpResponse();
    private HttpServer<HttpResponse> server;

    @Test
    public void secondServerGetsNextAddress() throws Exception {
        HttpServer<HttpResponse> server = storeNew(new HttpServer<>(PATH, response));

        HttpResponse resp = server.getResponse();
        assertSame(response, resp);

        int port1 = checkDefaultAddress(server);

        HttpServer<HttpResponse> server2 = storeNew(new HttpServer<>(PATH, response));
        int port2 = checkDefaultAddress(server2);

        assertEquals(port1 + 1, port2);
    }

    @Test
    public void serverAtLocalPort() throws Exception {
        HttpServer<HttpResponse> server = storeNew(new HttpServer<>(0, PATH, response));

        HttpResponse resp = server.getResponse();
        assertSame(response, resp);

        int port1 = checkDefaultAddress(server);
        isEphemeralPort(port1);

        HttpServer<HttpResponse> server2 = storeNew(new HttpServer<>(0, PATH, response));
        int port2 = checkDefaultAddress(server2);
        isEphemeralPort(port2);

        assertNotEquals(port1, port2);
    }

    @Test
    public void canPassExplicitAddress() throws Exception {
        checkMultipleRandomAtSameAddress("127.0.0.1");
    }

    @Test
    public void canPassExplicitHostname() throws Exception {
        checkMultipleRandomAtSameAddress("localhost");
    }

    @Test
    public void canPassWildcardAddress() throws Exception {
        checkMultipleRandomAtSameAddress("0.0.0.0");
    }

    @Test
    public void canPassExplicitPort() throws Exception {
        int expectedPort = HttpServer.MAX_PORT - 3;
        InetSocketAddress address = new InetSocketAddress(InetAddress.getByName("127.0.0.1"), expectedPort);

        HttpServer<HttpResponse> server = storeNew(new HttpServer<>(address, PATH, response));

        InetSocketAddress addressOfServer = server.getAddress();
        assertSame(address.getAddress(), addressOfServer.getAddress());

        int port = addressOfServer.getPort();
        assertEquals(expectedPort, port);
    }

    @Test
    public void explicitPortFailsWhenInUse() throws Exception {
        canPassExplicitPort();

        try {
            canPassExplicitPort();
            fail("Expected exception");
        } catch (RuntimeException e) {
            Throwable cause = e.getCause();
            assertNotNull("Null cause on " + e, cause);
            assertEquals(BindException.class, cause.getClass());
        }
    }

    private void checkMultipleRandomAtSameAddress(String hostName) throws UnknownHostException {
        InetAddress name = InetAddress.getByName(hostName);
        int port1 = createAndCheckAtRandomFreePort(name);
        int port2 = createAndCheckAtRandomFreePort(name);

        assertNotEquals(port1, port2);
    }

    private int createAndCheckAtRandomFreePort(InetAddress inetAddress) {
        InetSocketAddress address = new InetSocketAddress(inetAddress, 0);

        HttpServer<HttpResponse> server = storeNew(new HttpServer<>(address, PATH, response));

        HttpResponse resp = server.getResponse();

        assertSame(response, resp);

        InetSocketAddress addressOfServer = server.getAddress();
        assertSame(address.getAddress(), addressOfServer.getAddress());

        int port = addressOfServer.getPort();
        isEphemeralPort(port);

        return port;
    }

    private int checkDefaultAddress(HttpServer<HttpResponse> aServer) throws UnknownHostException {
        InetSocketAddress address = aServer.getAddress();
        assertNotNull(address);

        InetAddress inetAddress = address.getAddress();
        assertEquals(InetAddress.getLocalHost(), inetAddress);

        int port = address.getPort();
        assertTrue("Bad port: " + port, port >= 8000);

        return port;
    }

    private void isEphemeralPort(int port) {
        assertTrue(port >= MIN_EPHEMERAL_PORT);
    }

    public HttpServer<HttpResponse> storeNew(HttpServer<HttpResponse> newServer) {
        if (server != null) {
            server.stopServer();
        }
        server = newServer;
        return server;
    }

    @After
    public void tearDown() {
        if (server != null) {
            server.stopServer();
        }
    }

}
@@ -44,23 +44,95 @@
 ort 
-org.junit.After
+nl.hsac.fitnesse.fixture.slim.HttpTest;%0Aimport org.junit.After;%0Aimport org.junit.Before
 ;%0Aim
@@ -730,29 +730,8 @@
 onse
- = new HttpResponse()
 ;%0A  
@@ -774,16 +774,176 @@
 erver;%0A%0A
+    @Before%0A    public void setUp() %7B%0A        response = new HttpResponse();%0A        response.setResponse(%22Hallo%22);%0A        response.setStatusCode(200);%0A    %7D%0A%0A
     @Tes
@@ -2906,16 +2906,66 @@
 , port);
+%0A%0A        checkGetFromIsPossible(addressOfServer);
 %0A    %7D%0A%0A
@@ -4242,32 +4242,82 @@
 ralPort(port);%0A%0A
+        checkGetFromIsPossible(addressOfServer);%0A%0A
         return p
@@ -4737,35 +4737,430 @@
 );%0A%0A        
-return port
+checkGetFromIsPossible(address);%0A%0A        return port;%0A    %7D%0A%0A    private void checkGetFromIsPossible(InetSocketAddress address) %7B%0A        String url = %22http://%22 + address.getHostName() + %22:%22 + address.getPort() + PATH;%0A        HttpTest test = new HttpTest();%0A%0A        test.getFrom(url);%0A%0A        assertEquals(response.getResponse(), test.response());%0A%0A        assertEquals(1, server.getRequestsReceived())
 ;%0A    %7D%0A%0A   
@@ -5220,16 +5220,51 @@
 ertTrue(
+%22Unexpected port number: %22 + port, 
 port %3E= 

Add actually reading from servers created