package org.jenkinsci.plugins.dockerbuildstep;

import hudson.EnvVars;
import hudson.Extension;
import hudson.model.TaskListener;
import hudson.model.EnvironmentContributor;
import hudson.model.Run;

import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jenkinsci.plugins.dockerbuildstep.action.EnvInvisibleAction;

import com.github.dockerjava.api.model.ExposedPort;
import com.github.dockerjava.api.model.Ports.Binding;
import com.google.common.base.Joiner;

/**
 * This contributor adds various Docker relate variable like container IDs or IP addresses into build environment
 * variables.
 * 
 * @author vjuranek
 * 
 */
@Extension
public class DockerEnvContributor extends EnvironmentContributor {

    public final String ID_SEPARATOR = ",";
    public final String CONTAINER_IDS_ENV_VAR = "DOCKER_CONTAINER_IDS";
    public final String CONTAINER_IP_PREFIX = "DOCKER_IP_";
    public final String PORT_BINDINGS_ENV_VAR = "DOCKER_HOST_BIND_PORTS";
    public final String PORT_BINDING_PREFIX = "DOCKER_HOST_PORT_";

    @Override
    public void buildEnvironmentFor(@SuppressWarnings("rawtypes") Run r, EnvVars envs, TaskListener listener)
            throws IOException, InterruptedException {

        List<EnvInvisibleAction> envActions = r.getActions(EnvInvisibleAction.class);
        if (envActions.size() == 0) {
            return;
        }

        Set<String> containerIds = new LinkedHashSet<String>();
        containerIds.addAll(Arrays.asList(envs.get(CONTAINER_IDS_ENV_VAR, "").split(ID_SEPARATOR)));

        for (EnvInvisibleAction action : envActions) {
            containerIds.add(action.getId());

            envs.put(CONTAINER_IP_PREFIX + action.getHostName(), action.getIpAddress());
            if (action.hasPortBindings()) {
                exportPortBindings(envs, action.getPortBindings());
            }
        }

        containerIds.remove(null);
        containerIds.remove("");

        envs.put(CONTAINER_IDS_ENV_VAR, Joiner.on(ID_SEPARATOR).join(containerIds));
    }

    private void exportPortBindings(EnvVars envs, Map<ExposedPort, Binding[]> bindings) {
        StringBuilder ports = new StringBuilder();
        for (ExposedPort exposedPort : bindings.keySet()) {
            ports.append(exposedPort.toString()).append(ID_SEPARATOR);
            envs.put(PORT_BINDING_PREFIX + exposedPort.getProtocol().name() + "_" + exposedPort.getPort(),
                    Integer.toString(bindings.get(exposedPort)[0].getHostPort()));
        }
        String bindPorts = ports.substring(0, ports.length() - 1).toString();
        envs.put(PORT_BINDINGS_ENV_VAR, bindPorts);
    }

}

@@ -2403,102 +2403,248 @@
     
-envs.put(PORT_BINDING_PREFIX + exposedPort.getProtocol().name() + %22_%22 + exposedPort.getPort(),
+StringBuilder portBinding = new StringBuilder();%0A            String hostIp = bindings.get(exposedPort)%5B0%5D.getHostIp();%0A            if (hostIp != null && hostIp.length() %3E 0)%0A            %7B%0A            %09portBinding.append(hostIp).append(%22:%22);
 %0A   
@@ -2652,24 +2652,26 @@
         
+%7D%0A
         
 Integer.
@@ -2662,16 +2662,39 @@
         
+    portBinding.append(
 Integer.
@@ -2744,24 +2744,156 @@
 stPort()));%0A
+            envs.put(PORT_BINDING_PREFIX + exposedPort.getProtocol().name() + %22_%22 + exposedPort.getPort(), portBinding.toString());%0A
         %7D%0A  

return binding ip+port, use port binding '0.0.0.0:<port> <port>' to get the public ip of the host