package org.bench4q.master.infrastructure.communication.impl;

import java.io.IOException;
import java.util.Date;

import javax.xml.bind.JAXBException;

import org.apache.log4j.Logger;
import org.bench4q.master.exception.ExceptionLog;
import org.bench4q.master.infrastructure.communication.MonitorMessenger;
import org.bench4q.share.communication.HttpRequester;
import org.bench4q.share.communication.HttpRequester.HttpResponse;
import org.bench4q.share.helper.MarshalHelper;
import org.bench4q.share.models.master.statistics.SampleModel;
import org.bench4q.share.models.monitor.MonitorMain;
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.ProcessModel;
import org.bench4q.share.models.monitor.ProcessorModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MonitorMessengerImpl implements MonitorMessenger {
	private HttpRequester httpRequester;
	private Logger logger = Logger.getLogger(MonitorMessengerImpl.class);

	private HttpRequester getHttpRequester() {
		return httpRequester;
	}

	@Autowired
	private void setHttpRequester(HttpRequester httpRequester) {
		this.httpRequester = httpRequester;
	}

	private String buildUrl(String hostName, int port, String relativePath) {
		return hostName + ":" + port + relativePath;
	}

	public PhysicalDiskModel physicalDisk(String hostName, int port) {
		return getMonitorModel(hostName, port, PhysicalDiskModel.class,
				"physicalDisk");
	}

	private <T extends SampleModel> T getMonitorModel(String hostName,
			int port, Class<T> resultClass, String monitorTarget) {
		try {
			Date sampleDate = new Date();
			HttpResponse httpResponse = this.getHttpRequester().sendGet(
					buildUrl(hostName, port, "/monitor/" + monitorTarget),
					null, null);
			if (HttpRequester.isInvalidResponse(httpResponse)) {
				logger.info("The httpResponse is invalid ");
				return null;
			}
			@SuppressWarnings("unchecked")
			T model = (T) MarshalHelper.unmarshal(resultClass,
					httpResponse.getContent());
			model.setSamplingTime(sampleDate);

			return model;

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

	public MemoryModel memory(String hostName, int port) {
		return getMonitorModel(hostName, port, MemoryModel.class, "memory");
	}

	public ProcessorModel processor(String hostName, int port) {
		return this.getMonitorModel(hostName, port, ProcessorModel.class,
				"processor");

	}

	public NetworkInterfaceModel networkInterface(String hostName, int port) {
		return this.getMonitorModel(hostName, port,
				NetworkInterfaceModel.class, "network");
	}

	public ProcessModel process(String hostName, int port) {
		return this.getMonitorModel(hostName, port, ProcessModel.class,
				"process");
	}

	public MonitorMain monitorModel(String hostName, int port) {
		MonitorMain monitorMain = this.getMonitorModel(hostName, port,
				MonitorMain.class, "all");
		monitorMain.getMemoryModel().setSamplingTime(
				monitorMain.getSamplingTime());
		monitorMain.getNetworkInterfaceModel().setSamplingTime(
				monitorMain.getSamplingTime());
		monitorMain.getPhysicalDiskModel().setSamplingTime(
				monitorMain.getSamplingTime());
		monitorMain.getProcessModel().setSamplingTime(
				monitorMain.getSamplingTime());
		monitorMain.getProcessorModel().setSamplingTime(
				monitorMain.getSamplingTime());

		return monitorMain;
	}
}
