package com.eactive.eai.common.inflow;

import java.lang.reflect.Method;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;

import com.eactive.eai.common.message.EAIMessage;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.util.ApplicationContextProvider;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.message.service.InterfaceMapper;
import com.ext.eai.common.stdmessage.STDMessageKeys;

public class InflowControlUtil {
	private InflowControlUtil() {
	}

	static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);

	private static volatile AbstractInflowControlManager cachedInflowControlManager;
	private static volatile Bucket                       cachedBucket;

	/**
	 * INFLOW.properties의 inflow.control.bucket.className 설정에 따라
	 * 활성화된 InflowControlManager 구현체를 반환한다.
	 *
	 * getBean(InflowControlManager.class) 대신 설정된 구체 타입으로 조회하므로
	 * InflowControlManager와 DualInflowControlManager가 모두 Bean으로 등록된
	 * 환경에서도 NoUniqueBeanDefinitionException 없이 올바른 인스턴스를 반환한다.
	 *
	 * 최초 1회만 조회하고 이후에는 캐시된 인스턴스를 반환한다.
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static AbstractInflowControlManager getInflowControlManager() {
		if (cachedInflowControlManager == null) {
			synchronized (InflowControlUtil.class) {
				if (cachedInflowControlManager == null) {
					Properties inFlowProp = PropManager.getInstance().getProperties("INFLOW");
					String className = inFlowProp.getProperty("inflow.control.bucket.className");
					if (StringUtils.isBlank(className)
							|| StringUtils.equals(className, "com.eactive.eai.common.inflow.InflowControlManager")) {
						cachedInflowControlManager = InflowControlManager.getInstance();
					} else {
						try {
							Class clazz = Class.forName(className);
							cachedInflowControlManager = (AbstractInflowControlManager) ApplicationContextProvider.getContext().getBean(clazz);
						} catch (Exception e) {
							logger.error("getInflowControlManager error class= {}", className);
							logger.error(e.getMessage());
						}
					}
				}
			}
		}
		return cachedInflowControlManager;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static Bucket getBucket() {
		if (cachedBucket == null) {
			synchronized (InflowControlUtil.class) {
				if (cachedBucket == null) {
					Properties inFlowProp = PropManager.getInstance().getProperties("INFLOW");
					String className = inFlowProp.getProperty("inflow.control.bucket.className");
					if (StringUtils.isBlank(className)
							|| StringUtils.equals(className, "com.eactive.eai.common.inflow.InflowControlManager")) {
						cachedBucket = InflowControlManager.getBucket();
					} else {
						try {
							Class clazz = Class.forName(className);
							Method method = clazz.getMethod("getBucket", (Class<?>[]) null);
							cachedBucket = (Bucket) method.invoke(null, (Object[]) null);
						} catch (Exception e) {
							logger.error("Method call error class= {}, method= getBucket", className);
							logger.error(e.getMessage());
						}
					}
				}
			}
		}
		return cachedBucket;
	}

	public static boolean isTargetOfInflowControl(EAIServerManager eaiServerManager, EAIMessage eaiMessage) {
		Properties inFlowProp = PropManager.getInstance().getProperties("INFLOW");
		String controlInflow = inFlowProp.getProperty("inflow.control.yn", "N");

		if (!"Y".equalsIgnoreCase(controlInflow)) {
			return false;
		}
		
		try {
			InterfaceMapper mapper = eaiMessage.getMapper();
			String returnType = mapper.getSendRecvDivision(eaiMessage.getStandardMessage()); // S|R

			if (STDMessageKeys.SEND_RECV_CD_SEND.equals(returnType)) {
				return Boolean.valueOf(true);
			}

			return Boolean.valueOf(false);
		} catch (Exception e) {
			logger.error("isTargetOfInflowControl call error", e.getMessage());
		}

		return false;
	}
}
