package org.bench4q.master.unitTest.controller;

import static org.junit.Assert.*;

import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

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

import org.bench4q.master.unitTest.TestBase_MakeUpTestPlan;
import org.bench4q.share.communication.HttpRequester;
import org.bench4q.share.communication.HttpRequester.HttpResponse;
import org.bench4q.share.enums.master.TestPlanStatus;
import org.bench4q.share.helper.MarshalHelper;
import org.bench4q.share.models.master.MonitorPhysicalDiskResponseModel;
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.TestPlanResultModel;
import org.bench4q.share.models.master.TestPlanScriptBriefResultModel;
import org.bench4q.share.models.master.statistics.ScriptBriefResultModel;
import org.bench4q.share.models.master.statistics.ScriptPagesBriefModel;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:service-test-context.xml" })
public class Test_TestPlanController extends TestBase_MakeUpTestPlan {
	private TestPlanModel testPlanBusinessModel = new TestPlanModel();
	private String _url = TestBase.BASE_URL + "/testPlan";
	private int scriptSumNum;
	public static int SCRIPTID1 = 26;
	private static int SCRIPTID2 = 2;
	private static String Monitor_Host_Name = "133.133.12.3";
	private static String monitor_port = "5556";

	public TestPlanModel getTestPlanBusinessModel() {
		return testPlanBusinessModel;
	}

	public void setTestPlanBusinessModel(TestPlanModel testPlanBusinessModel) {
		this.testPlanBusinessModel = testPlanBusinessModel;
	}

	public int getScriptSumNum() {
		return scriptSumNum;
	}

	public void setScriptSumNum(int scriptSumNum) {
		this.scriptSumNum = scriptSumNum;
	}

	@SuppressWarnings("resource")
	public Test_TestPlanController() {
		new ClassPathXmlApplicationContext("classpath:service-test-context.xml");
	}

	public void testAllRight() throws JAXBException, IOException,
			InterruptedException {
		this.setScriptSumNum(1);
		this.setAccessTocken(this.login());
		this.runAndGetBrief();
	}

	@Before
	public void prepare() {
		this.setAccessTocken(this.login());
	}

	@Test
	public void testWithoutBrief() throws JAXBException, IOException,
			InterruptedException {
		this.setScriptSumNum(1);
		this.setAccessTocken(this.login());
		this.setTestPlanRunIdUuid(testWithTestPlanModel());
		@SuppressWarnings("unused")
		TestPlanResultModel resultModel = this.getRunningInfo(this
				.getTestPlanRunIdUuid());
		// System.out.println(MarshalHelper.marshal(TestPlanResultModel.class,
		// resultModel));
		Thread.sleep(60000);
		this.getTestPlanReport(this.getTestPlanRunIdUuid());
	}

	public void behaviorsBrief(UUID testPlanID, int scriptId)
			throws IOException {
		HttpResponse httpResponse = this.httpRequester.sendGet(_url
				+ "/getBehaviorsBrief/" + testPlanID.toString() + "/"
				+ scriptId, null, makeAccessTockenMap(this.accessTocken));
		if (HttpRequester.isInvalidResponse(httpResponse)) {
			System.out.println("Invalid response in behaviorsBrief");
			return;
		}
		System.out.println(httpResponse.getContent());
	}

	public void runAndGetBrief() throws IOException, JAXBException,
			InterruptedException {
		UUID testPlanID = this.testWithTestPlanModel();
		Thread.sleep(10000);
		while (this.getRunningInfo(testPlanID).getCurrentStatus() != TestPlanStatus.InRunning) {
			Thread.sleep(6000);
		}

		for (int i = 0; i < 20; i++) {
			Thread.sleep(3000);
			this.getScriptBrief(testPlanID, SCRIPTID1);
			this.behaviorsBrief(testPlanID, SCRIPTID1);
			this.getPagesBriefModel(testPlanID, SCRIPTID1, 0);
		}

		this.getMonitorBrief(testPlanID, Monitor_Host_Name, monitor_port);
		this.getTestPlanReport(testPlanID);
	}

	public void runTestWithoutLogin() {
		this.setTestPlanBusinessModel(new TestPlanModel());
		try {
			HttpResponse httpResponse = this.httpRequester.sendPostXml(
					this._url + "/runTestPlanWithTestPlanModel",
					marshalTestPlanToString(), null);
			System.out.println(httpResponse.getCode());
		} catch (IOException e) {
			e.printStackTrace();
		} catch (JAXBException e) {
			e.printStackTrace();
		}
	}

	public UUID testWithTestPlanModel() throws JAXBException, IOException {
		String content;
		TestPlanResultModel result = new TestPlanResultModel();

		this._createATestPlan();
		content = marshalTestPlanToString();

		HttpResponse httpResponse = this.httpRequester.sendPostXml(this._url
				+ "/runTestPlanWithTestPlanModel", content,
				this.makeAccessTockenMap(this.accessTocken));

		result = (TestPlanResultModel) MarshalHelper.unmarshal(
				TestPlanResultModel.class, httpResponse.getContent());
		System.out.println(result.getCurrentStatus());
		return result.getTestPlanId();
	}

	private String marshalTestPlanToString() throws JAXBException {
		StringWriter stringWriter = new StringWriter();
		Marshaller marshaller = JAXBContext.newInstance(
				this.testPlanBusinessModel.getClass()).createMarshaller();
		marshaller.marshal(this.testPlanBusinessModel, stringWriter);
		return stringWriter.toString();
	}

	public static TestPlanModel createATestPlanWithZeroMonitor(int scriptId) {
		TestPlanModel testPlanBusinessModel = new TestPlanModel();
		testPlanBusinessModel.setMonitorModels(new ArrayList<MonitorModel>());
		testPlanBusinessModel
				.setRunningScriptModels(createOneScriptList(SCRIPTID1));
		return testPlanBusinessModel;
	}

	public static TestPlanModel createATestPlanWithNullMonitorList(int scriptId) {
		TestPlanModel testPlanBusinessModel = new TestPlanModel();
		testPlanBusinessModel.setMonitorModels(null);
		testPlanBusinessModel
				.setRunningScriptModels(createOneScriptList(scriptId));
		return testPlanBusinessModel;
	}

	public TestPlanModel _createATestPlan() {
		if (this.getScriptSumNum() == 1) {
			this.testPlanBusinessModel
					.setRunningScriptModels(createOneScriptList(SCRIPTID1));
		} else if (getScriptSumNum() == 2) {
			this.testPlanBusinessModel
					.setRunningScriptModels(createTowScriptList());
		} else {
			return null;
		}
		this.testPlanBusinessModel.setMonitorModels(createOneMonitorList());
		return this.testPlanBusinessModel;
	}

	private List<RunningScriptModel> createTowScriptList() {
		List<RunningScriptModel> list = new ArrayList<RunningScriptModel>();
		list.add(buildScriptModel(SCRIPTID1));
		list.add(buildScriptModel(SCRIPTID2));
		return list;
	}

	public TestPlanResultModel getRunningInfo(UUID testPlanId)
			throws IOException, JAXBException {
		Map<String, String> params = new HashMap<String, String>();
		params.put("testPlanId", testPlanId.toString());

		HttpResponse httpResponse = this.httpRequester.sendGet(this._url
				+ "/getRunningInfo", params,
				this.makeAccessTockenMap(this.getAccessTocken()));
		TestPlanResultModel ret = (TestPlanResultModel) MarshalHelper
				.unmarshal(TestPlanResultModel.class, httpResponse.getContent());
		System.out.println(ret.getCurrentStatus());
		return ret;
	}

	public TestPlanScriptBriefResultModel getScriptBrief(UUID testPlanId,
			int scriptId) throws IOException, JAXBException {
		HttpResponse httpResponse = this.httpRequester.sendGet(this._url
				+ "/scriptBrief/" + testPlanId.toString() + "/" + scriptId
				+ "/" + 0, null, createAccessTokenMap());
		System.out.println(httpResponse.getContent());
		TestPlanScriptBriefResultModel ret = (TestPlanScriptBriefResultModel) MarshalHelper
				.unmarshal(TestPlanScriptBriefResultModel.class,
						httpResponse.getContent());
		for (ScriptBriefResultModel scriptBriefResultModel : ret
				.getScriptBriefResultModels()) {
			System.out.println(scriptBriefResultModel.getAverageResponseTime());
		}
		return ret;
	}

	public ScriptPagesBriefModel getPagesBriefModel(UUID testPlanId,
			int scriptId, int pageId) throws IOException, JAXBException {
		HttpResponse httpResponse = this.httpRequester.sendGet(this._url
				+ "/pagesBrief/" + testPlanId.toString() + "/" + scriptId,
				null, createAccessTokenMap());
		System.out.println(httpResponse.getContent());
		ScriptPagesBriefModel ret = (ScriptPagesBriefModel) MarshalHelper
				.unmarshal(ScriptPagesBriefModel.class,
						httpResponse.getContent());
		return ret;
	}

	private Map<String, String> createAccessTokenMap() {
		Map<String, String> properties = new HashMap<String, String>();
		properties.put(this.AUTH_HEADER_PROPERTY, this.ACCES_TOCKEN_STARTER
				+ this.accessTocken);
		return properties;
	}

	public void getMonitorBrief(UUID testPlanID, String hostName, String port)
			throws IOException, InterruptedException, JAXBException {
		for (int i = 0; i < 2; i++) {
			getMonitorMemoryResult(testPlanID, hostName, port);
			getProcessorResult(testPlanID, hostName, port);
			getLogicalDiskResult(testPlanID, hostName, port);
			getNetworkInterfaceResult(testPlanID, hostName, port);
		}
	}

	private void getMonitorMemoryResult(UUID testPlanId, String hostName,
			String port) throws IOException {
		getMonitorResult(testPlanId, hostName, port,
				"/monitorController/memorySUTInfo");

	}

	private void getProcessorResult(UUID testPlanId, String hostName,
			String port) throws IOException {
		getMonitorResult(testPlanId, hostName, port,
				"/monitorController/processorSUTInfo");
	}

	private void getLogicalDiskResult(UUID testPlanID, String hostName,
			String port) throws IOException, JAXBException {
		HttpResponse httpResponse = this.httpRequester.sendGet(
				TestBase.BASE_URL
						+ "/monitorController/logicDiskMonitorSUTInfo/"
						+ testPlanID.toString() + "/" + hostName + "/6565/0",
				null, this.createAccessTokenMap());
		System.out.println(httpResponse.getContent());
		MonitorPhysicalDiskResponseModel logicalDiskResponseModel = (MonitorPhysicalDiskResponseModel) MarshalHelper
				.unmarshal(MonitorPhysicalDiskResponseModel.class,
						httpResponse.getContent());
		assertNotNull(logicalDiskResponseModel);
	}

	private void getNetworkInterfaceResult(UUID testPlanID, String hostName,
			String port) throws IOException {
		getMonitorResult(testPlanID, hostName, port,
				"/monitorController/networkInfo");
	}

	private void getMonitorResult(UUID testPlanId, String hostName,
			String port, String relativePath) throws IOException {
		Map<String, String> params = new HashMap<String, String>();
		params.put("testPlanRunId", testPlanId.toString());
		params.put("hostName", hostName);
		params.put("port", port);
		params.put("duationBegin", 0 + "");
		HttpResponse httpResponse = this.httpRequester.sendGet(
				TestBase.BASE_URL + relativePath, params,
				this.createAccessTokenMap());
		System.out.println(httpResponse.getContent());
	}

	public void loadTestPlans() throws IOException {
		HttpResponse httpResponse = this.httpRequester.sendGet(this._url
				+ "/loadTestPlans", null,
				this.makeAccessTockenMap(this.getAccessTocken()));
		System.out.println(httpResponse.getContent());
	}

	public void getTestPlanReport(UUID testPlanID) throws IOException {
		Map<String, String> params = new HashMap<String, String>();
		params.put("testPlanRunID", testPlanID.toString());
		this.httpRequester.sendGet(this._url + "/getTestPlanReport", params,
				this.makeAccessTockenMap(this.getAccessTocken()));
	}

}
