package com.eactive.eai.adapter;

import java.nio.charset.Charset;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang3.StringUtils;

import com.eactive.eai.adapter.http.HttpStatusException;
import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.message.MessageType;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.state.ElinkState;
import com.eactive.eai.common.state.ElinkStateException;
import com.eactive.eai.common.state.ElinkStateManager;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.inbound.processor.Processor;
import com.eactive.eai.inbound.processor.ProcessorFactory;

public class RequestDispatcher {
	static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);

	private static boolean isTASEnabledEAIServer = true;
	static {
		EAIServerManager eaiServerManager = EAIServerManager.getInstance();
		isTASEnabledEAIServer = eaiServerManager.isTASEnabledEAIServer();
	}

	private static ConcurrentHashMap<String, RequestDispatcher> dispatchers = new ConcurrentHashMap<>();

	private String adapterGroupName;
	private Processor processor;
	
	private RequestDispatcher(String adapterGroupName) {
		this.adapterGroupName = adapterGroupName;
		processor = ProcessorFactory.newInstance();
	}
	
	public static RequestDispatcher getRequestDispatcher(String adapterGroupName) {
		return dispatchers.computeIfAbsent(adapterGroupName, k -> new RequestDispatcher(adapterGroupName));
	}

	public Object handle(String adapterName, Object message, Properties prop) throws Exception {
		AdapterManager manager = AdapterManager.getInstance();

		String inAdapterGroupName = this.adapterGroupName;
		String actionClass = "";
		String adptrMsgPtrnCd = "";
		String messageType = MessageType.ASC;

		AdapterGroupVO group = manager.getAdapterGroupVO(inAdapterGroupName);
		if (group == null) {
			String code = "RECEAIAAC042";
			String[] msgArgs = new String[2];
			msgArgs[0] = adapterGroupName;
			msgArgs[1] = adapterName;
			String errText = ExceptionUtil.make(code, msgArgs);
			if (logger.isError()) {
				logger.error(errText);
			}
			throw new Exception(errText);
		}

		AdapterVO adapter = group.getAdapterVO(adapterName);
		if (adapter == null) {
			String code = "RECEAIAAC022";
			String[] msgArgs = { adapterGroupName, adapterName, group.toString() };
			String errText = ExceptionUtil.make(code, msgArgs);
			if (logger.isError()) {
				logger.error(errText);
			}
			throw new Exception(errText);
		}

		if (prop == null) {
			prop = new Properties();
		}

		actionClass = group.getRefClass();
		adptrMsgPtrnCd = group.getAdptrMsgPtrnCd();
		messageType = group.getMessageType();
		try {
			prop.put(Processor.ADAPTER_GROUP_NAME, inAdapterGroupName);
			prop.put(Processor.ADAPTER_NAME, adapterName);
			prop.put(Processor.STD_MESSAGE, adptrMsgPtrnCd);
			prop.put(Processor.REQUEST_ACTION, actionClass);
			prop.put(Processor.MESSAGE_TYPE, messageType);

			// set Inbound AdapterGroup charset
			prop.setProperty(com.eactive.eai.adapter.Keys.CHARSET_KEY_IN,
					StringUtils.defaultIfBlank(group.getMessageEncode(), Charset.defaultCharset().name()));
		} catch (Exception e) {
			throw new Exception(ExceptionUtil.getErrorCode(e, "RECEAIAAC024"));
		}

		Object obj = null;
		
		// Check Elink lifecycle is STARTED
		// otherwise reject  this request
		if(ElinkStateManager.getInstance().getState() != ElinkState.STARTED) {
			logger.error("Elink STATE FAIL - " + ElinkStateManager.getInstance().getState());
			throw new ElinkStateException("Elink STATE FAIL - " + ElinkStateManager.getInstance().getState());
		}

		try {
			ElinkStateManager.getInstance().startRequest();
			group.increase();
			adapter.incrementRequestCount();
			obj = processor.execute(message, prop);
			group.increaseSuccess();
		} catch (HttpStatusException e) {
			group.increaseError();
			throw e;
		} catch (Exception e) {
			group.increaseError();
			throw new Exception(ExceptionUtil.getErrorCode(e, "RECEAIAAC025"));
		} finally {
			group.decrease();
			adapter.decrementRequestCount();
			ElinkStateManager.getInstance().completeRequest();
		}

		if (obj != null) {
			return obj;
		}
		else {
			if (message instanceof byte[]) {
				return new byte[0];
			} else if (message instanceof String) {
				return "";
			} else {
				return new Object();
			}
		}
	}
}
