package org.bench4q.agent.scenario.engine;

import java.util.HashMap;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.UUID;

import org.apache.log4j.Logger;
import org.bench4q.agent.plugin.PluginManager;
import org.bench4q.agent.scenario.Scenario;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class ScenarioEngine implements Observer {
	private Map<UUID, ScenarioContext> runningTests;
	private final Logger logger = Logger.getLogger(ScenarioEngine.class);
	private PluginManager pluginManager;

	public ScenarioEngine() {
		this.setRunningTests(new HashMap<UUID, ScenarioContext>());
	}

	public Map<UUID, ScenarioContext> getRunningTests() {
		return runningTests;
	}

	private void setRunningTests(Map<UUID, ScenarioContext> runningTests) {
		this.runningTests = runningTests;
	}

	private PluginManager getPluginManager() {
		return pluginManager;
	}

	@Autowired
	private void setPluginManager(PluginManager pluginManager) {
		this.pluginManager = pluginManager;
	}

	public void addRunningTestWithoutScenario(UUID runId, int poolSize) {
		try {
			final ScenarioContext scenarioContext = ScenarioContext
					.buildScenarioContextWithoutScenario(runId, poolSize,
							getPluginManager());
			this.getRunningTests().put(runId, scenarioContext);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void submitScenario(final UUID runId, final Scenario scenario,
			final Schedule schedule, final long realStartTime) {
		try {
			ScenarioContext old = this.getRunningTests().get(runId);
			this.getRunningTests().put(runId,
					old.addScenrio(scenario, schedule, realStartTime));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public boolean runWith(UUID runId) {
		if (!this.getRunningTests().containsKey(runId)) {
			return false;
		}
		final ScenarioContext context = this.getRunningTests().get(runId);
		return runWith(context);
	}

	private boolean runWith(final ScenarioContext scenarioContext) {
		if (scenarioContext == null) {
			logger.error("The context required is null");
			return false;
		}
		try {
			int currentLoad = scenarioContext.getSchedule().loadFor(
					System.currentTimeMillis()
							- scenarioContext.getStartDate().getTime());
			scenarioContext.initTasks(currentLoad);
			new Supervisor(scenarioContext).start();
			return true;
		} catch (Exception e) {
			this.logger.info(e, e);
			return false;
		}
	}

	@Override
	public void update(Observable o, Object arg) {
		if (!(o instanceof Supervisor)) {
			return;
		}
		UUID testId = (UUID) arg;
		this.getRunningTests().remove(testId);
	}

}
