package org.bench4q.agent.scenario;

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

import org.bench4q.agent.scenario.behavior.Behavior;
import org.bench4q.share.helper.MarshalHelper;
import org.bench4q.share.models.agent.ParameterModel;
import org.bench4q.share.models.agent.RunScenarioModel;
import org.bench4q.share.models.agent.scriptrecord.BatchModel;
import org.bench4q.share.models.agent.scriptrecord.PageModel;
import org.bench4q.share.models.agent.scriptrecord.UsePluginModel;

public class Scenario {
	private UsePlugin[] usePlugins;
	private Page[] pages;
	private List<Behavior> behaviors;

	public UsePlugin[] getUsePlugins() {
		return usePlugins;
	}

	private void setUsePlugins(UsePlugin[] usePlugins) {
		this.usePlugins = usePlugins;
	}

	public Page[] getPages() {
		return pages;
	}

	private void setPages(Page[] pages) {
		this.pages = pages;
	}

	private List<Behavior> getBehaviors() {
		return behaviors;
	}

	private void setBehaviors(List<Behavior> behaviors) {
		this.behaviors = behaviors;
	}

	public Scenario() {
		this.setBehaviors(new ArrayList<Behavior>());
	}

	public List<Behavior> getAllBehaviors() {
		if (this.getBehaviors().size() > 0) {
			return Collections.unmodifiableList(this.getBehaviors());
		}
		List<Behavior> behaviors = new ArrayList<Behavior>();
		for (Page page : this.getPages()) {
			for (Batch batch : page.getBatches()) {
				for (Behavior behavior : batch.getBehaviors()) {
					behaviors.add(behavior);
				}
			}
		}
		return Collections.unmodifiableList(behaviors);
	}

	public void compile() {
		for (Behavior behavior : this.getAllBehaviors()) {
			behavior.compile();
		}
	}

	public static Scenario scenarioBuilderWithCompile(String scenarioContent) {
		return scenarioBuilderWithCompile((RunScenarioModel) MarshalHelper
				.tryUnmarshal(RunScenarioModel.class, scenarioContent));
	}

	public static Scenario scenarioBuilderWithCompile(
			RunScenarioModel scenarioModel) {
		if (scenarioModel == null) {
			throw new NullPointerException();
		}
		Scenario scenario = extractScenario(scenarioModel);
		scenario.compile();
		return scenario;
	}

	private static Scenario extractScenario(RunScenarioModel runScenarioModel) {
		Scenario scenario = new Scenario();
		scenario.setUsePlugins(new UsePlugin[runScenarioModel.getUsePlugins()
				.size()]);
		scenario.setPages(new Page[runScenarioModel.getPages().size()]);
		extractUsePlugins(runScenarioModel, scenario);
		extractPages(runScenarioModel, scenario);
		return scenario;
	}

	private static void extractPages(RunScenarioModel runScenarioModel,
			Scenario scenario) {
		List<PageModel> pageModels = runScenarioModel.getPages();
		for (int i = 0; i < pageModels.size(); i++) {
			PageModel pageModel = pageModels.get(i);
			scenario.getPages()[i] = extractPage(pageModel);
		}
	}

	private static Page extractPage(PageModel pageModel) {
		Page page = new Page();
		page.setBatches(new Batch[pageModel.getBatches().size()]);
		List<BatchModel> batches = pageModel.getBatches();
		for (int i = 0; i < pageModel.getBatches().size(); i++) {
			BatchModel batch = batches.get(i);
			page.getBatches()[i] = extractBatch(batch);
		}
		return page;
	}

	private static Batch extractBatch(BatchModel batchModel) {
		Batch batch = new Batch();
		batch.setBehaviors(new Behavior[batchModel.getBehaviors().size()]);
		batch.setId(batchModel.getId());
		batch.setParentId(batchModel.getParentId());
		batch.setChildId(batchModel.getChildId());
		if (batchModel.getBehaviors() == null) {
			return batch;
		}
		batch.setBehaviors(new Behavior[batchModel.getBehaviors().size()]);
		for (int i = 0; i < batchModel.getBehaviors().size(); ++i) {
			batch.getBehaviors()[i] = Behavior.buildWith(batchModel
					.getBehaviors().get(i));
		}
		return batch;
	}

	private static void extractUsePlugins(RunScenarioModel runScenarioModel,
			Scenario scenario) {
		int i;
		List<UsePluginModel> usePluginModels = runScenarioModel.getUsePlugins();
		for (i = 0; i < runScenarioModel.getUsePlugins().size(); i++) {
			UsePluginModel usePluginModel = usePluginModels.get(i);
			UsePlugin usePlugin = extractUsePlugin(usePluginModel);
			scenario.getUsePlugins()[i] = usePlugin;
		}
	}

	private static UsePlugin extractUsePlugin(UsePluginModel usePluginModel) {
		UsePlugin usePlugin = new UsePlugin();
		usePlugin.setId(usePluginModel.getId());
		usePlugin.setName(usePluginModel.getName());
		usePlugin.setNickName(usePluginModel.getNickName());
		if (usePluginModel.getParameters() != null) {
			usePlugin.setParameters(new Parameter[usePluginModel
					.getParameters().size()]);
			int k = 0;
			for (k = 0; k < usePluginModel.getParameters().size(); k++) {
				ParameterModel parameterModel = usePluginModel.getParameters()
						.get(k);
				Parameter parameter = extractParameter(parameterModel);
				usePlugin.getParameters()[k] = parameter;
			}
		}
		return usePlugin;
	}

	private static Parameter extractParameter(ParameterModel parameterModel) {
		Parameter parameter = new Parameter();
		parameter.setKey(parameterModel.getKey());
		parameter.setValue(parameterModel.getValue());
		return parameter;
	}
}
