package org.bench4q.master.domain.service.report;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import org.apache.log4j.Logger;
import org.bench4q.master.domain.entity.TestPlanScript;
import org.bench4q.master.domain.entity.TestPlanScriptResult;
import org.bench4q.master.domain.repository.TestPlanRepository;
import org.bench4q.master.domain.service.MonitorResultService;
import org.bench4q.master.domain.service.TestPlanScriptService;
import org.bench4q.master.domain.service.TestPlanService;
import org.bench4q.share.models.master.statistics.ScriptBriefResultModel;
import org.jfree.data.time.Second;
import org.jfree.data.time.TimeSeries;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.lowagie.text.Document;

@Component
public class ScriptReportService {
	public static String SCRIPT_TITLE = "Script result";
	public static String Average_Response_Time = "averageResponseTime(unit: ms)";
	public static String MAX_RESPONSE_TIME = "maxResponseTime(unit : time)";
	private TestPlanScriptService testPlanScriptService;
	private TestPlanService testPlanService;
	private TestPlanRepository testPlanRepository;
	private MonitorResultService monitorResultService;
	private Logger logger = Logger.getLogger(ScriptReportService.class);

	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 MonitorResultService getMonitorResultService() {
		return monitorResultService;
	}

	@Autowired
	public void setMonitorResultService(
			MonitorResultService monitorResultService) {
		this.monitorResultService = monitorResultService;
	}

	private TestPlanRepository getTestPlanRepository() {
		return testPlanRepository;
	}

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

	void createScriptsResultsImage(UUID testPlanRunId, Document document) {

		Set<TestPlanScript> scripts = this.getTestPlanRepository()
				.getTestPlanInDomainBy(testPlanRunId).getTestPlanScripts();
		if (scripts == null) {
			return;
		}
		for (TestPlanScript testPlanScript : scripts) {
			createScriptImage(this.getTestPlanScriptService()
					.queryScriptBriefResults(testPlanScript), document);
		}

	}

	private void createScriptImage(List<TestPlanScriptResult> results,
			Document document) {

		if (results == null) {
			return;
		}
		createAverageReponseTimeImage(results, document);
	}

	private void createAverageReponseTimeImage(
			List<TestPlanScriptResult> results, Document document) {
		List<TimeSeries> timeSeriesList = new ArrayList<TimeSeries>();
		if (results == null) {
			return;
		}
		addScriptSeries(results, timeSeriesList, "averageResponseTime");
		addScriptSeries(results, timeSeriesList, "maxResponseTime");
		try {
			ReportService.writeImageIntoPdf(
					ReportService.buildChartStream(document,
							timeSeriesList.size(), timeSeriesList,
							Average_Response_Time + "&" + MAX_RESPONSE_TIME)
							.toByteArray(), document);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// TODO: refactor this to a kind of command mode
	private void addScriptSeries(List<TestPlanScriptResult> results,
			List<TimeSeries> timeSeriesList, String fieldName) {
		try {
			TimeSeries timeSeries = new TimeSeries(fieldName);
			for (TestPlanScriptResult result : results) {
				if (!result.getResultType().equals(
						ScriptBriefResultModel.class.getName())) {
					continue;
				}
				ScriptBriefResultModel scriptBriefResultModel = result
						.extractScriptBriefResultModel();
				Field field = scriptBriefResultModel.getClass()
						.getDeclaredField(fieldName);
				field.setAccessible(true);
				timeSeries.addOrUpdate(new Second(result.getCreateDatetime()),
						field.getLong(scriptBriefResultModel));
			}
			timeSeriesList.add(timeSeries);
		} catch (Exception e) {
			logger.error(e.toString()
					+ " in addScriptSeries where fieldName is : " + fieldName);
		}

	}
}
