package com.offbytwo.jenkins;

import java.io.IOException;
import java.util.Map;

import com.offbytwo.jenkins.model.Build;
import com.offbytwo.jenkins.model.BuildResult;
import com.offbytwo.jenkins.model.BuildWithDetails;
import com.offbytwo.jenkins.model.JobWithDetails;
import com.offbytwo.jenkins.model.QueueItem;
import com.offbytwo.jenkins.model.QueueReference;

/**
 * collection of convenient methods which use methods from {@link JenkinsServer}
 * etc.
 * 
 * @author Karl Heinz Marbaise
 *
 */
public class JenkinsTriggerHelper {

    private JenkinsServer server;

    public JenkinsTriggerHelper(JenkinsServer server) {
        this.server = server;
    }

    /**
     * This method will trigger a build of the given job and will wait until the
     * builds is ended or if the build has been cancelled.
     * 
     * @param jobName The name of the job which should be triggered.
     * @return In case of an cancelled job you will get
     *         {@link BuildWithDetails#getResult()}
     *         {@link BuildResult#CANCELLED}. So you have to check first if the
     *         build result is {@code CANCELLED}.
     * @throws IOException in case of errors.
     * @throws InterruptedException In case of interrupts.
     */
    public BuildWithDetails triggerJobAndWaitUntilFinished(String jobName) throws IOException, InterruptedException {
        return triggerJobAndWaitUntilFinished(jobName, false);
    }

    /**
     * This method will trigger a build of the given job and will wait until the
     * builds is ended or if the build has been cancelled.
     * 
     * @param jobName The name of the job which should be triggered.
     * @param params the job parameters
     * @return In case of an cancelled job you will get
     *         {@link BuildWithDetails#getResult()}
     *         {@link BuildResult#CANCELLED}. So you have to check first if the
     *         build result is {@code CANCELLED}.
     * @throws IOException in case of errors.
     * @throws InterruptedException In case of interrupts.
     */
    public BuildWithDetails triggerJobAndWaitUntilFinished(String jobName, Map<String, String> params)
            throws IOException, InterruptedException {
        return triggerJobAndWaitUntilFinished(jobName, params, false);
    }

    /**
     * This method will trigger a build of the given job and will wait until the
     * builds is ended or if the build has been cancelled.
     * 
     * @param jobName The name of the job which should be triggered.
     * @param params the job parameters
     * @param crumbFlag set to <code>true</code> or <code>false</code>.
     * @return In case of an cancelled job you will get
     *         {@link BuildWithDetails#getResult()}
     *         {@link BuildResult#CANCELLED}. So you have to check first if the
     *         build result is {@code CANCELLED}.
     * @throws IOException in case of errors.
     * @throws InterruptedException In case of interrupts.
     */
    public BuildWithDetails triggerJobAndWaitUntilFinished(String jobName, Map<String, String> params,
            boolean crumbFlag) throws IOException, InterruptedException {
        JobWithDetails job = this.server.getJob(jobName);
        QueueReference queueRef = job.build(params, crumbFlag);

        return triggerJobAndWaitUntilFinished(jobName, queueRef);
    }

    /**
     * This method will trigger a build of the given job and will wait until the
     * builds is ended or if the build has been cancelled.
     * 
     * @param jobName The name of the job which should be triggered.
     * @param crumbFlag set to <code>true</code> or <code>false</code>.
     * @return In case of an cancelled job you will get
     *         {@link BuildWithDetails#getResult()}
     *         {@link BuildResult#CANCELLED}. So you have to check first if the
     *         build result is {@code CANCELLED}.
     * @throws IOException in case of errors.
     * @throws InterruptedException In case of interrupts.
     */
    public BuildWithDetails triggerJobAndWaitUntilFinished(String jobName, boolean crumbFlag)
            throws IOException, InterruptedException {
        JobWithDetails job = this.server.getJob(jobName);
        QueueReference queueRef = job.build(crumbFlag);

        return triggerJobAndWaitUntilFinished(jobName, queueRef);
    }

    /**
     * @param jobName The name of the job.
     * @param queueRef {@link QueueReference}
     * @return In case of an cancelled job you will get
     *         {@link BuildWithDetails#getResult()}
     *         {@link BuildResult#CANCELLED}. So you have to check first if the
     *         build result is {@code CANCELLED}.
     * @throws IOException in case of errors.
     * @throws InterruptedException In case of interrupts.
     */
    private BuildWithDetails triggerJobAndWaitUntilFinished(String jobName, QueueReference queueRef)
            throws IOException, InterruptedException {
        JobWithDetails job;
        job = this.server.getJob(jobName);
        QueueItem queueItem = this.server.getQueueItem(queueRef);
        while (!queueItem.isCancelled() && job.isInQueue()) {
            // TODO: May be we should make this configurable?
            Thread.sleep(200);
            job = this.server.getJob(jobName);
            queueItem = this.server.getQueueItem(queueRef);
        }

        if (queueItem.isCancelled()) {
            // TODO: Check if this is ok?
            // We will get the details of the last build. NOT of the cancelled
            // build, cause there is no information about that available cause
            // it does not exist.
            BuildWithDetails result = new BuildWithDetails(job.getLastBuild().details());
            // TODO: Should we add more information here?
            result.setResult(BuildResult.CANCELLED);
            return result;
        }

        Build build = server.getBuild(queueItem);
        boolean isBuilding = build.details().isBuilding();
        while (isBuilding) {
            Thread.sleep(200);
            isBuilding = build.details().isBuilding();
        }

        return build.details();
    }
}

@@ -545,16 +545,22 @@
 private 
+final 
 JenkinsS
@@ -577,93 +577,402 @@
 er;%0A
-%0A    public JenkinsTriggerHelper(JenkinsServer server) %7B%0A        this.server = server
+    private final Long retryInterval;%0A    private static final Long DEFAULT_RETRY_INTERVAL = 200L;%0A%0A    public JenkinsTriggerHelper(JenkinsServer server) %7B%0A        this.server = server;%0A        this.retryInterval = DEFAULT_RETRY_INTERVAL;%0A    %7D%0A%0A    public JenkinsTriggerHelper(JenkinsServer server, Long retryInterval) %7B%0A        this.server = server;%0A        this.retryInterval = retryInterval
 ;%0A  
@@ -5269,21 +5269,8 @@
 ils 
-job;%0A        
 job 
@@ -5358,32 +5358,33 @@
 Item(queueRef);%0A
+%0A
         while (!
@@ -5445,86 +5445,34 @@
     
-// TODO: May be we should make this configurable?%0A            Thread.sleep(200
+Thread.sleep(retryInterval
 );%0A 
@@ -5600,561 +5600,135 @@
     
-if (queueItem.isCancelled()) %7B%0A            // TODO: Check if this is ok?%0A            // We will get the details of the last build. NOT of the cancelled%0A            // build, cause there is no information about that available cause%0A            // it does not exist.%0A            BuildWithDetails result = new BuildWithDetails(job.getLastBuild().details());%0A            // TODO: Should we add more information here?%0A            result.setResult(BuildResult.CANCELLED);%0A            return result;%0A        %7D%0A%0A        Build build = server.getBuild(queueItem);
+Build build = server.getBuild(queueItem);%0A        if (queueItem.isCancelled()) %7B%0A            return build.details();%0A        %7D%0A
 %0A   
@@ -5837,19 +5837,29 @@
 d.sleep(
-200
+retryInterval
 );%0A     

Simplify the triggerJobAndWaitUntilFinished method a bit Make the polling rate configurable