package org.jenkinsci.plugins.coordinator.model;

import hudson.Extension;
import hudson.Launcher;
import hudson.model.BuildListener;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.Builder;
import hudson.util.FormValidation;

import java.io.IOException;

import net.sf.json.JSONException;
import net.sf.json.JSONObject;

import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;

/**
 * 
 * For project's builder part configuration
 * @author Ace Han
 *
 */
public class CoordinatorBuilder extends Builder {
	
	private TreeNode executionPlan;
	
	public CoordinatorBuilder(){
		setExecutionPlan(TreeNode.EMPTY_ROOT);
	}
	
	@DataBoundConstructor
	public CoordinatorBuilder(TreeNode executionPlan){
		setExecutionPlan(executionPlan);
	}
	
	public TreeNode getExecutionPlan() {
		return executionPlan;
	}

	public void setExecutionPlan(TreeNode executionPlan) {
		this.executionPlan = executionPlan;
	}

	@Override
	public boolean perform(AbstractBuild<?, ?> build, Launcher launcher,
			BuildListener listener) throws InterruptedException, IOException {
		assert build instanceof CoordinatorBuild;
		
		CoordinatorBuild cb = (CoordinatorBuild) build;
		
		// TODO make this 10 configurable
		PerformExecutor performExecutor = new PerformExecutor(cb, listener, 10);
		return performExecutor.execute();
	}
	
	@Extension
	public static final class DescriptorImpl extends BuildStepDescriptor<Builder> {
		
		@Override
		public boolean isApplicable(@SuppressWarnings("rawtypes") 
									Class<? extends AbstractProject> jobType) {
			// Only available to CooradinatorProject
			return CoordinatorProject.class.isAssignableFrom(jobType);
		}
		
		@Override
		public String getDisplayName() {
			return "Coordinator";
		}

		@Override
		public Builder newInstance(StaplerRequest req, JSONObject formData)
				throws FormException {
			JSONObject jsonObject = JSONObject.fromObject(
											formData.getString("executionPlan"), 
											TreeNode.JSON_CONFIG);
			TreeNode executionPlan = (TreeNode)JSONObject.toBean(jsonObject, TreeNode.JSON_CONFIG);
			return new CoordinatorBuilder(executionPlan);
		}
		
		public FormValidation doCheckExecutionPlan(@QueryParameter String value) {
			// this check maybe not that much meaningful
			try{
				JSONObject.fromObject(value, TreeNode.JSON_CONFIG);
				return FormValidation.ok();
			} catch(JSONException e){
				return FormValidation.error(e.getMessage());
			}
		}
		
	}
}

@@ -128,24 +128,57 @@
 dListener;%0D%0A
+import hudson.model.Descriptor;%0D%0A
 import hudso
@@ -1551,16 +1551,642 @@
 %0A%09%7D%0D%0A%09%0D%0A
+%09/**%0D%0A%09 * It's really weird that jenkins doesn't load this plugin's descriptor in test%0D%0A%09 * %0D%0A%09 * It will break the test in some way, %0D%0A%09 * for example, CoordinatorBuild result will turn Result.UNSTABLE to Result.FAILURE%0D%0A%09 * refer to %7B@code hudson.model.AbstractBuild#getBuildStepName%7D, %0D%0A%09 * %7B@code hudson.tasks.Builder#getDescriptor%7D, %0D%0A%09 * %7B@code jenkins.model.Jenkins#getDescriptorOrDie%7D%0D%0A%09 * @return%0D%0A%09 */%0D%0A%09public Descriptor%3CBuilder%3E getDescriptor()%7B%0D%0A%09%09try%7B%0D%0A%09%09%09return super.getDescriptor();%0D%0A%09%09%7D catch(AssertionError e)%7B%0D%0A%09%09%09// this scenario should be only to unit test %0D%0A%09%09%09return new DescriptorImpl();%0D%0A%09%09%7D%0D%0A%09%7D%0D%0A%09%0D%0A
 %09@Extens

fix test always Result.UNSTABLE to Result.FAILURE error