package org.bench4q.recorder.httpcapture;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import org.apache.log4j.Logger;
import org.bench4q.recorder.httpcapture.generator.ChildrenUrl;
import org.bench4q.share.helper.MarshalHelper;
import org.bench4q.share.helper.RunScenarioModelHelper;
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.BehaviorModel;
import org.bench4q.share.models.agent.scriptrecord.PageModel;
import org.bench4q.share.models.agent.scriptrecord.UsePluginModel;

public class Bench4qTestScriptAdapter implements IScriptAdapter {
	private int idGenerator =1;
	private int pageCount;
	private RunScenarioModel runScenarioModel;
	private List<ChildrenUrl> childrenUrls = new ArrayList<ChildrenUrl>();
	private static Logger logger = Logger
			.getLogger(Bench4qTestScriptAdapter.class);

	public RunScenarioModel getRunScenarioModel() {
		return runScenarioModel;
	}

	private void setRunScenarioModel(RunScenarioModel runScenarioModel) {
		this.runScenarioModel = runScenarioModel;
	}

	public List<ChildrenUrl> getChildrenUrls() {
		return childrenUrls;
	}

	private void setChildrenUrls(List<ChildrenUrl> childrenUrls) {
		this.childrenUrls = childrenUrls;
	}

	private int getPageCount() {
		return pageCount;
	}

	private void setPageCount(int pageCount) {
		this.pageCount = pageCount;
	}

	public Bench4qTestScriptAdapter(RunScenarioModel runScenarioModel) {
		this.runScenarioModel = runScenarioModel;
		this.setChildrenUrls(new ArrayList<ChildrenUrl>());
		this.setPageCount(0);
		initWithOnePage();
	}

	private void initWithOnePage() {
		addPage();
	}

	public void appendUsePluginsToScenario(List<UsePluginModel> usePluginModels) {
		this.runScenarioModel.setUsePlugins(usePluginModels);
	}

	public void addPage() {
		this.setPageCount(this.getPageCount() + 1);
		this.getRunScenarioModel().getPages().add(new PageModel(idGenerator++));
		assert (pageCountEqualWithPageSizeInScenario());
	}

	public void insertUserBehaviorsToScenario(BehaviorModel model) {
		List<BatchModel> batches = this.getCurrentPage().getBatches();
		model.setId(idGenerator++);
		int parentBatchId = -1;
		assert (batches != null);
		parentBatchId = getUrlParentBatch(model);
		if (isIndependent(parentBatchId)) {
			BatchModel batch = createBatchBehaviorWithProperBatchId();
			batch.getBehaviors().add(model);
			batches.add(batch);
			return;
		}
		guardChildBatchExist(batches, parentBatchId);
		batches.get(batches.get(parentBatchId).getChildId()).getBehaviors()
				.add(model);
	}

	private void guardChildBatchExist(List<BatchModel> batches,
			int parentBatchId) {
		if (isChildBatchAbsent(batches, parentBatchId)) {
			BatchModel batchBehavior = createBatchBehaviorWithProperBatchId();
			batchBehavior.setParentId(parentBatchId);
			batches.add(batchBehavior);
			batches.get(parentBatchId).setChildId(batches.size() - 1);
		}
	}

	private PageModel getCurrentPage() {
		if (!pageCountEqualWithPageSizeInScenario()) {
			logger.error("The page count is not equal with the size of scenario pages, and the page count is"
					+ this.getPageCount()
					+ " , and pageSize is "
					+ this.getRunScenarioModel().getPages().size());
			return new PageModel(idGenerator++);
		}
		return this.getRunScenarioModel().getPages()
				.get(this.getPageCount() - 1);
	}

	private boolean pageCountEqualWithPageSizeInScenario() {
		return this.getPageCount() == this.getRunScenarioModel().getPages()
				.size();
	}

	private BatchModel createBatchBehaviorWithProperBatchId() {
		BatchModel batchBehavior = new BatchModel(idGenerator++);
//		batchBehavior.setId(RunScenarioModelHelper.getBatches(
//				this.runScenarioModel).size());
		batchBehavior.setParentId(-1);
		batchBehavior.setChildId(-1);
//		List<BehaviorModel> behaviors = new ArrayList<BehaviorModel>();
//		batchBehavior.setBehaviors(behaviors);
		return batchBehavior;
	}

	private boolean isChildBatchAbsent(List<BatchModel> batches,
			int parentBatchId) {
		if (parentBatchId >= batches.size()) {
			return false;
		}
		return batches.get(parentBatchId).getChildId() < 0;
	}

	private boolean isIndependent(int parentBatchId) {
		return parentBatchId < 0;
	}

	public boolean isInChildrenUrl(String url) {
		for (ChildrenUrl childrenUrl : this.getChildrenUrls()) {
			if (childrenUrl.getUrl().equals(url)) {
				return true;
			}
		}
		return false;
	}

	private int getUrlParentBatch(BehaviorModel model) {
		int parentBatchId = -1;
		for (ParameterModel parameter : model.getParameters()) {
			if (!parameter.getKey().equals("url")) {
				continue;
			}
			parentBatchId = getParentBatchIdWithChildUrl(parameter.getValue());
		}
		return parentBatchId;
	}

	private int getParentBatchIdWithChildUrl(String url) {
		for (ChildrenUrl childrenUrl : this.getChildrenUrls()) {
			if (childrenUrl.getUrl().equals(url)) {
				return childrenUrl.getParentBatchId();
			}
		}
		return -1;
	}

	public int getParentBatchIdWithParentUrl(String url) {
		List<BatchModel> batchesInScenario = RunScenarioModelHelper
				.getBatches(this.getRunScenarioModel());
//		for (int batchId = 0; batchId < batchesInScenario.size(); batchId++) {
//			BatchModel batch = batchesInScenario.get(batchId);
//			for (BehaviorModel behavior : batch.getBehaviors()) {
//				for (ParameterModel parameter : behavior.getParameters()) {
//					if (parameter.getKey().equals("url")
//							&& parameter.getValue().equals(url)) {
//						return batchId;
//					}
//				}
//			}
//		}
		for (int i = 0; i < batchesInScenario.size(); i++) {
			BatchModel batch = batchesInScenario.get(i);
			for (BehaviorModel behavior : batch.getBehaviors()) {
				for (ParameterModel parameter : behavior.getParameters()) {
					if (parameter.getKey().equals("url")
							&& parameter.getValue().equals(url)) {
						return batch.getId();
					}
				}
			}
		}
		return -1;
	}

	public void resetChildrenUrls() {
		this.getChildrenUrls().clear();
	}

	public String getText() {
		StringWriter stringWriter = new StringWriter();
		try {
			Marshaller marshaller = JAXBContext.newInstance(
					this.runScenarioModel.getClass()).createMarshaller();
			marshaller.marshal(this.runScenarioModel, stringWriter);
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
		} catch (JAXBException e) {
			e.printStackTrace();
		}

		return stringWriter.toString();
	}

	public void setText(String text) {
		if (text == null || text.isEmpty()) {
			// this.setRunScenarioModel(new RunScenarioModelNew());
			return;
		}
		try {
			this.setRunScenarioModel((RunScenarioModel) MarshalHelper
					.unmarshal(RunScenarioModel.class, text));
		} catch (JAXBException e) {
			logger.error(e, e);
			this.setRunScenarioModel(new RunScenarioModel());
		}
	}

}
