package io.jenkins.docker;

import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerCmd;
import com.github.dockerjava.api.exception.DockerException;
import com.github.dockerjava.api.model.Frame;
import com.github.dockerjava.api.model.LogConfig;
import com.github.dockerjava.core.command.AttachContainerResultCallback;
import com.google.common.annotations.Beta;
import com.nirima.jenkins.plugins.docker.DockerCloud;
import com.nirima.jenkins.plugins.docker.DockerSlave;
import com.nirima.jenkins.plugins.docker.DockerTemplate;
import hudson.model.Descriptor;
import hudson.model.TaskListener;
import hudson.remoting.Channel;
import hudson.remoting.Which;
import hudson.slaves.ComputerLauncher;
import hudson.slaves.SlaveComputer;
import jenkins.model.Jenkins;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

/**
 * Create a container in interactive mode and use attached stdin/stdout as transport for remoting.
 * @author <a href="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
 */
@Beta
public class AttachedDockerSlaveProvisioner extends DockerSlaveProvisioner {


    private DockerSlave slave;

    private File remoting;
    private InputStream in;
    private OutputStream out;

    public AttachedDockerSlaveProvisioner(DockerCloud cloud, DockerTemplate template, DockerClient client) {
        super(cloud, template, client);
    }

    @Override
    public DockerSlave provision() throws IOException, Descriptor.FormException, InterruptedException {

        this.remoting = Which.jarFile(Channel.class);
        this.slave = new DockerSlave(cloud, template, new NoOpLauncher());
        Jenkins.getInstance().addNode(slave);
        runContainer();

        slave.getComputer().setChannel(in, out, TaskListener.NULL, new Channel.Listener() {
            @Override
            public void onClosed(Channel channel, IOException cause) {
                System.out.println("Closed");
            }
        });

        return slave;
    }

    @Override
    protected void prepareCreateContainerCommand(CreateContainerCmd cmd) throws DockerException, IOException {
        cmd.withAttachStdin(true)
            .withAttachStdout(true)
            .withStdinOpen(true)
            .withStdInOnce(true)
            .withLogConfig(new LogConfig(LogConfig.LoggingType.NONE))
            .withCmd("java", "-jar", template.remoteFs + '/' + remoting.getName());
    }

    @Override
    protected void setupContainer() throws IOException, InterruptedException {

        // Copy slave.jar into container
        client.copyArchiveToContainerCmd(container)
                .withHostResource(remoting.getAbsolutePath())
                .withRemotePath(template.remoteFs)
                .exec();

        final PipedInputStream containerStdin = new PipedInputStream();
        out = new PipedOutputStream(containerStdin);

        final PipedOutputStream containerStdout = new PipedOutputStream();
        in =new PipedInputStream(containerStdout);

        final AttachContainerResultCallback callback = new AttachContainerResultCallback() {
            public void onNext(Frame item) {
                switch (item.getStreamType()) {
                    case STDOUT:
                    case RAW:
                        try {
                            containerStdout.write(item.getPayload());
                        } catch (IOException e) {
                            throw new DockerException("Failed to collect stdout", 0, e);
                        }
                }
            }
        };

        client.attachContainerCmd(container)
              .withStdOut(true)
              .withStdErr(true)
              .withStdIn(containerStdin)
              .withFollowStream(true)
              .exec(callback);
    }

    private static class NoOpLauncher extends ComputerLauncher {

        public void launch(SlaveComputer computer, TaskListener listener) {
            // Nop
        }

    }
}

@@ -455,16 +455,73 @@
 rCloud;%0A
+import com.nirima.jenkins.plugins.docker.DockerComputer;%0A
 import c
@@ -1896,16 +1896,48 @@
 %0A       
+ final DockerComputer computer =
  slave.g
@@ -1948,16 +1948,34 @@
 mputer()
+;%0A        computer
 .setChan
@@ -2144,61 +2144,83 @@
     
-System.out.println(%22Closed%22);%0A            %7D%0A        %7D
+// nop;%0A            %7D%0A        %7D);%0A        computer.setContainerId(container
 );%0A%0A

remove stdout debug set container ID