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

import org.apache.log4j.Logger;
import org.bench4q.master.domain.entity.TestPlan;
import org.bench4q.master.domain.entity.TestPlanScript;
import org.bench4q.master.domain.valueobject.transaction.Transaction;
import org.bench4q.master.helper.ApplicationContextHelper;
import org.bench4q.master.infrastructure.highavailable.HighAvailablePool;
import org.bench4q.master.infrastructure.highavailable.impl.HighAvailablePoolImpl;
import org.bench4q.share.enums.master.TestPlanStatus;

public class TestPlanLoadApplication implements Transaction {
	private TestPlan testPlan;
	private HighAvailablePool highAvailableAgentPool;
	private static Logger logger = Logger
			.getLogger(TestPlanLoadApplication.class);

	private HighAvailablePool getHighAvailableAgentPool() {
		return highAvailableAgentPool;
	}

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

	private TestPlan getTestPlan() {
		return testPlan;
	}

	private void setTestPlan(TestPlan testPlan) {
		this.testPlan = testPlan;
	}

	private boolean hasEnoughCurrentLoad(int totalRequireLoad) {
		return this.highAvailableAgentPool.getCurrentAvailableLoad() >= totalRequireLoad;
	}

	private boolean hasEnoughMaxLoad(int totalRequireLoad) {
		return this.getHighAvailableAgentPool().getMaxAvailableLoad() >= totalRequireLoad;
	}

	public TestPlanLoadApplication(TestPlan testPlanInDomain) {
		this.setHighAvailableAgentPool(ApplicationContextHelper
				.getBean(HighAvailablePoolImpl.class));
		this.setTestPlan(testPlanInDomain);
	}

	private void doAfterDistributeLoadForTestPlan() {
		this.getHighAvailableAgentPool().checkAllHeartBeat();
	}

	@Override
	public TestPlanStatus execute() throws Exception {
		synchronized (this.highAvailableAgentPool) {
			if (!hasEnoughMaxLoad(this.getTestPlan().getRequiredLoad())) {
				logger.error("There is no enough max load in the pool!");
				return TestPlanStatus.PendingNoEnoughMaxLoad;
			}
			if (!hasEnoughCurrentLoad(this.getTestPlan().getRequiredLoad())) {
				logger.info("There is no enough current load in the pool!");
				return TestPlanStatus.PendingNoEnoughCurrentLoad;
			}
			for (TestPlanScript testPlanScript : this.getTestPlan()
					.getTestPlanScripts()) {
				if (!testPlanScript.applyForLoad()) {
					return TestPlanStatus.ErrorInDistributeLoadForScript;
				}
			}
		}
		doAfterDistributeLoadForTestPlan();
		return TestPlanStatus.InRunning;
	}

	@Override
	public void rollBack() {
		for (TestPlanScript testPlanScript : this.getTestPlan()
				.getTestPlanScripts()) {
			testPlanScript.stop();
		}
	}

}
