package de.hottis.measurementCollector;

import java.io.Serializable;
import java.util.Properties;

import javax.jms.Connection;
import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import javax.jms.Topic;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class JmsTopic<T extends Serializable> implements MyQueue<T> {
	static final String JMS_PARSED_DATA_TOPIC = "jms.parseddata.topic";
	static final String JMS_CLIENTID_PROP = "jms.clientid";
	static final String JMS_BROKER ="jms.broker";

	static enum Mode { CONSUMER, PRODUCER, CONSUMER_PRODUCER };
	
	final protected Logger logger = LogManager.getRootLogger();

	private String clientId;
	private Properties config;
	private Connection connection;
	private Session session;
	private Topic topic;
	private MessageProducer producer;
	private MessageConsumer consumer;
	private String topicTxt;
	private String broker;
	private Mode mode;

	public JmsTopic(Properties config, Mode mode) {
		this.config = config;
		clientId = this.config.getProperty(JMS_CLIENTID_PROP);
		topicTxt = this.config.getProperty(JMS_PARSED_DATA_TOPIC);
		broker = this.config.getProperty(JMS_BROKER);
		this.mode = mode;
	}


	public void init() throws MeasurementCollectorException {
		try {
			ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(broker);
			connectionFactory.setTrustAllPackages(true);
			logger.debug("connectionFactory: " + connectionFactory);
			connection = connectionFactory.createConnection();
			connection.setClientID(clientId);
			connection.start();
			logger.debug("connection: " + connection);
			session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
			logger.debug("session: " + session);
			topic = session.createTopic(topicTxt);
			logger.debug("topic: " + topic);
			
			if ((mode == Mode.PRODUCER) || (mode == Mode.CONSUMER_PRODUCER)) {
				producer = session.createProducer(topic);
				producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
				logger.debug("producer: " + producer);
			} else {
				producer = null;
			}
			
			if ((mode == Mode.CONSUMER) || (mode == Mode.CONSUMER_PRODUCER)) {
				consumer = session.createDurableSubscriber(topic, "DatabaseEngine");
				logger.debug("consumer: " + consumer);
			} else {
				consumer = null;
			}
			
		} catch (JMSException e) {
			logger.error("JMSException in AJmsQueue.init", e); 
			throw new MeasurementCollectorException("JMSException in AJmsTopic.init", e);
		}
	}

	public T dequeue() throws MeasurementCollectorException {
		if (consumer == null) {
			throw new MeasurementCollectorException("This is no consumer");
		}
		try {
			ObjectMessage message = (ObjectMessage) consumer.receiveNoWait();
			T item;
			if (message != null) {
				@SuppressWarnings("unchecked")
				T t = (T) message.getObject();
				item = t;
				logger.debug("message dequeued");
			} else {
				item = null;
			}
			return item;
		} catch (JMSException e) {
			logger.error("JMSException in JmsTopic.dequeue", e);
			logger.error("Calling init");
			init();
			throw new MeasurementCollectorException("JMSException in JmsTopic.dequeue", e);
		}
	}

	public void enqueue(T item) throws MeasurementCollectorException {
		if (producer == null) {
			throw new MeasurementCollectorException("This is no producer");
		}
		try {
			ObjectMessage message = session.createObjectMessage();
			message.setObject(item);
			producer.send(message);
			logger.debug("message enqueued");
		} catch (JMSException e) {
			logger.error("JMSException in JmsTopic.enqueue", e);
			logger.error("Calling init");
			init();
			throw new MeasurementCollectorException("JMSException in JmsTopic.enqueue", e);
		}
	}

}
