// Path: src/main/java/pl/domzal/junit/docker/rule/logs/LogPrinter.java
// public class LogPrinter implements Runnable {
// 
//     private static Logger log = LoggerFactory.getLogger(LogPrinter.class);
// 
//     private final String prefix;
//     private final InputStream scannedInputStream;
//     private final PrintStream output;
//     private final LineListener lineListener;
// 
//     public LogPrinter(String prefix, InputStream scannedInputStream, PrintStream output, LineListener lineListener) {
//         this.prefix = prefix;
//         this.scannedInputStream = scannedInputStream;
//         this.output = output;
//         this.lineListener = lineListener;
//     }
// 
//     @Override
//     public void run() {
//         log.trace("{} printer thread started", prefix);
//         try (Scanner scanner = new Scanner(scannedInputStream)) {
//             while (scanner.hasNextLine()) {
//                 String line = scanner.nextLine();
//                 log.trace("{} line: {}", prefix, line);
//                 if (output != null) {
//                     output.println(prefix + line);
//                 }
//                 if (lineListener != null) {
//                     lineListener.nextLine(line);
//                 }
//             }
//         }
//         log.trace("{} printer thread terminated", prefix);
//     }
// }
// 
// Path: src/main/java/pl/domzal/junit/docker/rule/logs/LogSplitter.java
// public class LogSplitter implements Closeable {
// 
//     private final PipedInputStream stdoutInput = new PipedInputStream();
//     private final PipedInputStream stderrInput = new PipedInputStream();
//     private final PipedInputStream combinedInput = new PipedInputStream();
// 
//     private final PipedOutputStream stdoutPipeOutputStream;
//     private final PipedOutputStream stderrPipeOutputStream;
//     private final PipedOutputStream combinedPipeOutputStream;
// 
//     private final OutputStream stdoutOutput;
//     private final OutputStream stderrOutput;
// 
//     public LogSplitter() {
//         try {
//             this.stdoutPipeOutputStream = new PipedOutputStream(stdoutInput);
//             this.stderrPipeOutputStream = new PipedOutputStream(stderrInput);
//             this.combinedPipeOutputStream = new PipedOutputStream(combinedInput);
//             this.stdoutOutput = new TeeOutputStream(stdoutPipeOutputStream, combinedPipeOutputStream);
//             this.stderrOutput = new TeeOutputStream(stderrPipeOutputStream, combinedPipeOutputStream);
//         } catch (IOException e) {
//             throw new RuntimeException("Unable to create", e);
//         }
//     }
// 
//     public OutputStream getStdoutOutput() {
//         return stdoutOutput;
//     }
// 
//     public OutputStream getStderrOutput() {
//         return stderrOutput;
//     }
// 
//     public InputStream getStdoutInput() {
//         return stdoutInput;
//     }
// 
//     public InputStream getStderrInput() {
//         return stderrInput;
//     }
// 
//     public InputStream getCombinedInput() {
//         return combinedInput;
//     }
// 
//     @Override
//     public void close() throws IOException {
//         IOUtils.closeQuietly(stderrInput);
//         IOUtils.closeQuietly(stdoutInput);
//         IOUtils.closeQuietly(combinedInput);
//         IOUtils.closeQuietly(stdoutPipeOutputStream);
//         IOUtils.closeQuietly(stderrPipeOutputStream);
//         IOUtils.closeQuietly(combinedPipeOutputStream);
//         IOUtils.closeQuietly(stdoutOutput);
//         IOUtils.closeQuietly(stderrOutput);
//     }
// }
// 
// Path: src/main/java/pl/domzal/junit/docker/rule/wait/LineListener.java
// public interface LineListener {
//     void nextLine(String line);
// }


import java.io.Closeable;
import java.io.IOException;
import java.io.PrintStream;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.spotify.docker.client.DockerClient;
import com.spotify.docker.client.DockerClient.LogsParam;
import com.spotify.docker.client.LogStream;
import pl.domzal.junit.docker.rule.logs.LogPrinter;
import pl.domzal.junit.docker.rule.logs.LogSplitter;
import pl.domzal.junit.docker.rule.wait.LineListener;
package pl.domzal.junit.docker.rule;





/**
 * Docker container log binding feature.
 */
class DockerLogs implements Closeable {

    private static Logger log = LoggerFactory.getLogger(DockerLogs.class);

    private static final int NO_OF_THREADS = 4;
    private static final int SHORT_ID_LEN = 12;

    private final DockerClient dockerClient;
    private final String containerId;
    private final LineListener lineListener;

    private PrintStream stdoutWriter = System.out;
    private PrintStream stderrWriter = System.err;

    private final ThreadFactory threadFactory = new ThreadFactoryBuilder()//
            .setNameFormat("dockerlog-pool-%d")//
            .setDaemon(true)//
            .build();

    private final ExecutorService executor = Executors.newFixedThreadPool(NO_OF_THREADS, threadFactory);

    DockerLogs(DockerClient dockerClient, String containerId, LineListener lineListener) {
        this.dockerClient = dockerClient;
        this.containerId = containerId;
        this.lineListener = lineListener;
    }

    void setStderrWriter(PrintStream stderrWriter) {
        this.stderrWriter = stderrWriter;
    }

    void setStdoutWriter(PrintStream stdoutWriter) {
        this.stdoutWriter = stdoutWriter;
    }

    public void start() throws IOException, InterruptedException {
        final String containerShortId = StringUtils.left(containerId, SHORT_ID_LEN);
// Path: src/main/java/pl/domzal/junit/docker/rule/logs/LogPrinter.java
// public class LogPrinter implements Runnable {
// 
//     private static Logger log = LoggerFactory.getLogger(LogPrinter.class);
// 
//     private final String prefix;
//     private final InputStream scannedInputStream;
//     private final PrintStream output;
//     private final LineListener lineListener;
// 
//     public LogPrinter(String prefix, InputStream scannedInputStream, PrintStream output, LineListener lineListener) {
//         this.prefix = prefix;
//         this.scannedInputStream = scannedInputStream;
//         this.output = output;
//         this.lineListener = lineListener;
//     }
// 
//     @Override
//     public void run() {
//         log.trace("{} printer thread started", prefix);
//         try (Scanner scanner = new Scanner(scannedInputStream)) {
//             while (scanner.hasNextLine()) {
//                 String line = scanner.nextLine();
//                 log.trace("{} line: {}", prefix, line);
//                 if (output != null) {
//                     output.println(prefix + line);
//                 }
//                 if (lineListener != null) {
//                     lineListener.nextLine(line);
//                 }
//             }
//         }
//         log.trace("{} printer thread terminated", prefix);
//     }
// }
// 
// Path: src/main/java/pl/domzal/junit/docker/rule/logs/LogSplitter.java
// public class LogSplitter implements Closeable {
// 
//     private final PipedInputStream stdoutInput = new PipedInputStream();
//     private final PipedInputStream stderrInput = new PipedInputStream();
//     private final PipedInputStream combinedInput = new PipedInputStream();
// 
//     private final PipedOutputStream stdoutPipeOutputStream;
//     private final PipedOutputStream stderrPipeOutputStream;
//     private final PipedOutputStream combinedPipeOutputStream;
// 
//     private final OutputStream stdoutOutput;
//     private final OutputStream stderrOutput;
// 
//     public LogSplitter() {
//         try {
//             this.stdoutPipeOutputStream = new PipedOutputStream(stdoutInput);
//             this.stderrPipeOutputStream = new PipedOutputStream(stderrInput);
//             this.combinedPipeOutputStream = new PipedOutputStream(combinedInput);
//             this.stdoutOutput = new TeeOutputStream(stdoutPipeOutputStream, combinedPipeOutputStream);
//             this.stderrOutput = new TeeOutputStream(stderrPipeOutputStream, combinedPipeOutputStream);
//         } catch (IOException e) {
//             throw new RuntimeException("Unable to create", e);
//         }
//     }
// 
//     public OutputStream getStdoutOutput() {
//         return stdoutOutput;
//     }
// 
//     public OutputStream getStderrOutput() {
//         return stderrOutput;
//     }
// 
//     public InputStream getStdoutInput() {
//         return stdoutInput;
//     }
// 
//     public InputStream getStderrInput() {
//         return stderrInput;
//     }
// 
//     public InputStream getCombinedInput() {
//         return combinedInput;
//     }
// 
//     @Override
//     public void close() throws IOException {
//         IOUtils.closeQuietly(stderrInput);
//         IOUtils.closeQuietly(stdoutInput);
//         IOUtils.closeQuietly(combinedInput);
//         IOUtils.closeQuietly(stdoutPipeOutputStream);
//         IOUtils.closeQuietly(stderrPipeOutputStream);
//         IOUtils.closeQuietly(combinedPipeOutputStream);
//         IOUtils.closeQuietly(stdoutOutput);
//         IOUtils.closeQuietly(stderrOutput);
//     }
// }
// 
// Path: src/main/java/pl/domzal/junit/docker/rule/wait/LineListener.java
// public interface LineListener {
//     void nextLine(String line);
// }


// Path: src/main/java/pl/domzal/junit/docker/rule/DockerLogs.java
import java.io.Closeable;
import java.io.IOException;
import java.io.PrintStream;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.spotify.docker.client.DockerClient;
import com.spotify.docker.client.DockerClient.LogsParam;
import com.spotify.docker.client.LogStream;
import pl.domzal.junit.docker.rule.logs.LogPrinter;
import pl.domzal.junit.docker.rule.logs.LogSplitter;
import pl.domzal.junit.docker.rule.wait.LineListener;

package pl.domzal.junit.docker.rule;





/**
 * Docker container log binding feature.
 */
class DockerLogs implements Closeable {

    private static Logger log = LoggerFactory.getLogger(DockerLogs.class);

    private static final int NO_OF_THREADS = 4;
    private static final int SHORT_ID_LEN = 12;

    private final DockerClient dockerClient;
    private final String containerId;
    private final LineListener lineListener;

    private PrintStream stdoutWriter = System.out;
    private PrintStream stderrWriter = System.err;

    private final ThreadFactory threadFactory = new ThreadFactoryBuilder()//
            .setNameFormat("dockerlog-pool-%d")//
            .setDaemon(true)//
            .build();

    private final ExecutorService executor = Executors.newFixedThreadPool(NO_OF_THREADS, threadFactory);

    DockerLogs(DockerClient dockerClient, String containerId, LineListener lineListener) {
        this.dockerClient = dockerClient;
        this.containerId = containerId;
        this.lineListener = lineListener;
    }

    void setStderrWriter(PrintStream stderrWriter) {
        this.stderrWriter = stderrWriter;
    }

    void setStdoutWriter(PrintStream stdoutWriter) {
        this.stdoutWriter = stdoutWriter;
    }

    public void start() throws IOException, InterruptedException {
        final String containerShortId = StringUtils.left(containerId, SHORT_ID_LEN);
        final LogSplitter logSplitter = new LogSplitter();