package com.eactive.eai.flowcontroller;

import com.eactive.eai.adapter.AdapterGroupVO;
import com.eactive.eai.adapter.AdapterManager;
import com.eactive.eai.adapter.AdapterPropManager;
import com.eactive.eai.adapter.AdapterVO;
import com.eactive.eai.common.EAIKeys;
import com.eactive.eai.common.EAITable;
import com.eactive.eai.common.exception.ExceptionHandler;
import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.message.EAIMessage;
import com.eactive.eai.common.message.EAIMessageKeys;
import com.eactive.eai.common.routing.IFRouter;
import com.eactive.eai.common.routing.Process;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.MessageUtil;
import com.eactive.eai.control.LogSender;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.service.InterfaceMapper;
import com.eactive.eai.transformer.function.util.CodeConversion;
import com.ext.eai.common.stdmessage.STDMessageKeys;

public class StartFCProcess extends Process {
	public String adptrMsgPtrnCd; // migration - boolean 값이 아니라 [S, N, C] 값을 가짐

	public java.lang.String adapterGroupName;

	public int logPssSeq;

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

	public java.util.Properties callProp;

	public EAIMessage resEaiMsg;

	public com.eactive.eai.common.message.EAIMessage reqEaiMsg;

	static Logger esbLogger = Logger.getLogger(Logger.LOGGER_ESBFW);
	private int svrLogLevel;
	private static ThreadLocal local = new ThreadLocal();

	static final long serialVersionUID = 1L;

	String guidLogPrefix = "";

	public EAIMessage clientReturn() {
		if (svrLogLevel >= 1) {
			try {
				long msgSndTm = System.currentTimeMillis();

				Long threadData = (Long) local.get();
				long processTm = msgSndTm - threadData.longValue();
				if (esbLogger.isInfo())
					esbLogger.info(
							guidLogPrefix + " End... - 경과시간 : " + processTm + "(ms) - EAI Server Log Level is INFO");
			} catch (Exception e) {
				logger.error("clientReturn", e);
			}
		}
		return resEaiMsg;
	}

	public void callService(com.eactive.eai.common.message.EAIMessage reqEaiMsg, java.util.Properties callProp) {
		this.reqEaiMsg = reqEaiMsg;
		this.callProp = callProp;

		if (this.reqEaiMsg == null)
			return;

		svrLogLevel = this.reqEaiMsg.getSvrLogLvl();

//        guidLogPrefix =  guidLogPrefix + "GUID["+reqEaiMsg.getKbMsg().getKBHeader().getGuIdNo()+"]";
		guidLogPrefix = guidLogPrefix + "GUID[" + getGuid(reqEaiMsg) + "]";

		if (svrLogLevel >= 1) {
			try {
				long msgRcvTm = System.currentTimeMillis();
				local.set(new Long(msgRcvTm));

				if (esbLogger.isInfo())
					esbLogger.info(guidLogPrefix + " started... - EAI Server Log Level is INFO");
			} catch (Exception e) {
				logger.error("callService error", e);
			}
		}

		try {
			flow();
		} catch (Exception e) {
			// 에러처리
			printExceptionMessage(e);
			// ASYNC
			if (isSourceAsync()) {
				// Async-로그
				logSenderCtrlSend();
				// ExcetpionHandler 호출
				callExceptionHandler();
			}
			return;

		}
	}

	public void flow() throws Exception {
		// isRealCall
		if (!isRealCall()) {
			return;
		}
		// 초기화
		init();
		// Start Target Adapter
		startTargetAdapter();
		// Outbound 프로세스 호출
		ifRouterProcess();
		// GUID설정
		setGUID();
		// ASYNC-SYNC모델
		if (checkServiceMsgSize()) {
			// ServiceMessage설정
			setCurrentService();
			// 응답메시지전송
			ifRouterProcessResponse();
		}
	}

	public void ifRouterProcess() throws Exception {
		try {
			this.resEaiMsg = IFRouter.process(this.reqEaiMsg, this.callProp);
		} catch (Exception e) {
			String[] msgArgs = new String[1];
			msgArgs[0] = this.reqEaiMsg.getEAISvcCd();
			String rspErrorCode = "RECEAIFBF001";
			String rspErrorMsg = ExceptionUtil.make(e, rspErrorCode, msgArgs);
			if (logger.isError())
				logger.error(guidLogPrefix + "" + rspErrorMsg);
//			this.resEaiMsg.setRspErrCd(rspErrorCode);
//			this.resEaiMsg.setRspErrMsg(rspErrorMsg);
			this.resEaiMsg.setRspErr(rspErrorCode,rspErrorMsg);
			throw new Exception(rspErrorCode);
		}

		// ----------------------------------------------------
		// 기동시스템이 Async 거래의 OUtbound에서 오류가 발생할 경우
		// ExceptionHandler를 통해 응답메시지를 전송한다.
		// ----------------------------------------------------
		if (EAIMessageKeys.ASYNC_SVC.equals(this.reqEaiMsg.getSvcTsmtUsgTp())) {
			if (!MessageUtil.checkRspErrCd(this.resEaiMsg.getRspErrCd())) {
				try {
//                    AdapterManager adapterManager = AdapterManager.getInstance();
//                    AdapterGroupVO inAdptGrpVO = adapterManager.getAdapterGroupVO(this.reqEaiMsg.getSngSysItfTp());
//                    String inAdapterMsgType = inAdptGrpVO.getMessageType();
////                    Object[] bizObjs  = this.reqEaiMsg.getBizMsg();
//                    Object[] bizObjs  = this.reqEaiMsg.getExtMsg().getBizData();
//                    if(EAITable.EBCDIC_TYPE.equals(inAdapterMsgType)) {                                        
//                        if(bizObjs != null && bizObjs[0] instanceof byte[]) {
//                            bizObjs[0] = CodeConversion.meToMixedAsc((byte[])bizObjs[0]);
//                        }                        
//                    }
////                    this.resEaiMsg.setBizMsg(bizObjs);
//                    this.resEaiMsg.getExtMsg().setBizData(bizObjs);

					String bizData = this.reqEaiMsg.getStandardMessage().getBizData();
					String inboundCharset = callProp.getProperty(com.eactive.eai.adapter.Keys.CHARSET_KEY_IN);
					this.resEaiMsg.getStandardMessage().setBizData(bizData, inboundCharset);
					ExceptionHandler.handle(this.resEaiMsg);
					// ----------------------------------------------------------

				} catch (Exception e) {
					if (logger.isError())
						logger.error(guidLogPrefix + "ExceptionHandler Call Error :" + e.getMessage());
				}
			}
		}
	}

	public void ifRouterProcessResponse() throws Exception {
		try {
			this.resEaiMsg = IFRouter.process(this.resEaiMsg, this.callProp);
		} catch (Exception e) {
			String[] msgArgs = new String[1];
			msgArgs[0] = this.reqEaiMsg.getEAISvcCd();
			String rspErrorCode = "RECEAIFBF100";
			String orgErrorCode = ExceptionUtil.getErrorCode(e, rspErrorCode);
			String rspErrorMsg = ExceptionUtil.make(rspErrorCode, orgErrorCode, msgArgs);
			if (logger.isError())
				logger.error(guidLogPrefix + "" + rspErrorMsg);
//			this.resEaiMsg.setRspErrCd(rspErrorCode);
//			this.resEaiMsg.setRspErrMsg(rspErrorMsg);
			this.resEaiMsg.setRspErr(rspErrorCode,rspErrorMsg);
			// throw new RuntimeException(rspErrorCode);
		}
	}

	public void logSenderCtrlSend() {
		String returnType = getReturnType(reqEaiMsg);
		if (STDMessageKeys.SEND_RECV_CD_RECV.equals(returnType)) {
			this.logPssSeq = 400;
		} else {
			this.logPssSeq = 200;
		}

		try {
			LogSender.send(this.logPssSeq, this.resEaiMsg, null);
		} catch (Exception e) {
			if (logger.isError())
				logger.error(guidLogPrefix + "AA Exception Logging Error :" + e.getMessage());
		}
	}

	public boolean checkServiceMsgSize() {
		// Outbound Error일 경우
		if (MessageUtil.checkRspErrCd(this.resEaiMsg.getRspErrCd()) && reqEaiMsg.getSvcMsgs().size() > 1) {
			return true;
		} else {
			return false;
		}
	}

	public void setCurrentService() throws Exception {
		if (logger.isDebug())
			logger.debug(guidLogPrefix + "ASYNC-SYNC CALLED");
		// ---------------------------------------------------------------
		// AS의 경우 다음 서비스메시지(AS 응답)에 키관리메시지내용을 복사한다.
		// ---------------------------------------------------------------
		String keyMgtMsgVl = resEaiMsg.getCurrentSvcMsg().getKeyMgtMsgVl();
		if (logger.isDebug())
			logger.debug(guidLogPrefix + "AS 응답 keyMgtMsgVl[" + keyMgtMsgVl + "]");
		resEaiMsg.setSvcPssSeq(resEaiMsg.getSvcPssSeq() + 1);
		resEaiMsg.getCurrentSvcMsg().setKeyMgtMsgVl(keyMgtMsgVl);
		// ---------------------------------------------------------------

		AdapterManager adapterManager = AdapterManager.getInstance();
		AdapterGroupVO adptGrpVO = adapterManager.getAdapterGroupVO(this.adapterGroupName);
		this.adptrMsgPtrnCd = adptGrpVO.getAdptrMsgPtrnCd(); // migration - boolean 값이 아니라 [S, N, C] 값을 가짐

		// SA Type의 요청 Outbound가 비표준일 경우
		// KESA Header의 값을 바꾼다. (0200 -> TR_RES)

	}

	public boolean isOutboundCall() {
		return true;
	}

	public void init() throws Exception {
		InterfaceMapper mapper = this.reqEaiMsg.getMapper();
		StandardMessage standardMessage = this.reqEaiMsg.getStandardMessage();
		String guid = mapper.getGuid(standardMessage);
		String guidseq = mapper.getGuidSeq(standardMessage);

		if (logger.isDebug())
			logger.debug(guidLogPrefix + " REQ Current GUID [" + guid + "][" + guidseq + "]");
		mapper.nextGuidSeq(standardMessage);
		guidseq = mapper.getGuidSeq(standardMessage);
		if (logger.isDebug())
			logger.debug(guidLogPrefix + " REQ ADD PATHSEQ GUID [" + guid + "][" + guidseq + "]");

		this.resEaiMsg = this.reqEaiMsg;
		this.adapterGroupName = reqEaiMsg.getCurrentSvcMsg().getPsvSysItfTp();
	}

	public void printExceptionMessage(Exception e) {
		// Exception e = this.context.getExceptionInfo().getException();
		if (logger.isError())
			logger.error(guidLogPrefix + "ExceptionPath : " + e.getMessage());
	}

	public boolean isSourceAsync() {
		if (EAIMessageKeys.ASYNC_SVC.equals(this.reqEaiMsg.getSvcTsmtUsgTp())) {
			return true;
		} else {
			return false;
		}
	}

	public void callExceptionHandler() {
		try {
			AdapterManager adapterManager = AdapterManager.getInstance();
			AdapterGroupVO inAdptGrpVO = adapterManager.getAdapterGroupVO(this.reqEaiMsg.getSngSysItfTp());
			String inAdapterMsgType = inAdptGrpVO.getMessageType();
			if (EAITable.EBCDIC_TYPE.equals(inAdapterMsgType)) {
////                Object[] bizObjs  = this.reqEaiMsg.getBizMsg();                
//                Object[] bizObjs  = this.reqEaiMsg.getExtMsg().getBizData();                
//                if(bizObjs != null && bizObjs[0] instanceof byte[]) {
//                    bizObjs[0] = CodeConversion.meToMixedAsc((byte[])bizObjs[0]);
//                }
////                this.reqEaiMsg.setBizMsg(bizObjs);                
//                this.reqEaiMsg.getExtMsg().setBizData(bizObjs);   
				String bizData = this.reqEaiMsg.getStandardMessage().getBizData();
				byte[] asc = CodeConversion.meToMixedAsc(bizData.getBytes());
				try {
					String inboundCharset = callProp.getProperty(com.eactive.eai.adapter.Keys.CHARSET_KEY_IN);
					this.reqEaiMsg.getStandardMessage().setBizData(new String(asc), inboundCharset);
				} catch (Exception e) {
					logger.error("setBizData error", e);
				}
			}
			// ----------------------------------------------------------
			ExceptionHandler.handle(this.reqEaiMsg);
		} catch (Exception e) {
			if (logger.isError())
				logger.error(guidLogPrefix + "ExceptionHandler Call Error :" + e.getMessage());
		}
	}

	public boolean isRealCall() {
		if (this.callProp != null) {
			String mode = this.callProp.getProperty(EAIKeys.CALL_MODE_KEY);
			if (mode != null && EAIKeys.CALL_MODE_WARMUP.equals(mode)) {
				logger.warn(guidLogPrefix + "Warming Up Called");
				return false;
			} else {
				return true;
			}
		} else {
			return true;
		}
	}

	public void setGUID() throws Exception {
		InterfaceMapper mapper = this.resEaiMsg.getMapper();
		StandardMessage standardMessage = this.resEaiMsg.getStandardMessage();
		String guid = mapper.getGuid(standardMessage);
		String guidseq = mapper.getGuidSeq(standardMessage);

		if (logger.isDebug())
			logger.debug(guidLogPrefix + " REQ Current GUID [" + guid + "][" + guidseq + "]");
		mapper.nextGuidSeq(standardMessage);
		guidseq = mapper.getGuidSeq(standardMessage);
		if (logger.isDebug())
			logger.debug(guidLogPrefix + " REQ ADD PATHSEQ GUID [" + guid + "][" + guidseq + "]");

	}

	public void startTargetAdapter() throws Exception {
		try {
			String srcAdapterGroupName = this.reqEaiMsg.getSngSysItfTp();

			AdapterManager adapterManager = AdapterManager.getInstance();
			AdapterGroupVO srcAdapterGroup = adapterManager.getAdapterGroupVO(srcAdapterGroupName);

			String[] srcAdapterNames = srcAdapterGroup.getAdapterNames();

			if (srcAdapterNames != null && srcAdapterNames.length > 0) {
				AdapterVO srcAdapter = srcAdapterGroup.getAdapterVO(srcAdapterNames[0]);
				String adapterPropGroupName = srcAdapter.getPropGroupName();
				// PropManager manager = PropManager.getInstance();
				AdapterPropManager manager = AdapterPropManager.getInstance();

				String adptrPropVal = manager.getProperty(adapterPropGroupName, "inisafe.related.adapter.groups");
				if (logger.isDebug())
					logger.debug(guidLogPrefix + "" + adapterPropGroupName + " : inisafe.related.adapter.groups -> "
							+ adptrPropVal);

				if (adptrPropVal != null && adptrPropVal.trim().length() > 0) {
					String[] adapter_list = adptrPropVal.split(",");
					for (int p = 0; p < adapter_list.length; p++) {
						String[] adapterNames = adapterManager.getAdapterGroupVO(adapter_list[p]).getAdapterNames();
						for (int i = 0; i < adapterNames.length; i++) {
							if (logger.isDebug())
								logger.debug(guidLogPrefix + "startTargetAdapter :" + adapter_list[p] + " "
										+ adapterNames[i]);
							try {
								adapterManager.getAdapterGroupVO(adapter_list[p]).getAdapterVO(adapterNames[i]).start();
							} catch (Exception ex) {
								if (logger.isWarn()) {
									logger.warn(guidLogPrefix + "startTargetAdapter Fail :" + adapter_list[p] + " "
											+ adapterNames[i], ex);
								}
							}
						}
					}
				} else {
					if (logger.isDebug())
						logger.debug(
								guidLogPrefix + "inisafe.related.adapter.groups NOT FOUND :" + srcAdapterGroupName);
				}
			} else {
				if (logger.isDebug())
					logger.debug(guidLogPrefix + "srcAdapter NOT FOUND :" + srcAdapterGroupName);
			}
		} catch (Exception e) {
			if (logger.isError()) {
				logger.error(guidLogPrefix + "startTargetAdapter Error", e);
			}
		}
	}

}
