package org.bench4q.master.domain.valueobject.transaction.impl;

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBException;

import org.apache.log4j.Logger;
import org.bench4q.master.domain.RunningAgentInterface;
import org.bench4q.master.domain.RunningScriptInterface;
import org.bench4q.master.domain.valueobject.transaction.Transaction;
import org.bench4q.master.domain.valueobject.transaction.exception.ScriptLoadDistributeException;
import org.bench4q.master.exception.ExceptionLog;
import org.bench4q.master.infrastructure.highavailable.HighAvailablePool;
import org.bench4q.share.models.agent.RunScenarioModel;

public abstract class ScriptLoadBase implements Transaction {
	private RunningScriptInterface runningScript;
	private List<RunningAgentInterface> agentListThisTime;
	private HighAvailablePool highAvailableAgentPool;
	private static Logger logger = Logger
			.getLogger(ScriptLoadApplication.class);

	protected RunningScriptInterface getRunningScript() {
		return runningScript;
	}

	protected void setRunningScript(RunningScriptInterface runningScript) {
		this.runningScript = runningScript;
	}

	private List<RunningAgentInterface> getAgentListThisTime() {
		return agentListThisTime;
	}

	private void setAgentListThisTime(
			List<RunningAgentInterface> agentListThisTime) {
		this.agentListThisTime = agentListThisTime;
	}

	private HighAvailablePool getHighAvailableAgentPool() {
		return highAvailableAgentPool;
	}

	protected void setHighAvailableAgentPool(
			HighAvailablePool highAvailableAgentPool) {
		this.highAvailableAgentPool = highAvailableAgentPool;
	}

	protected ScriptLoadBase(RunningScriptInterface runningScript) {
		initialize(runningScript);
	}

	private void initialize(RunningScriptInterface runningScript) {
		this.setRunningScript(runningScript);
		this.setAgentListThisTime(new ArrayList<RunningAgentInterface>());
	}

	public List<RunningAgentInterface> execute() {
		logger.info(this.getRunningScript().getScriptId());
		RunScenarioModel runScenarioModel = this.getRunningScript()
				.getScenario();
		if (runScenarioModel == null) {
			logger.error("runScenarioModel is null!");
			throw new IllegalArgumentException("runScenarioModel is null!");
		}
		try {
			if (isNotValidScript(this.getRunningScript())) {
				logger.error("The running agents of runningScriptModel is null, whose scriptId is"
						+ this.getRunningScript().getScriptId());
				throw new RuntimeException("Running Script not valid!");
			}
			this.getAgentListThisTime().addAll(
					this.applyForLoad(getRequireLoad()));
			return this.getAgentListThisTime();
		} catch (Exception e) {
			logger.error(ExceptionLog.getStackTrace(e).toString()
					+ " whose scriptID is "
					+ this.getRunningScript().getScriptId()
					+ " and TestPlanID is "
					+ this.getRunningScript().getTestPlanID().toString());
			throw new RuntimeException(e);
		}
	}

	private boolean isNotValidScript(RunningScriptInterface input) {
		return input == null || input.getRunningAgents() == null;
	}

	protected abstract int getRequireLoad();

	private List<RunningAgentInterface> applyForLoad(int totalRequireLoad)
			throws JAXBException, ScriptLoadDistributeException {
		List<RunningAgentInterface> resultWithouIdAndRunningScript = this
				.getHighAvailableAgentPool().applyFor(totalRequireLoad);
		if (resultWithouIdAndRunningScript == null) {
			throw new ScriptLoadDistributeException();
		}
		for (RunningAgentInterface runningAgent : resultWithouIdAndRunningScript) {
			runningAgent.completeWithRunningScript(this.getRunningScript());
		}
		return resultWithouIdAndRunningScript;
	}

	public void rollBack() {
		stopAgentsRunningThisScript();
	}

	private void stopAgentsRunningThisScript() {
		if (this.getAgentListThisTime() == null) {
			return;
		}
		// for (RunningAgentInterface runningAgent :
		// this.getAgentListThisTime()) {
		// if (runningAgent.isBreakDown()) {
		// continue;
		// }
		// runningAgent.stop();
		// this.getAgentListThisTime().remove(runningAgent);
		// this.highAvailableAgentPool.removeABlotter(runningAgent
		// .getAgentRunId());
		// }
	}

}
