package com.eactive.eai.outbound;

import java.nio.charset.Charset;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;

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.adapter.handler.AdapterErrorMessageHandler;
import com.eactive.eai.adapter.handler.AdapterErrorMessageHandlerFactory;
import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey;
import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceKey;
import com.eactive.eai.common.EAIKeys;
import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.header.HeaderActionKeys;
import com.eactive.eai.common.message.EAIMessage;
import com.eactive.eai.common.message.EAIMessageKeys;
import com.eactive.eai.common.message.MessageType;
import com.eactive.eai.common.routing.Process;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.submessage.SubMessageManager;
import com.eactive.eai.common.util.DatetimeUtil;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.MessageKeyExtractor;
import com.eactive.eai.common.util.MessageUtil;
import com.eactive.eai.common.util.StringUtil;
import com.eactive.eai.common.util.TranLogUtil;
import com.eactive.eai.common.util.UUIDGenerator;
import com.eactive.eai.control.LogSender;
import com.eactive.eai.message.StandardItem;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.manager.StandardMessageManager;
import com.eactive.eai.message.mapper.MessageMapper;
import com.eactive.eai.message.service.InterfaceMapper;
import com.ext.eai.common.stdmessage.STDMessageKeys;
import com.eactive.eai.common.message.ServiceMessage;  // jwhong

public abstract class DefaultProcess extends Process {
	protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
	protected static Logger esbLogger = Logger.getLogger(Logger.LOGGER_ESBFW);

	protected String guidLogPrefix = this.getClass().getSimpleName() + "] ";

	protected static ThreadLocal local = new ThreadLocal(); // 경과시간 동기화를 위한 ThreadLocal

	protected int svrLogLevel;

	protected EAIMessage resEaiMsg;

	protected EAIMessage reqEaiMsg;
	
	protected Properties callProp;

	protected Object tgtTranObject;

	protected int logPssSno;

	protected String svcTsmtUsgTp;
	protected String psvItfTp;

	protected Properties prop;
	protected Properties outboundProp;
	protected Properties tempProp;

	protected boolean isComp;
	protected String svcPssTp;
	protected int svcPssSeq;

	protected Object jmsRespObject;

	protected boolean isSuccess;

	protected String adapterGroupName;
	protected String adapterName;

	protected Object reqObject;
	protected Object resObject;
	protected String inboundCharset;
	protected String outboundCharset;

	protected String adptrMsgPtrnCd; // migration - boolean 값이 아니라 [S, N, C] 값을 가짐

	protected String diURI;

	protected boolean isTgtTran;

	protected com.eactive.eai.common.worker.Future future;
	protected com.eactive.eai.common.worker.JMSListenerAction jmsRespAction;

	protected String inAdapterMsgType; // 송신어댑터 타입
	protected String adptrMsgType; // 추가

	protected String topicName;

	protected String topicConFactory;

	protected int timeout;

	protected String tracekey;

	protected Object srcTranObject;

	protected byte[] orgData;

	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.warn("clientReturn", e);
			}
		}
		return resEaiMsg;
	}

	public void callService(EAIMessage reqEaiMsg, Properties prop) {
		if (reqEaiMsg == null) {
			return;
		}

		if (StringUtils.equals(reqEaiMsg.getFlwCntlRtnNm(), "PUBFC")) {
			try {
				this.reqEaiMsg = (EAIMessage) reqEaiMsg.clone();
				if (prop != null) {
					this.callProp = (Properties) prop.clone();
				}
			} catch (Exception e) {
				logger.warn("callService-1", e);
			}
		} else {
			this.reqEaiMsg = reqEaiMsg;
			this.callProp = prop;
		}

		svrLogLevel = this.reqEaiMsg.getSvrLogLvl();

		guidLogPrefix = this.getClass().getSimpleName() + "] GUID["
				+ reqEaiMsg.getMapper().getGuid(reqEaiMsg.getStandardMessage()) + "] UUID["
				+ this.reqEaiMsg.getSvcOgNo() + "] ";

		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.warn("callService", e);
			}
		}

		try {
			// IN,OUT adapter의 charset.
			this.inboundCharset = prop.getProperty(com.eactive.eai.adapter.Keys.CHARSET_KEY_IN);
			// Queue에서 호출될때 설정이 없음
			if (StringUtils.isBlank(this.inboundCharset)) {
				this.inboundCharset = this.reqEaiMsg.getStandardMessage().getBizDataCharset();
			}

			String outboundAdapterGroupName = reqEaiMsg.getCurrentSvcMsg().getPsvSysItfTp();
			AdapterGroupVO outboundAdapterGvo = AdapterManager.getInstance()
					.getAdapterGroupVO(outboundAdapterGroupName);
			prop.setProperty(com.eactive.eai.adapter.Keys.CHARSET_KEY_OUT,
					StringUtils.defaultIfBlank(outboundAdapterGvo.getMessageEncode(), Charset.defaultCharset().name()));
			this.outboundCharset = prop.getProperty(com.eactive.eai.adapter.Keys.CHARSET_KEY_OUT);
			flow();
		} catch (Exception e) {
			logger.warn("flow", e);
		} finally {
			if (jmsRespAction != null) {
				this.jmsRespAction.doEnd();
			}
		}
	}

	public void flow() throws Exception {
		// WarmUp start
		if (!isRealCall()) {
			return;
		}
		// WarmUp end

		// 송신전 처리 start
		try {
			// 초기화
			init();

			// 송신변환
			if (isSourceTransform()) {
				// 수동메시지 변환
				transControlTransformSingleReq();
			} else {
				// 메시지 설정
				setTgtTranObject();
			}
			// Header컨트롤여부
			if (isHeaderControl()) {
				performSend();
			}
			// 송신전 메시지 설정
			setSendMsg();
		} catch (Exception e) {
			// 오류처리
			checkErrorReturn(e);
			return;
		}
		// 송신전 처리 end

		// Sync-Async 호출 start
		try {
			// 아웃바운드 Sync 호출
			if (isOutboundSync()) {
				// 송신전로그
				logSenderCtrlSendReq();
				try {
					// Sync 호출
					outboundCtrlCallService();
				} catch (Exception e1) {
					printCallError(e1);
				}
				// 응답메시지확인
				checkResultMessage();

				// Sync 에서 Wait 올경우 체크
				waitCheckForSync();
			} else {
				// SA
				if (isSyncAsyncPattern()) {
					// 응답환경설정
					getTopicProperty();
				} else {
					// 복원저장
					storeMessage();
				}
				// 송신전 로그
				logSenderCtrlSendReq();
				try {
					// Async 호출
					outboundCtrlCallServiceAsync();
				} catch (Exception e1) {
					printCallError(e1);
				}
				// 송신결과확인
				checkSendResult();
				// 400 Async 에 대한 ack 오는것 500 으로 log에 저장, jwhong for kjbank
				if(isAsyncSyncPattern()){
					StandardMessage standardMessage = this.resEaiMsg.getStandardMessage();
					standardMessage.setBizData(this.resObject, this.outboundCharset);
					
					if ("E".equals(resEaiMsg.getRspErrCd().substring(1, 2))
							|| "F".equals(resEaiMsg.getRspErrCd().substring(1, 2))) {
						this.logPssSno = 900;
					} else {
						this.logPssSno = 500;
					}
					logSenderCtrlSendRes();
				}
				// SA
				if (isSyncAsyncPattern()) {
					try {
						// SA응답메시지 설정
						setTopicResult();
					} catch (Exception e) {
						// Timeout
						executeTimeout();
					}
				}
				// AA : commented - Do nothing
//    			else if (isAsyncAsyncPattern()){
//    				//TimerInfo 설정
//    				setTimerInfo();
//    				//timerInforInsert
//    				timerInfoControlTimerInfoInsert();
//    			}
			}
		} catch (Exception e) {
			performSendError();
		}
		// Sync-Async 호출 end

		// 정상처리 확인 start
		// 정상처리확인
		if (checkOutboundTransaction()) {
			// 동기거래
			if (isSync()) {
				// 응답로그값 설정
				setRcvLogInfoExtend();
				// 응답로그
				logSenderCtrlSendRes();
				// 업무응답메시지추출
				getBizMessage();
				// 업무 응답메시지 확인
				boolean successReturn = isSuccessReturn();
				if (logger.isDebug())
					logger.debug(guidLogPrefix + " isSuccessReturn() >> [" + successReturn + "]");
				if (successReturn) {
					// 정상메시지변환
					transformToSource();
				} else {
					// 오류메시지변환
					transformErrorToSource();
				}
				if (logger.isDebug())
					logger.debug(guidLogPrefix + " isTgtTranCall() >> [" + isTgtTranCall() + "]");
				// 응답변환
				if (isTgtTranCall()) {
					// 응답메시지변환
					transControlTransformSingleRes();
					// 변환응답메시지설정
					setConvertedMsg();
				} else {
					// 응답메시지설정
					setResMsg();
				}
				transControlHeaderTrnsformSinglesRes();
				// Header컨트롤여부
				if (isHeaderControl()) {
					performRecv();
				}
			} else {
				// 비동기 거래
			}
		} else {
			// sync 오류시 추가
//            if (isSync()) {
//            }

			// default
			// 요청거래
			if (isRequest()) {
				// 오류메시지설정
				setOutboundErrorMessage();
				// 오류메시지로그
				logSenderCtrlSendError();
			} else {
				// default
			}
		}
	}

	protected void setRcvLogInfoExtend() throws Exception {
		setRcvLogInfo();

		// 비표준만 셋팅함 표준은 위 코드에서 셋팅함
		if (!com.eactive.eai.adapter.Keys.IF_STANDARD.equals(this.adptrMsgPtrnCd)) {
			InterfaceMapper mapper = this.resEaiMsg.getMapper();
			StandardMessage standardMessage = this.resEaiMsg.getStandardMessage();

			// GUID SET
			mapper.nextGuidSeq(standardMessage);
//			String guid = mapper.getGuid(standardMessage);
//			String guidSeq = mapper.getGuidSeq(standardMessage);
//			mapper.setGuid(standardMessage,
//					guid + StringUtils.defaultString(StringUtils.leftPad(guidSeq, UUIDGenerator.GUID_SEQ_LENGTH, '0')));

			// 시스템구분
//            stdmsg.setData("stdheader.Inter_chn", EAIServerManager.getInstance().getSystemGubun());
			mapper.setReqSysCode(standardMessage, EAIServerManager.getInstance().getSystemGubun());

			// 수신시각 설정
//            stdmsg.setData("stdheader.recv_tm", DatetimeUtil.getCurrentTimeMillis());
			mapper.setRecvTime(standardMessage, DatetimeUtil.getCurrentTimeMillis());
			// 전문응답구분
//            stdmsg.setData("stdheader.return_gubun", STDMessage.SEND_RECV_CD_RECV);
			mapper.setSendRecvDivision(standardMessage, STDMessageKeys.SEND_RECV_CD_RECV);
			// 처리결과
			String procsRsltDvcd = mapper.getResponseType(standardMessage);
			if (StringUtils.isBlank(procsRsltDvcd)) {
				mapper.setResponseType(standardMessage, STDMessageKeys.RESPONSE_TYPE_CODE_N);
			}
			standardMessage.setBizData(this.resObject, this.outboundCharset);
			
			StandardMessageManager.getInstance().getMessageCoordinator().coordinateAfterRecvNonStdSyncResponse(standardMessage);
		}

		// inbound adapter로 참조데이터 전달
		if (this.tempProp.get(HttpAdapterServiceKey.OUTBOUND_PROPERTY_MAP) != null) {
			this.callProp.put(HttpAdapterServiceKey.OUTBOUND_PROPERTY_MAP,
					this.tempProp.get(HttpAdapterServiceKey.OUTBOUND_PROPERTY_MAP));
		}
	}

	/**
	 * WarmUp 여부
	 * 
	 * @return
	 */
	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 setTgtTranObject() throws Exception {
		String bizData = this.reqEaiMsg.getStandardMessage().getBizData();
		// if(bizData != null && bizData.length() > 0) {
		if (bizData != null) {
			this.tgtTranObject = bizData;
		}
	}

	/**
	 * 헤더 추가삭제/삭제추가 여부
	 * 
	 * @return
	 */
	public boolean isHeaderControl() {
		// supplDelYn = Y && (da || ad)

		if (logger.isDebug()) {
			logger.debug(guidLogPrefix + " Header Control 여부 :  [" + this.reqEaiMsg.getCurrentSvcMsg().getSupplDelYn()
					+ "]");
			logger.debug(guidLogPrefix + " Header Control Type :  ["
					+ this.reqEaiMsg.getCurrentSvcMsg().getHdrCtrlDstcd() + "]");
			logger.debug(guidLogPrefix + " header Action  Name :  ["
					+ this.reqEaiMsg.getCurrentSvcMsg().getHdrRefClsName() + "]");
		}

		String hdrCtrlDstcd = StringUtil.getNullStr(this.reqEaiMsg.getCurrentSvcMsg().getHdrCtrlDstcd());
		if (HeaderActionKeys.SUPPORT_Y.equals(StringUtil.getNullStr(this.reqEaiMsg.getCurrentSvcMsg().getSupplDelYn()))
				&& (HeaderActionKeys.DELETE_ADD_HEADER.equals(hdrCtrlDstcd)
						|| HeaderActionKeys.ADD_DELETE_HEADER.equals(hdrCtrlDstcd))) {
			return true;
		} else {
			return false;
		}
	}

	public void checkErrorReturn(Exception e1) throws Exception {
		try {
			if (this.resEaiMsg == null)
				this.resEaiMsg = this.reqEaiMsg;

			// 에러코드가 설정되지 않은 경우
			// 공통에러코드를 설정한다.
			if (MessageUtil.checkRspErrCd(this.resEaiMsg.getRspErrCd())) {
				String[] msgArgs = new String[1];
				msgArgs[0] = this.resEaiMsg.getEAISvcCd();
				// [EAI 서비스코드:{1}] 송신전 메시지 처리 중 에러
				String rspErrorCode = "RECEAIOCO000";
				String rspErrorMsg = ExceptionUtil.make(e1, rspErrorCode, msgArgs);
				if (logger.isError())
					logger.error(guidLogPrefix + rspErrorMsg, e1);
				this.resEaiMsg.setRspErr(rspErrorCode, rspErrorMsg);
			}

			LogSender.send(this.logPssSno, this.resEaiMsg, this.prop);
			if (EAIMessageKeys.SYNC_SVC.equals(this.reqEaiMsg.getSvcTsmtUsgTp())) {
				// 요청시 에러 발생해서 응답 설정필요
				StandardMessageManager standardManager = StandardMessageManager.getInstance();
				standardManager.getMessageCoordinator().coordinateInReturnObject(this.resEaiMsg.getStandardMessage());
				this.logPssSno = TranLogUtil.getResLogSeq(this.svcPssTp, this.svcPssSeq, this.isComp);
				LogSender.send(this.logPssSno, this.resEaiMsg, this.prop);
			}
		} catch (Exception e) {
			if (logger.isWarn()) {
				logger.warn(guidLogPrefix + " 송신전 오류애 대한 처리로직 수행 중 오류가 발생");
				logger.warn(e.getMessage());
			}
		}
	}

	public boolean isOutboundSync() {
		if (logger.isDebug())
			logger.debug(guidLogPrefix + "수동인터페이스 통신유형[" + this.psvItfTp + "]");
		if (EAIMessageKeys.SYNC_SVC.equals(this.psvItfTp)) {
			return true;
		} else {
			return false;
		}
	}
	
	// jwhong
	public boolean isAsyncSyncPattern() {
		ServiceMessage firstService = this.reqEaiMsg.getSvcMsg(0);
		ServiceMessage secondService = this.reqEaiMsg.getSvcMsg(1);
		if (EAIMessageKeys.ASYNC_SVC.equals(this.reqEaiMsg.getSvcTsmtUsgTp())
		&& EAIMessageKeys.SYNC_SVC.equals(firstService.getPsvItfTp())
		&& EAIMessageKeys.ASYNC_SVC.equals(secondService.getPsvItfTp())
		&& this.reqEaiMsg.getCurrentSvcMsg() == secondService){
			return true;
		}
		return false;
	}

	public boolean isSyncAsyncPattern() {
		if (!MessageUtil.checkRspErrCd(this.resEaiMsg.getRspErrCd())) {
			return false;
		} else if (EAIMessageKeys.SYNC_SVC.equals(this.reqEaiMsg.getSvcTsmtUsgTp())) {
			return true;
		} else {
			return false;
		}
	}

	public void performSendError() throws Exception {
		try {
			if (this.resEaiMsg == null)
				this.resEaiMsg = this.reqEaiMsg;

			if(EAIMessageKeys.ASYNC_SVC.equals(this.resEaiMsg.getCurrentSvcMsg().getPsvItfTp())){
				return ;
			}
			LogSender.send(this.logPssSno, this.resEaiMsg, this.prop);

			if (EAIMessageKeys.SYNC_SVC.equals(this.reqEaiMsg.getSvcTsmtUsgTp())) {
				this.logPssSno = TranLogUtil.getResLogSeq(this.svcPssTp, this.svcPssSeq, this.isComp);
				LogSender.send(this.logPssSno, this.resEaiMsg, this.prop);
			}

		} catch (Exception e) {
			if (logger.isWarn()) {
				logger.warn(guidLogPrefix + "송신에러 처리로직 수행 중 오류가 발생");
				logger.warn(e.getMessage());
			}
		}
	}

	public void executeTimeout() throws Exception {
		this.jmsRespObject = new byte[0];

	}

	public boolean checkOutboundTransaction() {
		if (!MessageUtil.checkRspErrCd(this.resEaiMsg.getRspErrCd())) {
			return false;
		} else {
			return true;
		}
	}

	public boolean isSync() {
		// SS || SA
		if (EAIMessageKeys.SYNC_SVC.equals(this.reqEaiMsg.getSvcTsmtUsgTp())
				|| EAIMessageKeys.SYNC_SVC.equals(this.psvItfTp)) {
			return true;
		} else {
			return false;
		}
	}

	public boolean isSuccessReturn() {
		try {
			// 표준헤더의 출력메시지 정보의 출력데이터 유형구분코드가 '02' 이고
			// 오류변환이 있는 경우에 오류변환을 수행하도록 한다

			/**
			 * NexCore 는 오류일경우 업무데이터가 없음 응답에 N이 아닐경우 ERROR로 설정(오류변환주석처리)
			 */
			InterfaceMapper mapper = this.resEaiMsg.getMapper();
			StandardMessage standardMessage = this.resEaiMsg.getStandardMessage();

			String responseType = mapper.getResponseType(standardMessage);
			if ((com.eactive.eai.adapter.Keys.IF_STANDARD.equals(this.adptrMsgPtrnCd) 
					||com.eactive.eai.adapter.Keys.IF_SUBSTANDARD.equals(this.adptrMsgPtrnCd))
					&& responseType != null
					&& !STDMessageKeys.RESPONSE_TYPE_CODE_N.equals(responseType)
			// &&
			// EAIMessageKeys.YES_FLAG.equals(this.reqEaiMsg.getCurrentSvcMsg().getErrRspCnvEn())
			) {
				if (logger.isDebug()) {
					logger.debug(guidLogPrefix + " 표준헤더의 출력메시지 정보의 출력데이터 유형구분코드[" + responseType + "]가 오류출력");
				}
				this.isSuccess = false;
			} else {
				this.isSuccess = MessageKeyExtractor.isSuccessMessage(this.adapterGroupName, this.resObject);
				// 비표준인 경우 출력 데이터 유형구분코드를 EAI가 설정한다.
				if (!com.eactive.eai.adapter.Keys.IF_STANDARD.equals(this.adptrMsgPtrnCd)) {
					if (this.isSuccess) {
						mapper.setResponseType(standardMessage, STDMessageKeys.RESPONSE_TYPE_CODE_N);
					} else {
						mapper.setResponseType(standardMessage, STDMessageKeys.RESPONSE_TYPE_CODE_E);
					}
				}
			}
		} catch (Exception e) {
			this.isSuccess = false;
		}
		return this.isSuccess;
	}

	public void logSenderCtrlSendError() throws Exception {
		try {
			LogSender.send(this.logPssSno, this.resEaiMsg, this.prop);
		} catch (Exception e) {
			if (logger.isWarn())
				logger.warn(guidLogPrefix + " EAI 서비스코드[" + this.resEaiMsg.getEAISvcCd() + "] " + this.logPssSno
						+ " 거래로그 중 오류발생");
		}
	}

	public void transformToSource() throws Exception {
		if (MessageUtil.checkRspErrCd(this.resEaiMsg.getRspErrCd())) {
			this.resEaiMsg.setRspErrCd(EAIMessageKeys.EAI_SUCCESS_CODE);
		}

		// 2020.02.07 업무데이터가 Empty 이면 변환을 Skip한다.
//        if(MessageUtil.isBizDataEmpty(this.resBytes)) {
//        	if (logger.isInfo()) logger.info(guidLogPrefix + "Response Message is EMPTY, Skip Transform.");
//        	this.isTgtTran = false;
//        }
//        else
		if (EAIMessageKeys.YES_FLAG.equals(this.reqEaiMsg.getCurrentSvcMsg().getBsRspCnvEn())) {
			this.isTgtTran = true;
			this.resEaiMsg.setRspnsChngMsgType(EAIMessageKeys.RSPNSCHNGMSGTYPE_RES);
		} else {
			this.isTgtTran = false;
		}

		this.diURI = this.reqEaiMsg.getCurrentSvcMsg().getBsRspCnvMsgID();
	}

	public void transformErrorToSource() throws Exception {
		this.resEaiMsg.setRspErrCd(EAIMessageKeys.BWK_ERRMSG_CODE);

		// 2020.02.07 업무데이터가 Empty 이면 변환을 Skip한다.
//        if(MessageUtil.isBizDataEmpty(this.resBytes)) {
//        	if (logger.isInfo()) logger.info(guidLogPrefix + "Error Response Message is EMPTY, Skip Transform.");
//        	this.isTgtTran = false;
//        }
//        else
		if (EAIMessageKeys.YES_FLAG.equals(this.reqEaiMsg.getCurrentSvcMsg().getErrRspCnvEn())) {
			this.isTgtTran = true;
		} else {
			this.isTgtTran = false;
			/**
			 * 20210608 NexCore 는 오류일경우 업무데이터가 없음 에러 변환이 없기 때문에 isTgtTran 로 설정하면 변환을 안탐
			 */

//        	//--------------------------------------------------
//        	// 오류응답인 경우 에러변환이 없는 경우 에러로 처리함
//        	//--------------------------------------------------
//        	String[] msgArgs = new String[1];
//            msgArgs[0] = this.reqEaiMsg.getEAISvcCd();
//            if (logger.isError()) {
//        		logger.error(guidLogPrefix + " 오류응답변환 미등록 EAI서비스코드["+msgArgs[0]+"]");
//            }
//
//            String rspErrorCode = "RECEAIOHP030";
//            String rspErrorMsg = ExceptionUtil.make(rspErrorCode, "오류응답변환 미등록 ", msgArgs);
//            if (logger.isError()) logger.error(guidLogPrefix + rspErrorMsg);
//            this.resEaiMsg.setRspErrCd(rspErrorCode);
//            this.resEaiMsg.setRspErrMsg(rspErrorMsg);
//            //---------------------------------------------------
		}

		this.diURI = this.reqEaiMsg.getCurrentSvcMsg().getErrRspCnvMsgID();
		this.resEaiMsg.setRspnsChngMsgType(EAIMessageKeys.RSPNSCHNGMSGTYPE_ERR);
	}

	public void setResMsg() throws Exception {
		StandardMessage resStandardMessage = this.resEaiMsg.getStandardMessage();
		InterfaceMapper mapper = this.resEaiMsg.getMapper();
		String responseType = mapper.getResponseType(resStandardMessage);
		
		// apigw내 오류 없이, 표준헤더내 오류설정된 경우 응답 처리
		if(!STDMessageKeys.RESPONSE_TYPE_CODE_N.equals(responseType)){
			String inboudnAdapterGroupName = this.callProp.getProperty(HttpClientAdapterServiceKey.ADAPTER_GROUP_NAME);
			String inboudnAdapterName = this.callProp.getProperty(HttpClientAdapterServiceKey.ADAPTER_NAME);
			if(StringUtils.isBlank(inboudnAdapterGroupName) || StringUtils.isBlank(inboudnAdapterName)) {
				return;
			}
			
			AdapterGroupVO inboundAdapterGroupVO = AdapterManager.getInstance().getAdapterGroupVO(inboudnAdapterGroupName);
			AdapterVO inboundAdapterVO = AdapterManager.getInstance().getAdapterVO(inboudnAdapterGroupName, inboudnAdapterName);
			String errorResponseHandlerClass = AdapterPropManager.getInstance().getProperty(inboundAdapterVO.getPropGroupName(), "ERR_MSG_HANDLER");
			if(StringUtils.isBlank(errorResponseHandlerClass)) {
				if ((com.eactive.eai.adapter.Keys.IF_STANDARD.equals(this.adptrMsgPtrnCd) 
						||com.eactive.eai.adapter.Keys.IF_SUBSTANDARD.equals(this.adptrMsgPtrnCd))) {
					String errorCode = mapper.getErrorCode(resStandardMessage);
					String errorMsg = StringUtils.trim(mapper.getErrorMsg(resStandardMessage));
					String errorDesc = StringUtils.trim(resStandardMessage.findItemValue("MSG.MAIN_MSG.outp_msg_desc"));
					this.resEaiMsg.setRspErr("RECEAIINA001", String.format("[%s] %s (%s)", errorCode, errorMsg, errorDesc));
					return;
				} else {
					this.resEaiMsg.setRspErr("RECEAIINA001", "비표준 오류 응답 수신");
					return;
				}
			}
			
			logger.info(inboudnAdapterName+", Handle Error Message Class-"+errorResponseHandlerClass);
			
			AdapterErrorMessageHandler adapterErrorMessageHandler = AdapterErrorMessageHandlerFactory.createHandler(errorResponseHandlerClass);
			
			Object responseObj = adapterErrorMessageHandler.generateNonStandardErrorResponseMessage(inboudnAdapterGroupName, inboudnAdapterName, this.callProp, this.tgtTranObject, this.resEaiMsg);
			if(responseObj != null) {
				resStandardMessage.setBizData(responseObj, inboundAdapterGroupVO.getMessageEncode());
			}
			
			this.resEaiMsg.setRspErrCd(EAIMessageKeys.BWK_FAILMSG_CODE, false);
		}
	}

	public boolean isTgtTranCall() {
		return this.isTgtTran;
	}

	public void setConvertedMsg() throws Exception {
		this.resEaiMsg.getStandardMessage().setBizData(this.tgtTranObject, this.inboundCharset);
	}

	public boolean isSourceTransform() {
		try {
			// 표준헤더의 출력메시지 정보의 출력데이터 유형구분코드가 '02' 이고
			// 오류변환이 있는 경우에 오류변환을 수행하도록 한다
			InterfaceMapper mapper = this.reqEaiMsg.getMapper();
			StandardMessage standardMessage = this.reqEaiMsg.getStandardMessage();

			String responseType = mapper.getResponseType(standardMessage);
			String returnType = mapper.getSendRecvDivision(standardMessage);

			// 2025.03.28 responseType값이 없을때 return값이 " "로 설정되어 if문에서 true가 되어 에러응답변환 값으로 설정됨
			if (responseType != null && !"".equals(responseType.trim()) && !STDMessageKeys.RESPONSE_TYPE_CODE_N.equals(responseType)
					&& EAIMessageKeys.YES_FLAG.equals(this.reqEaiMsg.getCurrentSvcMsg().getErrRspCnvEn())) {
				this.diURI = this.reqEaiMsg.getCurrentSvcMsg().getErrRspCnvMsgID();
				if (logger.isDebug()) {
					logger.debug(guidLogPrefix + " 요청변환(에러응답변환) 출력데이터 유형구분코드[" + responseType + "] - " + this.diURI);
				}
				return true;
			} else {
				if (EAIMessageKeys.YES_FLAG.equals(this.reqEaiMsg.getCurrentSvcMsg().getCnvEn())) {
					this.diURI = this.reqEaiMsg.getCurrentSvcMsg().getCnvMsgID();
					// ----------------------------------------------------------------
					// AA 응답 거래일 경우 기동어댑터의 정상응답 에러응답여부를 확인하여
					// 오류응답일 경우 오류변환을 수행
					// ----------------------------------------------------------------
					if (EAIMessageKeys.ASYNC_SVC.equals(this.reqEaiMsg.getSvcTsmtUsgTp())
							&& EAIMessageKeys.ASYNC_SVC.equals(this.psvItfTp)
							&& STDMessageKeys.SEND_RECV_CD_RECV.equals(returnType)
							&& EAIMessageKeys.YES_FLAG.equals(this.reqEaiMsg.getCurrentSvcMsg().getErrRspCnvEn())) {
						String inAdapter = this.reqEaiMsg.getSngSysItfTp();
						boolean successFlag = MessageKeyExtractor.isSuccessMessage(inAdapter,
								standardMessage.getBizData());

						if (!successFlag) {
							this.diURI = this.reqEaiMsg.getCurrentSvcMsg().getErrRspCnvMsgID();
							if (logger.isDebug()) {
								logger.debug(guidLogPrefix + " 요청변환(에러응답변환)  - " + this.diURI);
							}
						}
					}

					if (logger.isDebug()) {
						logger.debug(guidLogPrefix + " 요청변환  - " + this.diURI);
					}
					return true;
				} else {
					return false;
				}
			}
		} catch (Exception e) {
			return false;
		}
	}

	public void setOutboundErrorMessage() throws Exception {
		this.logPssSno = TranLogUtil.getResLogSeq(this.svcPssTp, this.svcPssSeq, this.isComp);

		InterfaceMapper mapper = this.resEaiMsg.getMapper();
		StandardMessage standardMessage = this.resEaiMsg.getStandardMessage();

		// 에러에 대한 응답메시지
		if(this.tempProp.get(HttpAdapterServiceKey.OUTBOUND_PROPERTY_MAP) instanceof Map) {
			Map<String, Object> map = (Map<String, Object>) this.tempProp.get(HttpAdapterServiceKey.OUTBOUND_PROPERTY_MAP);
			this.resObject = map.get(HttpAdapterServiceKey.OUTBOUND_RESPONSE_MESSAGE);
			this.callProp.put(HttpAdapterServiceKey.OUTBOUND_PROPERTY_MAP, map);
		}
		standardMessage.setBizData(this.resObject, this.inboundCharset);
		try {
			//mapper.nextGuidSeq(standardMessage);
			mapper.setSendRecvDivision(standardMessage, STDMessageKeys.SEND_RECV_CD_RECV);
			StandardMessageManager standardManager = StandardMessageManager.getInstance();
			standardManager.getMessageCoordinator().coordinateSetStandardMessageError(standardMessage, mapper,
					this.resEaiMsg.getRspErrCd(), this.resEaiMsg.getRspErrMsg());
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
	}

	public boolean isRequest() {
		// ----------------------------------------------
		// FILE 변경에 따른 BUG
		// AA 응답거래일 경우
		// 에러 로그를 남기지 않는다.
		// AA 응답거래일 경우에는 FlowControl에서 ExceptionHandler에 의해
		// 900 ERROR 로그를 남긴다.
		// ----------------------------------------------
		InterfaceMapper mapper = reqEaiMsg.getMapper();
		StandardMessage standardMessage = reqEaiMsg.getStandardMessage();
		String returnType = mapper.getSendRecvDivision(standardMessage);
		// AA && RES
		if (EAIMessageKeys.ASYNC_SVC.equals(this.reqEaiMsg.getSvcTsmtUsgTp())
				&& EAIMessageKeys.ASYNC_SVC.equals(this.psvItfTp)
				&& STDMessageKeys.SEND_RECV_CD_RECV.equals(returnType)) {
			return false;
		} else {
			return true;
		}
	}

	protected int getTimeoutCodeToValue() throws Exception {
//		PropManager propManager = PropManager.getInstance();
//		/**
//         * TIMEOUT CODE 로 변경됨
//         * TIMEOUT_CODE : S : 30
//         * TIMEOUT_CODE : M : 90
//         * TIMEOUT_CODE : L : 180
//         * TIMEOUT_CODE : X : 300
//         * TIMEOUT_CODE : DEFAULT : S
//         */
////        this.timeout = this.reqEaiMsg.getCurrentSvcMsg().getTmoVl() * 1000; //180 * 1000;
//        String timeoutCode = this.reqEaiMsg.getCurrentSvcMsg().getTimeoutCode(); //S/M/L/X
//        if (StringUtils.isEmpty(timeoutCode)){
//        	timeoutCode = propManager.getProperty("TIMEOUT_CODE", "DEFAULT" );
//        }
//        String timeoutCodeValue = propManager.getProperty("TIMEOUT_CODE", timeoutCode ); //실제 값
//
//        int iTimeoutValue = 30;
//    	try{
//    		iTimeoutValue = Integer.parseInt(timeoutCodeValue);
//    	}catch(Exception e){
//
//    	}
//    	/**
//    	 * TODO 20210826 타임아웃값 조정
//    	 * MCI 일경우 전체 타임아웃에서 5초 추가
//    	 * EAI 일경우 전체 타임아웃값
//    	 * FEP 일경우 전체 타임아웃은 무의미
//    	 */
//    	if (EAIServerManager.getInstance().isMCI()){
//    		iTimeoutValue += 5;
//    	}
//
//    	return iTimeoutValue;
		// return this.reqEaiMsg.getCurrentSvcMsg().getTmoVl() * 1000;
		StandardMessageManager standardManager = StandardMessageManager.getInstance();
		return standardManager.getMessageCoordinator().coordinateForTimeoutCodeToValue(this.reqEaiMsg);
//		return this.reqEaiMsg.getCurrentSvcMsg().getTmoVl();
	}

	public abstract void logSenderCtrlSendReq() throws Exception;

	public abstract void logSenderCtrlSendRes() throws Exception;

	public abstract void outboundCtrlCallService() throws Exception;

	public abstract void outboundCtrlCallServiceAsync() throws Exception;

	public abstract void transControlTransformSingleRes() throws Exception;

	public abstract void transControlTransformSingleReq() throws Exception;

	public abstract void printCallError(Exception e1) throws Exception;

	public abstract void setRcvLogInfo() throws Exception;

	public abstract void setTopicResult() throws Exception;

	public abstract void checkResultMessage() throws Exception;

	public abstract void checkSendResult() throws Exception;

	public abstract void init() throws Exception;

	public abstract void setSendMsg() throws Exception;

	public abstract void getTopicProperty() throws Exception;

	public abstract void performSend() throws Exception;

	public abstract void performRecv() throws Exception;

	public abstract void storeMessage() throws Exception;

	public abstract void getBizMessage() throws Exception;

	public abstract void waitCheckForSync() throws Exception;

	public abstract void transControlHeaderTrnsformSinglesRes() throws Exception;

	protected Object makeSubStandardMessageData(EAIMessage eaiMessage, String msgType, Object bizObject, String charset)
			throws Exception {
		StandardMessageManager standardManager = StandardMessageManager.getInstance();
		StandardMessage standardMessage = eaiMessage.getStandardMessage();

		String outboundAdapterGroupName = eaiMessage.getCurrentSvcMsg().getPsvSysItfTp();
		AdapterGroupVO outboundAdapterGvo = AdapterManager.getInstance().getAdapterGroupVO(outboundAdapterGroupName);
		standardMessage.setBizData(bizObject, outboundAdapterGvo.getMessageEncode());

		StandardMessage subMessage = standardManager.getVersionMessage();

		SubMessageManager subManager = SubMessageManager.getInstance();
		String eaiSvcCode = eaiMessage.getEAISvcCd();
		Map<String, String> subMap = subManager.getSubMessageMap(eaiSvcCode);
		if (subMap != null) {
			for (Map.Entry<String, String> entry : subMap.entrySet()) {
				if (logger.isDebug()) {
					logger.debug(String.format("DefaultProcess] SUBSTANDARD-MAPPING path: %s, value: %s",
							entry.getKey(), entry.getValue()));
				}
				StandardItem sItem = subMessage.findItem(entry.getKey());
				if (sItem != null) {
					sItem.setValue(entry.getValue());
				}
			}
		}

		MessageMapper versionMapper = standardManager.getVersionMapper();
		subMessage = versionMapper.convertToSub(standardMessage, subMessage);
		subMessage.setBizDataCharset(charset);

		eaiMessage.setSubMessage(subMessage);
		if (logger.isDebug()) {
			logger.debug(String.format("DefaultProcess] SUBSTANDARD-LOGGING SAVE UUID: %s, LOGSEQ: %s, HEADER: %s",
					eaiMessage.getSvcOgNo(), this.logPssSno, subMessage.toFixedString(false)));
		}

		if (MessageType.JSON.equals(msgType)) {
			return subMessage.toJson();
		} else if (MessageType.XML.equals(msgType)) {
			return subMessage.toXML();
		} else if (MessageType.ASC.equals(msgType)) {
			return subMessage.toByteArray(charset);
		} else {
			throw new Exception("Unsupported msgType - " + msgType);
		}
	}

	protected EAIMessage convertToStandardMessage(EAIMessage eaiMessage, String msgType, Object message, String charset)
			throws Exception {
		InterfaceMapper mapper = eaiMessage.getMapper();
		StandardMessageManager standardManager = StandardMessageManager.getInstance();
		MessageMapper versionMapper = standardManager.getVersionMapper();
		StandardMessage orgStandardMessage = eaiMessage.getStandardMessage();
		StandardMessage subMessage = versionMapper.parseSub(msgType, message);
		subMessage.setBizDataCharset(charset);
		eaiMessage.setSubMessage(subMessage);
		if (logger.isDebug()) {
			logger.debug(String.format("DefaultProcess] SUBSTANDARD-LOGGING SAVE UUID: %s, LOGSEQ: %s, HEADER: %s",
					eaiMessage.getSvcOgNo(), this.logPssSno, subMessage.toFixedString(false)));
		}

		StandardMessage standardMessage = versionMapper.mapFromSub(subMessage, orgStandardMessage);

		standardMessage.setBizDataCharset(charset);
		standardManager.getMessageCoordinator().coordinateAfterParsing(standardMessage, null, new Properties());
		eaiMessage.setStandardMessage(standardMessage);

		mapper.setRecvTime(standardMessage, DatetimeUtil.getCurrentTimeMillis());
		return eaiMessage;
	}
}
