package org.bench4q.master.domain.entity;

import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.apache.log4j.Logger;
import org.bench4q.master.domain.factory.TestPlanFactory;
import org.bench4q.master.domain.valueobject.datastatistics.TestMonitorSampler;
import org.bench4q.master.exception.ExceptionLog;
import org.bench4q.master.helper.ApplicationContextHelper;
import org.bench4q.share.helper.MarshalHelper;
import org.bench4q.share.models.monitor.MemoryModel;
import org.bench4q.share.models.monitor.MonitorMain;
import org.bench4q.share.models.monitor.NetworkInterfaceModel;
import org.bench4q.share.models.monitor.PhysicalDiskModel;
import org.bench4q.share.models.monitor.ProcessModel;
import org.bench4q.share.models.monitor.ProcessModelChild;
import org.bench4q.share.models.monitor.ProcessorModel;
import org.bench4q.share.models.monitor.ProcessorModelChild;

@Entity
@Table(name = "monitor")
public class Monitor {
	private int id;
	private String hostName;
	private int port;
	private TestPlan testPlan;
	private Set<MonitorResult> results;
	private Logger logger = Logger.getLogger(Monitor.class);
	private TestPlanFactory testPlanFactory;

	public Monitor() {
		this.results = new HashSet<MonitorResult>();
	}

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id", nullable = false)
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	@Column(name = "hostName", nullable = false)
	public String getHostName() {
		return hostName;
	}

	public void setHostName(String hostName) {
		this.hostName = hostName;
	}

	@Column(name = "port", nullable = false)
	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	@ManyToOne
	@JoinColumn(name = "testPlanId")
	public TestPlan getTestPlan() {
		return testPlan;
	}

	public void setTestPlan(TestPlan testPlan) {
		this.testPlan = testPlan;
	}

	@OneToMany(mappedBy = "monitor", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
	public Set<MonitorResult> getResults() {
		return results;
	}

	public void setResults(Set<MonitorResult> results) {
		this.results = results;
	}

	@Transient
	public TestMonitorSampler getTestMonitorSampler() {
		return ApplicationContextHelper.getContext().getBean(
				TestMonitorSampler.class);
	}

	@Transient
	public TestPlanFactory getTestPlanFactory() {
		return testPlanFactory;
	}

	public void setTestPlanFactory(TestPlanFactory testPlanFactory) {
		this.testPlanFactory = testPlanFactory;
	}

	public void doRunInit() {

	}

	public List<MonitorResult> doAfterRun(Date sampeTime) {
		try {
			MonitorMain monitorMain = getTestMonitorSampler().getMonitorResult(
					hostName, port);
			System.out.println(MarshalHelper.tryMarshal(monitorMain));
			List<MonitorResult> monitorResults = this.getTestPlanFactory()
					.createMonitorResultListWithOutId(monitorMain, testPlan,
							this, sampeTime);
			return monitorResults;

		} catch (Exception e) {
			logger.error(ExceptionLog.getStackTrace(e));
			return null;
		}
	}

	public List<MonitorResult> createFinishedResult() {
		try {
			MonitorMain monitorMain = createFinishedMonitorMain();
			List<MonitorResult> monitorResults = this.getTestPlanFactory()
					.createMonitorResultListWithOutId(monitorMain, testPlan,
							this, monitorMain.getSamplingTime());
			return monitorResults;

		} catch (Exception e) {
			logger.error(ExceptionLog.getStackTrace(e));
			return null;
		}

	}

	private MonitorMain createFinishedMonitorMain() {
		MonitorMain monitorMain = new MonitorMain();
		Date date = new Date();
		monitorMain.setSamplingTime(date);
		monitorMain.setFinished(true);
		monitorMain.setMemoryModel(createFinishedMemoryModel(date));
		monitorMain
				.setNetworkInterfaceModel(createFinishedNetworkInterfaceModel(date));
		monitorMain.setProcessorModel(createFinishedProcessorModel(date));
		monitorMain.setPhysicalDiskModel(createFinishedPhysicalDiskModel(date));
		monitorMain.setProcessModel(createFinishedProcessModel(date));
		return monitorMain;

	}

	private ProcessorModel createFinishedProcessorModel(Date date) {
		ProcessorModel processorModel = new ProcessorModel();
		processorModel.setSamplingTime(date);
		processorModel.setFinished(true);
		processorModel
				.setProcessorModelList(new LinkedList<ProcessorModelChild>());
		processorModel.setCpuInstanceList(new LinkedList<String>());
		return processorModel;
	}

	private MemoryModel createFinishedMemoryModel(Date date) {
		MemoryModel memoryModel = new MemoryModel();
		memoryModel.setFinished(true);
		memoryModel.setSamplingTime(date);
		return memoryModel;
	}

	private PhysicalDiskModel createFinishedPhysicalDiskModel(Date date) {
		PhysicalDiskModel physicalDiskModel = new PhysicalDiskModel();
		physicalDiskModel.setFinished(true);
		physicalDiskModel.setSamplingTime(date);
		return physicalDiskModel;
	}

	private NetworkInterfaceModel createFinishedNetworkInterfaceModel(Date date) {
		NetworkInterfaceModel networkInterfaceModel = new NetworkInterfaceModel();
		networkInterfaceModel.setFinished(true);
		networkInterfaceModel.setSamplingTime(date);
		return networkInterfaceModel;
	}

	private ProcessModel createFinishedProcessModel(Date date) {

		ProcessModel processModel = new ProcessModel();
		processModel.setProcessModelList(new LinkedList<ProcessModelChild>());
		processModel.setProcessNameList(new LinkedList<String>());
		processModel.setFinished(true);
		processModel.setSamplingTime(date);
		return processModel;
	}

}
