package org.bench4q.master.domain.service;

import java.util.Date;
import java.util.List;
import java.util.UUID;

import org.apache.log4j.Logger;
import org.bench4q.master.domain.entity.MonitorResult;
import org.bench4q.master.domain.repository.TestPlanRepository;
import org.bench4q.master.exception.Bench4QException;
import org.bench4q.master.exception.ExceptionLog;
import org.bench4q.master.helper.SessionHelper;
import org.bench4q.share.helper.MarshalHelper;
import org.bench4q.share.models.master.MonitorPhysicalDiskResponseModel;
import org.bench4q.share.models.master.MonitorMemoryResponseModel;
import org.bench4q.share.models.master.MonitorNetworkReponseModel;
import org.bench4q.share.models.master.MonitorProcessorResponseModel;
import org.bench4q.share.models.master.MonitorResultBase;
import org.bench4q.share.models.master.statistics.SampleModel;
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.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MonitorResultService {
	private TestPlanRepository testPlanRepository;
	private SessionHelper sessionHelper;
	private static Logger logger = Logger.getLogger(MonitorResult.class);

	private TestPlanRepository getTestPlanRepository() {
		return testPlanRepository;
	}

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

	public SessionHelper getSessionHelper() {
		return sessionHelper;
	}

	@Autowired
	public void setSessionHelper(SessionHelper sessionHelper) {
		this.sessionHelper = sessionHelper;
	}

	@SuppressWarnings("unchecked")
	public List<MonitorResult> queryMonitorResults(UUID testPlanRunId)
			throws Bench4QException {
		Session session = this.getSessionHelper().openSession();
		try {
			return session
					.createCriteria(MonitorResult.class)
					.add(Restrictions.eq(
							"testPlanDB",
							this.getTestPlanRepository().getTestPlanInDomainBy(
									testPlanRunId)))
					.addOrder(Order.asc("createDatetime")).list();

		} catch (Exception e) {
			logger.info(ExceptionLog.getStackTrace(e));
			throw new Bench4QException("", "get MonitorResult from db failed",
					"monitor service");
		} finally {
			if (session != null) {
				session.close();
			}
		}
	}

	public MonitorPhysicalDiskResponseModel physicalDiskDiskResults(
			UUID testPlanRunId, String hostName, int port, long beginTime)
			throws Bench4QException {
		try {
			return loadMonitorResultModel(testPlanRunId, hostName, beginTime,
					PhysicalDiskModel.class,
					MonitorPhysicalDiskResponseModel.class);
		} catch (Exception e) {
			logger.error(ExceptionLog.getStackTrace(e));
			throw new Bench4QException("",
					"laod monitor physicalDisk result failed",
					"monitor service");
		}
	}

	@SuppressWarnings("unchecked")
	private List<MonitorResult> doGetMonitorResultsByeTypeAndBeginDate(
			UUID testPlanRunId, String hostName, long beginTime,
			Session session, Class<?> resultClass) {
		return session
				.createCriteria(MonitorResult.class)
				.add(Restrictions.eq("testPlanDB", this.getTestPlanRepository()
						.getTestPlanInDomainBy(testPlanRunId)))
				.add(Restrictions.eq("hostNameUnderMonitor", hostName))
				.add(Restrictions.eq("type", resultClass.getName()))
				.add(Restrictions.ge("createDatetime", new Date(beginTime)))
				.addOrder(Order.asc("createDatetime")).list();
	}

	public MonitorMemoryResponseModel loadMemoryModels(UUID testPlanRunId,
			String hostName, int port, long beginTime) throws Bench4QException {
		try {
			return loadMonitorResultModel(testPlanRunId, hostName, beginTime,
					MemoryModel.class, MonitorMemoryResponseModel.class);
		} catch (Exception e) {
			logger.error(ExceptionLog.getStackTrace(e));
			throw new Bench4QException("", "laod monitor memory result failed",
					"monitor service");
		}
	}

	public MonitorProcessorResponseModel loadProcessorModels(
			UUID testPlanRunId, String hostName, int port, long beginTime)
			throws Bench4QException {
		try {
			return loadMonitorResultModel(testPlanRunId, hostName, beginTime,
					ProcessorModel.class, MonitorProcessorResponseModel.class);
		} catch (Exception e) {
			logger.error(ExceptionLog.getStackTrace(e));
			throw new Bench4QException("",
					"laod monitor processor result failed", "monitor service");
		}
	}

	@SuppressWarnings("unchecked")
	private <T1 extends SampleModel, T2 extends MonitorResultBase> T2 loadMonitorResultModel(
			UUID testPlanRunId, String hostName, long beginTime,
			Class<T1> fromMonitorClass, Class<T2> resultClass) throws Exception {
		Session session = this.getSessionHelper().openSession();
		try {
			T2 ret = resultClass.newInstance();
			List<MonitorResult> monitorResults = doGetMonitorResultsByeTypeAndBeginDate(
					testPlanRunId, hostName, beginTime, session,
					fromMonitorClass);
			for (MonitorResult monitorResult : monitorResults) {

				assert (fromMonitorClass.getName().equals(monitorResult
						.getType()));
				T1 result = (T1) MarshalHelper.unmarshal(fromMonitorClass,
						monitorResult.getContent());

				ret.add(result);
			}
			return ret;
		} catch (Exception e) {

			throw e;
		} finally {
			if (session != null) {
				session.close();
			}
		}
	}

	public MonitorNetworkReponseModel loadNetworkInterfaceModels(
			UUID testPlanRunId, String hostName, int port, long beginTime)
			throws Bench4QException {
		try {
			return loadMonitorResultModel(testPlanRunId, hostName, beginTime,
					NetworkInterfaceModel.class,
					MonitorNetworkReponseModel.class);
		} catch (Exception e) {
			logger.error(ExceptionLog.getStackTrace(e));
			throw new Bench4QException("",
					"laod monitor network result failed", "monitor service");
		}
	}

}
