package org.bench4q.master.unitTest;

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

import org.bench4q.master.domain.RunningScriptInterface;
import org.bench4q.master.domain.entity.RunningAgentDB;
import org.bench4q.master.domain.entity.TestPlan;
import org.bench4q.master.domain.entity.TestPlanScript;
import org.bench4q.master.domain.entity.User;
import org.bench4q.master.domain.factory.TestPlanFactory;
import org.bench4q.master.domain.repository.AgentRepository;
import org.bench4q.master.domain.repository.TestPlanRepository;
import org.bench4q.master.domain.repository.UserRepository;
import org.bench4q.master.domain.service.AgentService;
import org.bench4q.master.domain.service.ScriptService;
import org.bench4q.master.domain.service.TestPlanEngine;
import org.bench4q.master.domain.service.TestPlanScriptResultService;
import org.bench4q.master.domain.service.TestPlanScriptService;
import org.bench4q.master.domain.service.TestPlanService;
import org.bench4q.master.domain.service.UserService;
import org.bench4q.master.helper.SessionHelper;
import org.bench4q.master.infrastructure.communication.AgentMessenger;
import org.bench4q.master.infrastructure.highavailable.HighAvailablePool;
import org.bench4q.master.unitTest.controller.TestBase;
import org.bench4q.share.enums.master.TestPlanStatus;
import org.bench4q.share.models.master.MonitorModel;
import org.bench4q.share.models.master.RunningScriptModel;
import org.bench4q.share.models.master.TestPlanModel;
import org.bench4q.share.models.master.TestScriptConfig;
import org.bench4q.share.models.master.statistics.ScriptBriefResultModel;
import org.springframework.beans.factory.annotation.Autowired;

public class TestBase_MakeUpTestPlan extends TestBase {
	private SessionHelper sessionHelper;
	private TestPlanScriptResultService testPlanScriptResultService;
	private TestPlanScriptService testPlanScriptService;
	private TestPlanService testPlanService;
	private TestPlanRepository testPlanRepository;
	private UserService userService;
	private UserRepository userRepository;
	private ScriptService scriptService;
	private HighAvailablePool haPool;
	private AgentRepository agentRepository;
	private AgentMessenger agentMessenger;
	private TestPlanEngine testPlanEngine;
	private AgentService agentService;
	@Autowired
	protected TestPlanFactory testPlanFactory;
	private UUID testPlanRunIdUuid;
	private int scriptId;
	private int scriptIdForSecond;
	private User testUser;
	// private static int EACH_SCRIPT_LOAD_LargeSCALE = 12000;
	protected static int EACH_SCRIPT_LOAD_SMALLSCALE = 10;
	// private static int EACH_SCRIPT_LOAD_MIDDLESCALE = 800;
	public static String Monitor_Host_Name = "133.133.12.3";
	public static String monitor_port = "5556";

	public static final String Test_AGENT_HOSTNAME = "133.133.12.4";
	public static final int TEST_PORT = 6565;

	protected SessionHelper getSessionHelper() {
		return sessionHelper;
	}

	@Autowired
	protected void setSessionHelper(SessionHelper sessionHelper) {
		this.sessionHelper = sessionHelper;
	}

	public TestPlanScriptResultService getTestPlanScriptResultService() {
		return testPlanScriptResultService;
	}

	@Autowired
	public void setTestPlanScriptResultService(
			TestPlanScriptResultService testPlanScriptResultService) {
		this.testPlanScriptResultService = testPlanScriptResultService;
	}

	public TestPlanScriptService getTestPlanScriptService() {
		return testPlanScriptService;
	}

	@Autowired
	public void setTestPlanScriptService(
			TestPlanScriptService testPlanScriptService) {
		this.testPlanScriptService = testPlanScriptService;
	}

	public TestPlanService getTestPlanService() {
		return testPlanService;
	}

	@Autowired
	public void setTestPlanService(TestPlanService testPlanService) {
		this.testPlanService = testPlanService;
	}

	public UserService getUserService() {
		return userService;
	}

	@Autowired
	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	protected UserRepository getUserRepository() {
		return userRepository;
	}

	@Autowired
	protected void setUserRepository(UserRepository userRepository) {
		this.userRepository = userRepository;
	}

	public ScriptService getScriptService() {
		return scriptService;
	}

	@Autowired
	public void setScriptService(ScriptService scriptService) {
		this.scriptService = scriptService;
	}

	protected TestPlanRepository getTestPlanRepository() {
		return testPlanRepository;
	}

	@Autowired
	private void setTestPlanRepository(TestPlanRepository testPlanRepository) {
		this.testPlanRepository = testPlanRepository;
	}

	protected HighAvailablePool getHaPool() {
		return haPool;
	}

	@Autowired
	protected void setHaPool(HighAvailablePool haPool) {
		this.haPool = haPool;
	}

	protected AgentRepository getAgentRepository() {
		return agentRepository;
	}

	@Autowired
	protected void setAgentRepository(AgentRepository agentRepository) {
		this.agentRepository = agentRepository;
	}

	protected AgentMessenger getAgentMessenger() {
		return agentMessenger;
	}

	@Autowired
	protected void setAgentMessenger(AgentMessenger agentMessenger) {
		this.agentMessenger = agentMessenger;
	}

	protected TestPlanEngine getTestPlanEngine() {
		return testPlanEngine;
	}

	@Autowired
	private void setTestPlanEngine(TestPlanEngine testPlanEngine) {
		this.testPlanEngine = testPlanEngine;
	}

	protected AgentService getAgentService() {
		return agentService;
	}

	@Autowired
	protected void setAgentService(AgentService agentService) {
		this.agentService = agentService;
	}

	public UUID getTestPlanRunIdUuid() {
		return testPlanRunIdUuid;
	}

	public void setTestPlanRunIdUuid(UUID testPlanRunIdUuid) {
		this.testPlanRunIdUuid = testPlanRunIdUuid;
	}

	public int getScriptId() {
		return scriptId;
	}

	public void setScriptId(int scriptId) {
		this.scriptId = scriptId;
	}

	protected int getScriptIdForSecond() {
		return scriptIdForSecond;
	}

	protected void setScriptIdForSecond(int scriptIdForSecond) {
		this.scriptIdForSecond = scriptIdForSecond;
	}

	protected User getTestUser() {
		return testUser;
	}

	protected void setTestUser(User testUser) {
		this.testUser = testUser;
	}

	/**
	 * 
	 */
	public TestBase_MakeUpTestPlan() {
	}

	protected void prepareForTestPlanRunning() {
		this.getHaPool().checkAllHeartBeat();
	}

	protected void cleanUpForTestPlanRunning() {
		TestPlan testPlan = this.getTestPlanRepository().getTestPlanInDomainBy(
				getTestPlanRunIdUuid());
		if (testPlan == null) {
			return;
		}
		testPlan.setCurrentStatus(TestPlanStatus.Complete.name());
		RunningAgentDB runningAgent = extractTheFirstRunningAgent(testPlan
				.extracSpecifiedScript(getScriptId()));
		RunningScriptInterface runningScript = testPlan
				.extracSpecifiedScript(getScriptId());
		runningScript.stop();
		if (runningAgent == null)
			return;
		this.getAgentMessenger().stop(runningAgent.getAgent(),
				runningAgent.getAgentRunId());
		runningAgent.getAgent().setRemainLoad(
				runningAgent.getAgent().getMaxLoad());
		this.getAgentRepository().update(runningAgent.getAgent());
		this.getTestPlanRepository().detach(testPlan.getId());
	}

	protected RunningAgentDB extractTheFirstRunningAgent(
			TestPlanScript testPlanScript) {
		for (RunningAgentDB runningAgentDB : testPlanScript
				.getRunningAgentsDB()) {
			return runningAgentDB;
		}
		return null;
	}

	protected UUID submitATestPlanWithOneScript() {
		return submitATestPlan(1);
	}

	protected UUID submitATestPlanWithTwoScript() {
		return submitATestPlan(2);
	}

	private UUID submitATestPlan(int i) {
		UUID testPlanRunId = UUID.randomUUID();
		User user = this.getUserRepository().getUser("admin");
		int scriptOne = getUserFirstScript(user);
		this.setScriptId(scriptOne);
		int scriptTwo = -1;
		TestPlanModel model = null;
		if (i == 2) {
			scriptTwo = getUserSecondScript(user);
			this.setScriptIdForSecond(scriptTwo);
			model = createATestPlanWithTwoScript(scriptOne, scriptTwo);
		} else {
			model = createATestPlanWithOneScript(scriptOne);
		}
		try {
			this.getTestPlanRepository().attach(
					this.testPlanFactory.createATestPlanWithoutId(model, user,
							testPlanRunId));
		} catch (Exception e) {
			e.printStackTrace();
		}

		this.setTestPlanRunIdUuid(testPlanRunId);
		return testPlanRunId;
	}

	public TestPlanModel createATestPlanWithOneScript(int scriptId) {
		TestPlanModel testPlanBusinessModel = new TestPlanModel();
		testPlanBusinessModel.setMonitorModels(createOneMonitorList());
		testPlanBusinessModel
				.setRunningScriptModels(createOneScriptList(scriptId));
		this.setScriptId(scriptId);
		return testPlanBusinessModel;
	}

	public UUID submitATestPlanWithScriptName() {
		UUID testPlanRunId = UUID.randomUUID();
		User user = this.getUserRepository().getUser("admin");
		int scriptOne = getUserFirstScript(user);
		this.setScriptId(scriptOne);
		TestPlanModel model = null;

		model = createAtestPlanWithOneScriptAndName();
		this.getTestPlanEngine().submitTestPlan(model, user, testPlanRunId);
		this.setTestPlanRunIdUuid(testPlanRunId);
		return testPlanRunId;
	}

	public TestPlanModel createAtestPlanWithOneScriptAndName() {
		TestPlanModel testPlanBusinessModel = new TestPlanModel();
		testPlanBusinessModel.setName("testName");
		testPlanBusinessModel.setMonitorModels(createOneMonitorList());
		testPlanBusinessModel
				.setRunningScriptModels(createOneScriptList(scriptId));
		this.setScriptId(scriptId);
		return testPlanBusinessModel;
	}

	protected TestPlanModel createATestPlanWithTwoScript(int scriptIdForOne,
			int scriptIdForTwo) {
		TestPlanModel testPlanBusinessModel = new TestPlanModel();
		testPlanBusinessModel.setMonitorModels(createOneMonitorList());
		testPlanBusinessModel.setRunningScriptModels(createTwoScriptList(
				scriptIdForOne, scriptIdForTwo));
		return testPlanBusinessModel;
	}

	private List<RunningScriptModel> createTwoScriptList(int scriptIdForOne,
			int scriptIdForTwo) {
		List<RunningScriptModel> runningScriptModels = createOneScriptList(scriptIdForOne);
		runningScriptModels.add(buildScriptModel(scriptIdForTwo));
		return runningScriptModels;
	}

	protected int getUserFirstScript(User user) {
		return this.getScriptService().loadScripts(user).get(0).getId();
	}

	protected int getUserSecondScript(User user) {
		return this.getScriptService().loadScripts(user).get(1).getId();
	}

	protected void deleteTestPlan() {
		this.getTestPlanRepository().detach(
				this.getTestPlanRepository()
						.getTestPlanInDomainBy(this.getTestPlanRunIdUuid())
						.getId());
	}

	protected ScriptBriefResultModel buildScriptBriefResultModel(int i) {
		ScriptBriefResultModel resultModel = new ScriptBriefResultModel();
		resultModel.setAverageElapsedTime(100 * i);
		resultModel.setAverageResponseTime(100 * i);
		resultModel.setFailRateThisTime(10 * i);
		return resultModel;
	}

	public static List<MonitorModel> createOneMonitorList() {
		List<MonitorModel> monitors = new ArrayList<MonitorModel>();
		monitors.add(buildMonitorModel());
		return monitors;
	}

	public static List<RunningScriptModel> createOneScriptList(int scriptId) {
		List<RunningScriptModel> list = new ArrayList<RunningScriptModel>();
		list.add(buildScriptModel(scriptId));
		return list;
	}

	public static RunningScriptModel buildScriptModel(int scriptID) {
		RunningScriptModel model = new RunningScriptModel();
		model.setScriptId(scriptID);
		model.setRequireLoad(EACH_SCRIPT_LOAD_SMALLSCALE);
		TestScriptConfig config = new TestScriptConfig();
		config.setWarmUp(20);
		config.setExecuteRange(60);
		config.setCoolDown(10);
		model.setConfig(config);
		return model;
	}

	private static MonitorModel buildMonitorModel() {
		MonitorModel monitorModel = new MonitorModel();
		monitorModel.setHostName(Monitor_Host_Name);
		monitorModel.setPort(Integer.parseInt(monitor_port));
		return monitorModel;
	}

	public TestPlan fetchTestPlan() {
		return this.getTestPlanRepository().getTestPlanInDomainBy(
				getTestPlanRunIdUuid());
	}
}
