package com.eactive.eai.adapter.amq;

import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.jms.pool.PooledConnectionFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;

import com.eactive.eai.adapter.AdapterGroupVO;
import com.eactive.eai.adapter.AdapterPropManager;
import com.eactive.eai.adapter.AdapterVO;
import com.eactive.eai.agent.command.CommandException;
import com.eactive.eai.common.util.Logger;

public class AMQAdapterManager {
	public static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);
	private static AMQAdapterManager instance = new AMQAdapterManager();

	// adapterName - Outbound Queue PooledConnectionFactory
	private ConcurrentHashMap<String, PooledConnectionFactory> adapterConFacMap = new ConcurrentHashMap<>();

	// adapterName - Inbound Queue Listener
	private ConcurrentHashMap<String, AMQReceiverAdapter> receiverAdapterMap = new ConcurrentHashMap<>();

	public static AMQAdapterManager getInstance() {
		return instance;
	}

	public PooledConnectionFactory getOutboundPooledConnectionFactory(String adapterName) {
		return adapterConFacMap.get(adapterName);
	}

	public void start(AdapterVO adapterVO) throws Exception {
		if (logger.isDebug()) {
			logger.debug("= AMQAdapterManager.start...");
		}

		AdapterGroupVO adapterGroupVO = adapterVO.getAdapterGroupVO();
		AdapterPropManager propManager = AdapterPropManager.getInstance();
		Properties queueProp = propManager.getProperties(adapterVO.getPropGroupName());
		String brokerUrl = queueProp.getProperty(AMQAdapterConstants.PROP_BROKER_URL);
		if (StringUtils.isBlank(brokerUrl)) {
			throw new CommandException(AMQAdapterConstants.PROP_BROKER_URL + " is a required.");
		}

		if (StringUtils.equals(adapterGroupVO.getGubun(), "I")) {
			AMQReceiverAdapter receiverAdapter = new AMQReceiverAdapter(adapterVO);
			receiverAdapter.start();
			receiverAdapterMap.put(adapterVO.getName(), receiverAdapter);

			// Sync 거래일 경우 응답 Queue 연결
			String replyQueue = queueProp.getProperty(AMQAdapterConstants.PROP_REPLY_QUEUE_NAME);
			if (StringUtils.isNotBlank(replyQueue)) {
				String userName = queueProp.getProperty(AMQAdapterConstants.PROP_USER_NAME);
				String password = queueProp.getProperty(AMQAdapterConstants.PROP_PASSWORD);
				String maxConnections = queueProp.getProperty(AMQAdapterConstants.PROP_REPLY_POOL_MAX_CONNECTIONS);
				String idleTimeout = queueProp.getProperty(AMQAdapterConstants.PROP_REPLY_POOL_IDLE_TIMEOUT);
				String expiryTimeout = queueProp.getProperty(AMQAdapterConstants.PROP_REPLY_POOL_EXPIRY_TIMEOUT);
				adapterConFacMap.put(adapterVO.getName(), getPooledConnectionFactory(brokerUrl, userName, password,
						maxConnections, idleTimeout, expiryTimeout));
			}
		} else {
			String userName = queueProp.getProperty(AMQAdapterConstants.PROP_USER_NAME);
			String password = queueProp.getProperty(AMQAdapterConstants.PROP_PASSWORD);
			String maxConnections = queueProp.getProperty(AMQAdapterConstants.PROP_POOL_MAX_CONNECTIONS);
			String idleTimeout = queueProp.getProperty(AMQAdapterConstants.PROP_POOL_IDLE_TIMEOUT);
			String expiryTimeout = queueProp.getProperty(AMQAdapterConstants.PROP_POOL_EXPIRY_TIMEOUT);
			adapterConFacMap.put(adapterVO.getName(), getPooledConnectionFactory(brokerUrl, userName, password,
					maxConnections, idleTimeout, expiryTimeout));
		}
	}

	public void stop(AdapterVO adapterVO) throws Exception {
		AdapterGroupVO adapterGroupVO = adapterVO.getAdapterGroupVO();

		if (StringUtils.equals(adapterGroupVO.getGubun(), "I")) {
			AMQReceiverAdapter receiverAdapter = receiverAdapterMap.get(adapterVO.getName());
			if (receiverAdapter != null) {
				receiverAdapterMap.remove(adapterVO.getName());
				receiverAdapter.stop();
			}

			// Sync 거래일 경우 응답 Queue 연결 해제
			PooledConnectionFactory connectionFactory = adapterConFacMap.get(adapterVO.getName());
			if (connectionFactory != null) {
				adapterConFacMap.remove(adapterVO.getName());
				connectionFactory.clear();
			}
		} else {
			PooledConnectionFactory connectionFactory = adapterConFacMap.get(adapterVO.getName());
			if (connectionFactory != null) {
				adapterConFacMap.remove(adapterVO.getName());
				connectionFactory.clear();
			}
		}

		if (logger.isDebug()) {
			logger.debug("= AMQAdapterManager.stoped...");
		}
	}

	private PooledConnectionFactory getPooledConnectionFactory(String brokerUrl, String userName, String password,
			String maxConnections, String idleTimeout, String expiryTimeout) throws Exception {
		// Queue Connection pool 생성
		ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(brokerUrl);
		if (StringUtils.isNotBlank(userName)) {
			activeMQConnectionFactory.setUserName(userName);
			activeMQConnectionFactory.setPassword(StringUtils.defaultString(password));
		}
		activeMQConnectionFactory.setTrustAllPackages(true);

		PooledConnectionFactory connectionFactory = new PooledConnectionFactory();
		connectionFactory.setConnectionFactory(activeMQConnectionFactory);
		connectionFactory
				.setMaxConnections(NumberUtils.toInt(maxConnections, AMQAdapterConstants.DEFAULT_POOL_MAX_CONNECTIONS));
		if (NumberUtils.isParsable(idleTimeout)) {
			connectionFactory.setIdleTimeout(NumberUtils.toInt(idleTimeout) * 1000);
		}
		if (NumberUtils.isParsable(expiryTimeout)) {
			connectionFactory.setExpiryTimeout(NumberUtils.toLong(expiryTimeout) * 1000);
		}

		return connectionFactory;
	}
}
