package com.eactive.eai.common.worker;

import java.lang.Thread.State;

import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;

import com.eactive.eai.common.jms.JmsServiceLocator;
import com.eactive.eai.common.util.ContainerUtil;

public class JMSListenerAction extends ActionSupport implements MessageListener {
	private String topicConFactory;
	private String topicName;
	private int timeout;

	private TopicConnectionFactory tconFactory;
	private TopicConnection tcon;
	private TopicSession tsession;
	private TopicSubscriber tsubscriber;
	private Topic topic;
	private Slot slot;

	public JMSListenerAction(String topicConFactory, String topicName, int timeout) {
		this.topicConFactory = topicConFactory;
		this.topicName = topicName;
		this.timeout = timeout;
	}

	public void doStart(Slot slot) throws ActionException {
		if (ContainerUtil.get() == ContainerUtil.WEBSPHERE) {
			doStartForWebSphere(slot);
		} else if (ContainerUtil.get() == ContainerUtil.WEBLOGIC) {
			doStartForWeblogic(slot);
		} else {
			doStartForWeblogic(slot);
		}
	}

	public void doStartForWeblogic(Slot slot) throws ActionException {
		this.slot = slot;
		try {
			JmsServiceLocator slocator = JmsServiceLocator.getInstance();
			tconFactory = (TopicConnectionFactory) slocator.getTopicConnectionFactory(this.topicConFactory);
			tcon = tconFactory.createTopicConnection();
			tsession = tcon.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
			topic = (Topic) slocator.getTopic(this.topicName);
			tsubscriber = tsession.createSubscriber(topic, "JMSCorrelationID = '" + id + "'", true);
			tsubscriber.setMessageListener(this);
			tcon.start();
			this.ready = true;
		} catch (Exception e) {
			this.ready = false;
			this.doEnd();
			throw new ActionException("ResponseTopic에 응답메시지를 수신하기 위한 JMSListener를 초기화 하지 못했습니다.");
		}
	}

	public void doStartForWebSphere(Slot slot) throws ActionException {
		this.slot = slot;
		int retryCount = 0;
		try {
			if (logger.isWarn())
				logger.warn("start correlationID[" + id + "]");
			JmsServiceLocator slocator = JmsServiceLocator.getInstance();
			tconFactory = (TopicConnectionFactory) slocator.getTopicConnectionFactory(this.topicConFactory);
			if (tconFactory == null)
				throw new Exception("tconFactory not found - " + this.topicConFactory);
			while (retryCount < 3) {
				try {
					tcon = tconFactory.createTopicConnection();
				} catch (Exception ex) {
					retryCount++;
					if (retryCount < 3) {
//	    				if(logger.isWarn()) 
						logger.error("correlationID[" + id + "] retry count=" + retryCount);
						continue;
					}
					throw ex;
				}
				if (tcon != null)
					break;
			}

			tsession = tcon.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
			topic = (Topic) slocator.getTopic(this.topicName);
			tsubscriber = tsession.createSubscriber(topic, "JMSCorrelationID = '" + id + "'", true);
			tcon.start();
			Thread receiverThread = new Thread(new Runnable() {
				@Override
				public void run() {
					if (logger.isWarn())
						logger.warn("run correlationID[" + id + "]");
					long startTime = System.currentTimeMillis();
					Message msg = null;
					if (logger.isInfo())
						logger.info("executing. - " + id);
					try {
						msg = tsubscriber.receive(timeout + (10 * 1000L));
						if (logger.isInfoEnabled())
							logger.info("receive JMSCorrelationID=" + id + ", message=" + msg);

						if (logger.isWarn())
							logger.warn("receive correlationID[" + id + "]");

						if (msg instanceof ObjectMessage) {
							ObjectMessage omsg = (ObjectMessage) msg;
							Object value = omsg.getObject();
							slot.put(value);
						}
						if (logger.isWarn())
							logger.warn("slot.put correlationID[" + id + "]");
					} catch (Exception e) {
						logger.error("JMSListenerAction Error", e);
					}
					long endTime = System.currentTimeMillis();
					if (logger.isInfo())
						logger.info(id + " >> ELAPSE TIME : " + (endTime - startTime) / 1000.);
				}
			});
			receiverThread.setName("JMSTopicReceiver");
			receiverThread.setPriority(Thread.MAX_PRIORITY);
			receiverThread.start();

			int i = 0;
			while (true) {
				State s = receiverThread.getState();
				if (s == Thread.State.TIMED_WAITING || i > 100) {
					if (i > 100) {
						logger.error("JMSListenerAction] receiverThread state = " + s.toString() + ",count=" + i);
					} else if (100 >= i && i > 0) {
						logger.info("JMSListenerAction] receiverThread state = " + s.toString() + ",count=" + i);
					}
					break;
				}
				Thread.sleep(10L);
				i++;
			}

			this.ready = true;
		} catch (Exception e) {
			this.ready = false;
			this.doEnd();
			logger.error("ResponseTopic에 응답메시지를 수신하기 위한 JMSListener를 초기화 하지 못했습니다.topicConFactory="
					+ this.topicConFactory + ", topic=" + topicName + ", " + e.getMessage(), e);
			throw new ActionException("ResponseTopic에 응답메시지를 수신하기 위한 JMSListener를 초기화 하지 못했습니다.");
		}
	}

	public void doEnd() {
		try {
			if (tsubscriber != null)
				tsubscriber.close();
		} catch (Exception e) {
		}
		try {
			if (tsession != null)
				tsession.close();
		} catch (Exception e) {
		}
		try {
			if (tcon != null)
				tcon.close();
		} catch (Exception e) {
		}
	}

	public void onMessage(Message msg) {
		long startTime = System.currentTimeMillis();
		if (logger.isInfo())
			logger.info("executing. - " + id);

		try {
			if (msg instanceof ObjectMessage) {
				ObjectMessage omsg = (ObjectMessage) msg;
				Object value = omsg.getObject();
				this.slot.put(value);
			}
		} catch (Exception e) {
			logger.error("JMSListenerAction Error - " + e.getMessage());
		}
		long endTime = System.currentTimeMillis();
		if (logger.isInfo())
			logger.info(id + " >> ELAPSE TIME : " + (endTime - startTime) / 1000.);
	}
}
