package com.github.dockerjava.core.command;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.model.Frame;
import com.github.dockerjava.api.model.StreamType;
import com.github.dockerjava.client.AbstractDockerClientTest;
import com.github.dockerjava.core.DockerClientBuilder;

@Test(groups = "integration")
public class FrameReaderITest {

    private DockerClient dockerClient;

    private DockerfileFixture dockerfileFixture;

    @BeforeTest
    public void beforeTest() throws Exception {
        dockerClient = DockerClientBuilder.getInstance().build();
        dockerfileFixture = new DockerfileFixture(dockerClient, "frameReaderDockerfile");
        dockerfileFixture.open();
    }

    @AfterTest
    public void deleteDockerContainerImage() throws Exception {
        dockerfileFixture.close();
        dockerClient.close();
    }

    @Test
    public void canCloseFrameReaderAndReadExpectedLines() throws Exception {

        // wait for the container to be successfully executed
        int exitCode = dockerClient.waitContainerCmd(dockerfileFixture.getContainerId())
                .exec(new WaitContainerResultCallback()).awaitStatusCode();
        assertEquals(0, exitCode);

        Iterator<Frame> response = getLoggingFrames().iterator();

        assertEquals(response.next(), new Frame(StreamType.STDOUT, "to stdout\n".getBytes()));
        assertEquals(response.next(), new Frame(StreamType.STDERR, "to stderr\n".getBytes()));
        assertFalse(response.hasNext());

    }

    private List<Frame> getLoggingFrames() throws Exception {

        FrameReaderITestCallback collectFramesCallback = new FrameReaderITestCallback();

        dockerClient.logContainerCmd(dockerfileFixture.getContainerId()).withStdOut(true).withStdErr(true)
                .withTailAll()
                // we can't follow stream here as it blocks reading from resulting InputStream infinitely
                // .withFollowStream()
                .exec(collectFramesCallback).awaitCompletion();

        return collectFramesCallback.frames;
    }

    @Test
    public void canLogInOneThreadAndExecuteCommandsInAnother() throws Exception {

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {

                    Iterator<Frame> frames = getLoggingFrames().iterator();

                    while (frames.hasNext()) {
                        frames.next();
                    }

                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });

        thread.start();

        try (DockerfileFixture busyboxDockerfile = new DockerfileFixture(dockerClient, "busyboxDockerfile")) {
            busyboxDockerfile.open();
        }

        thread.join();

    }

    public static class FrameReaderITestCallback extends LogContainerResultCallback {

        public List<Frame> frames = new ArrayList<Frame>();

        @Override
        public void onNext(Frame item) {
            frames.add(item);
            super.onNext(item);
        }

    }
}

@@ -38,16 +38,351 @@
 mmand;%0A%0A
+import static org.hamcrest.MatcherAssert.assertThat;%0Aimport static org.hamcrest.Matchers.contains;%0Aimport static org.hamcrest.Matchers.containsInAnyOrder;%0Aimport static org.hamcrest.Matchers.hasEntry;%0Aimport static org.hamcrest.Matchers.hasProperty;%0Aimport static org.hamcrest.Matchers.hasSize;%0Aimport static org.hamcrest.Matchers.is;%0A
 import s
@@ -419,16 +419,16 @@
 Equals;%0A
-
 import s
@@ -520,16 +520,48 @@
 erator;%0A
+import java.util.LinkedHashSet;%0A
 import j
@@ -1602,33 +1602,32 @@
 ows Exception %7B%0A
-%0A
         // wait 
@@ -1885,104 +1885,92 @@
     
-Iterator%3CFrame%3E response = getLoggingFrames().iterator();%0A%0A        assertEquals(response.next(),
+final List%3CFrame%3E loggingFrames = getLoggingFrames();%0A        final Frame outFrame =
  new
@@ -2012,33 +2012,32 @@
 t%5Cn%22.getBytes())
-)
 ;%0A        assert
@@ -2034,37 +2034,30 @@
     
-assertEquals(response.next(),
+final Frame errFrame =
  new
@@ -2107,18 +2107,26 @@
 Bytes())
-)
 ;
+%0A        
 %0A       
@@ -2136,36 +2136,116 @@
 sert
-False(response.hasNext(
+That(loggingFrames, containsInAnyOrder(outFrame, errFrame));%0A        assertThat(loggingFrames, hasSize(2
 ));%0A
-%0A
     

Fix sync test to be async.