package hudson.plugins.selenium.callables;

import hudson.FilePath;
import hudson.FilePath.FileCallable;
import hudson.model.TaskListener;
import hudson.plugins.selenium.RemoteControlLauncher;
import hudson.plugins.selenium.RemoteRunningStatus;
import hudson.plugins.selenium.process.ProcessArgument;
import hudson.plugins.selenium.process.SeleniumProcessUtils;
import hudson.plugins.selenium.process.SeleniumRunOptions;
import hudson.remoting.Channel;
import hudson.remoting.VirtualChannel;
import hudson.util.IOException2;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.lang.ArrayUtils;

public class SeleniumCallable implements FileCallable<String> {

    private static final String ROLE_PARAM = "-role";

    private static final String ROLE_NODE_VALUE = "node";

    private static final String HOST_PARAM = "-host";

    private static final String HUB_PARAM = "-hub";

    private static final Logger LOGGER = Logger.getLogger(SeleniumCallable.class.getName());

    private FilePath seleniumJar;
    private long jarTimestamp;
    private String nodeName;
    private SeleniumRunOptions options;
    private String config;
    private TaskListener listener;

    private String[] defaultArgs;

    public SeleniumCallable(FilePath jar, String nodehost, String masterName, int masterPort, String nodeName, TaskListener listener,
            String confName, SeleniumRunOptions options) throws InterruptedException, IOException {
        seleniumJar = jar;
        jarTimestamp = jar.lastModified();
        this.nodeName = nodeName;
        this.options = options;
        this.listener = listener;
        config = confName;
        defaultArgs = new String[] { ROLE_PARAM, ROLE_NODE_VALUE, HOST_PARAM, nodehost, HUB_PARAM,
                "http://" + masterName + ":" + masterPort + "/wd/hub" };
    }

    /**
	 * 
	 */
    private static final long serialVersionUID = 2047557797415325512L;

    public String invoke(File f, VirtualChannel channel) throws IOException {
        RemoteRunningStatus status = (RemoteRunningStatus) PropertyUtils.getMapProperty(SeleniumConstants.PROPERTY_STATUS, config);

        if (status != null && status.isRunning()) {
            // listener.getLogger().println("Skipping Selenium RC execution because this slave has already started its RCs");
            return null;
        }

        // listener.getLogger().println("Copy grid jar");
        File localJar = new File(f, seleniumJar.getName());
        if (localJar.lastModified() != jarTimestamp) {
            try {
                seleniumJar.copyTo(new FilePath(localJar));
                localJar.setLastModified(jarTimestamp);
            } catch (InterruptedException e) {
                throw new IOException2("Failed to copy grid jar", e);
            }
        }

        try {

            // listener.getLogger().println("Creating selenium VM");
            Channel jvm = SeleniumProcessUtils.createSeleniumRCVM(localJar, listener, options.getJVMArguments(), options.getEnvironmentVariables());
            status = new RemoteRunningStatus(jvm, options);
            status.setStatus(SeleniumConstants.STARTING);

            List<String> arguments = new ArrayList<String>(options.getSeleniumArguments().size());
            for (ProcessArgument arg : options.getSeleniumArguments()) {
                arguments.addAll(arg.toArgumentsList());
            }

            // listener.getLogger().println("Starting the selenium process");
            jvm.callAsync(new RemoteControlLauncher(nodeName, (String[]) ArrayUtils.addAll(defaultArgs, arguments.toArray(new String[0]))));
            status.setStatus(SeleniumConstants.STARTED);
            status.setRunning(true);
        } catch (Exception t) {
            status.setRunning(false);
            status.setStatus(SeleniumConstants.ERROR);
            LOGGER.log(Level.WARNING, "Selenium launch failed", t);
            // listener.getLogger().println( "Selenium launch failed" + t.getMessage());

            throw new IOException2("Selenium launch interrupted", t);
        }
        PropertyUtils.setMapProperty(SeleniumConstants.PROPERTY_STATUS, config, status);

        return config;
    }
}
@@ -592,24 +592,49 @@
 .ArrayList;%0A
+import java.util.Arrays;%0A
 import java.
@@ -937,63 +937,8 @@
 %22;%0A%0A
-    private static final String HOST_PARAM = %22-host%22;%0A%0A
     
@@ -1779,16 +1779,32 @@
 ring%5B%5D %7B
+%0A               
  ROLE_PA
@@ -1828,41 +1828,8 @@
 LUE,
- HOST_PARAM, nodehost, HUB_PARAM,
 %0A   
@@ -1840,16 +1840,27 @@
         
+ HUB_PARAM,
  %22http:/
@@ -1927,17 +1927,16 @@
  /**%0A%09 *
- 
 %0A%09 */%0A  
@@ -2897,35 +2897,32 @@
 y %7B%0A%0A           
- //
  listener.getLog
@@ -2954,16 +2954,21 @@
 elenium 
+node 
 VM%22);%0A  
@@ -3481,34 +3481,144 @@
  %7D%0A%0A            
-//
+Object%5B%5D allArgs = ArrayUtils.addAll(defaultArgs, arguments.toArray(new String%5Barguments.size()%5D));%0A%0A           
  listener.getLog
@@ -3658,16 +3658,56 @@
 ium 
+node 
 process
-%22
+. Args: %22 + Arrays.toString(allArgs)
 );%0A 
@@ -3781,73 +3781,15 @@
 g%5B%5D)
- ArrayUtils.addAll(defaultArgs, arguments.toArray(new String%5B0%5D))
+allArgs
 ));%0A
@@ -4047,32 +4047,37 @@
 NING, %22Selenium 
+node 
 launch failed%22, 
@@ -4083,35 +4083,32 @@
  t);%0A           
- //
  listener.getLog
@@ -4128,24 +4128,29 @@
 ( %22Selenium 
+node 
 launch faile
@@ -4217,16 +4217,21 @@
 elenium 
+node 
 launch i
@@ -4377,8 +4377,9 @@
 %0A    %7D%0A%7D
+%0A

Remove parameter -host from defaultArgs. It might fail node registration with NPE in case getHostName() returns null (see SeleniumJarRunner.start() ) Moreover this parameter already present (if not equal to null) in options.arguments (see SeleniumJarRunner.start() )