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

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.bench4q.master.domain.entity.MonitorResult;
import org.bench4q.master.domain.service.MonitorResultService;
import org.bench4q.master.domain.service.TestPlanScriptService;
import org.bench4q.master.domain.service.TestPlanService;
import org.bench4q.master.exception.Bench4QException;
import org.bench4q.share.helper.MarshalHelper;
import org.bench4q.share.models.master.MonitorResultContainerModel;
import org.bench4q.share.models.monitor.MemoryModel;
import org.bench4q.share.models.monitor.NetworkInterfaceModel;
import org.bench4q.share.models.monitor.PhysicalDiskModel;
import org.bench4q.share.models.monitor.ProcessorModel;
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 MonitorReportService {
	public static String Processor = "ProcessorTimePercent (unit: %)";
	public static String Memory = "Memory Available Memory(unit: KiloByte)";
	public static String logical_Disk = "logicalDisk IO (unit: Byte)";
	public static String network_Interface = "networkInterface IO (unit: Byte/second)";
	private TestPlanScriptService testPlanScriptService;
	private TestPlanService testPlanService;
	private MonitorResultService monitorResultService;

	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;
	}

	void createMonitorResultImages(UUID testPlanRunID, Document document) throws Bench4QException {
		Map<String, MonitorResultContainerModel> SUTResultMap = new HashMap<String, MonitorResultContainerModel>();
		List<MonitorResult> results = this.getMonitorResultService()
				.queryMonitorResults(testPlanRunID);
		if (results == null) {
			return;
		}

		for (MonitorResult result : results) {
			if (result == null) {
				continue;
			}
			buildSUTResultMap(SUTResultMap, result);
		}

		for (String hostName : SUTResultMap.keySet()) {
			createSUTImage(hostName, SUTResultMap.get(hostName), document);
		}
	}

	private void buildSUTResultMap(
			Map<String, MonitorResultContainerModel> sUTResultMap,
			MonitorResult result) {
		String hostName = result.getHostNameUnderMonitor();
		if (!sUTResultMap.containsKey(hostName)) {
			sUTResultMap.put(result.getHostNameUnderMonitor(),
					new MonitorResultContainerModel());
		}
		sortResultToList(result, sUTResultMap.get(hostName));
	}

	private void sortResultToList(final MonitorResult result,
			MonitorResultContainerModel container) {
		try {
			if (Class.forName(result.getType()).equals(PhysicalDiskModel.class)) {
				container.getLogicalDiskModels().add(
						(PhysicalDiskModel) MarshalHelper.unmarshal(
								PhysicalDiskModel.class, result.getContent()));
			} else if (Class.forName(result.getType())
					.equals(MemoryModel.class)) {
				container.getMemoryModels().add(
						(MemoryModel) MarshalHelper.unmarshal(
								MemoryModel.class, result.getContent()));
			} else if (Class.forName(result.getType()).equals(
					NetworkInterfaceModel.class)) {
				container.getNetWorkModels().add(
						(NetworkInterfaceModel) MarshalHelper.unmarshal(
								NetworkInterfaceModel.class,
								result.getContent()));
			} else if (Class.forName(result.getType()).equals(
					ProcessorModel.class)) {
				container.getProcessorModels().add(
						(ProcessorModel) MarshalHelper.unmarshal(
								ProcessorModel.class, result.getContent()));
			}
		} catch (Exception e) {
			e.printStackTrace();
			return;
		}
	}

	private void createSUTImage(String hostName,
			MonitorResultContainerModel container, Document document) {
		try {
			ReportService.addParagraph(logical_Disk, document);
			createLogicalDiskImage(container.getLogicalDiskModels(), document);
			ReportService.addParagraph(Memory, document);
			createMemoryImage(container.getMemoryModels(), document);
			ReportService.addParagraph(network_Interface, document);
//			createNetworkImage(container.getNetWorkModels(), document);
			ReportService.addParagraph(Processor, document);
			createProcessorImage(container.getProcessorModels(), document);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	private void createProcessorImage(List<ProcessorModel> list,
			Document document) throws Exception {
		if (list == null || list.size() == 0) {
			return;
		}
		int seriesCount = list.get(0).getProcessorModelList().size();

		List<TimeSeries> timeSeriesArray = ReportService.buildSeries(
				seriesCount, Processor);

		for (ProcessorModel model : list) {
			if (model == null)
				continue;
			for (int i = 0; i < timeSeriesArray.size(); i++) {
				timeSeriesArray.get(i).addOrUpdate(
						new Second(model.getSamplingTime()),
						model.getProcessorModelList().get(i)
								.getProcessorTimePercent());
			}
		}
		ReportService.writeImageIntoPdf(
				ReportService.buildChartStream(document, seriesCount,
						timeSeriesArray, Processor).toByteArray(), document);

	}

	private void createMemoryImage(List<MemoryModel> list, Document document)
			throws Exception {
		if (list == null || list.size() == 0) {
			return;
		}
		int seriesCount = 1;
		List<TimeSeries> timeSeriesArray = ReportService.buildSeries(
				seriesCount, Memory);
		for (MemoryModel model : list) {
			if (model == null)
				continue;
			for (int i = 0; i < timeSeriesArray.size(); i++) {
				timeSeriesArray.get(i).addOrUpdate(
						new Second(model.getSamplingTime()),
						model.getAvailableKiloBytes());
			}
		}
		ReportService.writeImageIntoPdf(
				ReportService.buildChartStream(document, seriesCount,
						timeSeriesArray, Memory).toByteArray(), document);
	}

	private void createLogicalDiskImage(List<PhysicalDiskModel> list,
			Document document) throws Exception {
		if (list == null || list.size() == 0) {
			return;
		}
		int seriesCount = list.get(0).getFieFileSystemModels().size();
		List<TimeSeries> timeSeriesArray = ReportService.buildSeries(
				seriesCount, logical_Disk);

		for (PhysicalDiskModel model : list) {
			if (model == null)
				continue;
			for (int i = 0; i < timeSeriesArray.size(); i++) {
				timeSeriesArray.get(i).addOrUpdate(
						new Second(model.getSamplingTime()),
						model.getFieFileSystemModels().get(i)
								.getDiskTotalKBytesRate());
			}
		}

		ReportService.writeImageIntoPdf(
				ReportService.buildChartStream(document, seriesCount,
						timeSeriesArray, logical_Disk).toByteArray(), document);
	}
	

	/**
	 * refactor this kind of use
	 * 
	 * @param list
	 * @param document
	 * @throws Exception
	 */

//	private void createNetworkImage(List<NetworkInterfaceModel> list,
//			Document document) throws Exception {
//		if (list == null || list.size() == 0) {
//			return;
//		}
//		int seriesCount = list.get(0).getNetworkList().size();
//		List<TimeSeries> timeSeriesArray = ReportService.buildSeries(
//				seriesCount, network_Interface);
//		for (NetworkInterfaceModel model : list) {
//			for (int i = 0; i < timeSeriesArray.size(); i++) {
//				timeSeriesArray.get(i).addOrUpdate(
//						new Second(model.getSamplingTime()),
//						model.getNetworkList().get(i).getBytesTotalPerSecond());
//			}
//		}
//		ReportService.writeImageIntoPdf(
//				ReportService.buildChartStream(document, seriesCount,
//						timeSeriesArray, network_Interface).toByteArray(),
//				document);
//	}
//}
}
