package com.eactive.eai.common.exception;

import java.nio.charset.Charset;
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.common.EAIKeys;
import com.eactive.eai.common.logger.EAILogSender;
import com.eactive.eai.common.message.EAIMessage;
import com.eactive.eai.common.message.EAIMessageKeys;
import com.eactive.eai.common.message.EAIMessageManager;
import com.eactive.eai.common.message.MessageType;
import com.eactive.eai.common.message.ServiceMessage;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.MessageUtil;
import com.eactive.eai.common.util.SMSLogUtil;
import com.eactive.eai.message.manager.StandardMessageManager;
import com.eactive.eai.transformer.engine.TransformEngine;
import com.eactive.eai.transformer.engine.Transformer;
import com.eactive.eai.transformer.layout.Item;
import com.eactive.eai.transformer.layout.Layout;
import com.eactive.eai.transformer.layout.LayoutType;
import com.eactive.eai.transformer.message.Message;
import com.eactive.eai.transformer.message.MessageFactory;
import com.eactive.eai.transformer.transform.Transform;
import com.eactive.eai.transformer.transform.TransformManager;
import com.ext.eai.common.stdmessage.STDMessageKeys;

/**
 * 1. 기능 : Exception의 동기,비동기 방식을 지원하는 클래스 2. 처리 개요 : * - SYNC 방식의 Exception
 * Handler 처리 * - ASYNC 방식의 Exception Handler 처리 3. 주의사항
 *
 * @author :
 * @version : v 1.0.0
 * @see : 관련 기능을 참조
 * @since : :
 */
public class ExceptionHandler {
	private static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);

	public ExceptionHandler() {
		// empty
	}

	public static String handle(String errMsg) {
		if (errMsg == null) {
			return "[errCd][/errCd][errMsg]EAI 내부처리 오류 입니다.[/errMsg][GstatSysAdptrBzwkGroupName][/GstatSysAdptrBzwkGroupName][data][/data]";
		} else {
			return "[errCd][/errCd][errMsg]" 
					+ errMsg
					+ "[/errMsg][GstatSysAdptrBzwkGroupName][/GstatSysAdptrBzwkGroupName][data][/data]";
		}
	}

	public static EAIMessage handle(EAIMessage eaiMessage) {
		Properties prop = eaiMessage.getCallProp();
		prop.setProperty("API_INTERNAL_ERROR_CODE", eaiMessage.getRspErrCd());

		String inAdapterGroupName = eaiMessage.getSngSysItfTp();
		AdapterManager manager = AdapterManager.getInstance();
		AdapterGroupVO group = manager.getAdapterGroupVO(inAdapterGroupName);
		String charset = StringUtils.defaultIfBlank(group.getMessageEncode(), Charset.defaultCharset().name());
		
		String transClassifycation = eaiMessage.getMapper().getSendRecvDivision(eaiMessage.getStandardMessage()); // S|R
		boolean transClassify = false;
		if (transClassifycation.equals(STDMessageKeys.SEND_RECV_CD_SEND)) {
			transClassify = true;
		} 
//		else if (transClassifycation.equals(STDMessageKeys.SEND_RECV_CD_RECV)) {
//			transClassify = false;
//		}
		return handle(eaiMessage, transClassify, charset);
	}

	public static EAIMessage handle(EAIMessage eaiMessage, boolean transClassify, String charset) {
		smsLogging(eaiMessage);

		EAIMessage resultEAIMessage = null;

		// 3. EAI 서비스 정보 추출
		// 요청오류변환ID명
		String reqErrTransID = eaiMessage.getDmndErrChngIDName();
		// 응답오류변환ID명
		String resErrTransID = eaiMessage.getRspnsErrChngIDName();
		// 오류EAI서비스명
		String resEAISvcCode = eaiMessage.getErrEAISvcName();
		// 요청에러필드명
		String reqErrPosition = eaiMessage.getDmndErrFldName();
		// 응답에러필드명
		String resErrPosition = eaiMessage.getRspnsErrFldName();

		// 서비스동기사용구분코드 //SYNC/ASYNC/AKON
		String serviceType = eaiMessage.getSvcTsmtUsgTp();

		if (serviceType == null) serviceType = "";
		// 전문요청구분코드
		String tmpTrans = eaiMessage.getMapper().getSendRecvDivision(eaiMessage.getStandardMessage()); // S|R
		// 응답에러코드
		String errCode = eaiMessage.getRspErrCd();
		// 응답에러메시지
		String errMsg = eaiMessage.getRspErrMsg();
		// 기동시스템어댑터업무그룹명
		String sngSysItfTp = eaiMessage.getSngSysItfTp();

		// 어댑터메시지구분코드 //ASC/EBC/JOB/FML/F32/XML
		String messageTypeSource = "";
		// 수동시스템어댑터업무그룹명
		String psvSysItfTp = eaiMessage.getCurrentSvcMsg().getPsvSysItfTp();
		// 수동 어댑터메시지구분코드 //ASC/EBC/JOB/FML/F32/XML
		String messageTypeTarget = "";
		// 표준메시지사용구분
		String stdMsgUsgCls = eaiMessage.getStdMsgUsgCls();
		// 수동인터페이스구분명 //SYNC/ASYNC/AKON
		String psvItfTp = eaiMessage.getCurrentSvcMsg().getPsvItfTp();

		String inboundCharset = Charset.defaultCharset().name();		
		String inAdapterGroupName = eaiMessage.getSngSysItfTp();
		AdapterGroupVO inAdapterGvo = AdapterManager.getInstance().getAdapterGroupVO(inAdapterGroupName);
		
		if(inAdapterGvo != null) {
			inboundCharset = StringUtils.defaultIfBlank(inAdapterGvo.getMessageEncode(), Charset.defaultCharset().name());
		}
		if (logger.isInfo()) {
			logger.info("ExceptionHandler] inboundCharset : {}", inboundCharset);
		}
		
		if (logger.isInfo()) {
			logger.info("ExceptionHandler] 디버그 로그 시작");
			logger.info("EAI 서비스 코드 = " + eaiMessage.getEAISvcCd());
			logger.info("서비스동기사용구분코드 = " + eaiMessage.getSvcTsmtUsgTp());
			logger.info("수동인터페이스구분명 = " + eaiMessage.getCurrentSvcMsg().getPsvItfTp());
			logger.info("전문요청구분코드 = " + eaiMessage.getMapper().getSendRecvDivision(eaiMessage.getStandardMessage())); // S|R);
			logger.info("오류EAI서비스명 = " + eaiMessage.getErrEAISvcName());
			logger.info("요청오류변환ID명 = " + eaiMessage.getDmndErrChngIDName());
			logger.info("응답오류변환ID명 = " + eaiMessage.getRspnsErrChngIDName());
			logger.info("요청에러필드명 = " + eaiMessage.getDmndErrFldName());
			logger.info("응답에러필드명 = " + eaiMessage.getRspnsErrFldName());

			logger.info("응답에러코드 = " + eaiMessage.getRspErrCd());
			logger.info("응답에러메시지 = " + eaiMessage.getRspErrMsg());
			logger.info("기동시스템어댑터업무그룹명 = " + eaiMessage.getSngSysItfTp());
			logger.info("수동시스템어댑터업무그룹명 = " + eaiMessage.getCurrentSvcMsg().getPsvSysItfTp());
			logger.info("표준메시지사용구분 = " + eaiMessage.getStdMsgUsgCls());
		}
		
		String tgtStdMsgUsgCls = "";

		// 4. 업무 데이터 추출
		String orgBizDataStr = null;
		try {
			orgBizDataStr = eaiMessage.getStandardMessage().getBizData();
		} catch (Exception e) {
			logger.error("getBizData failed.", e);
		}

		String data = null;
		try {
			AdapterManager adapterManager = null;
			AdapterGroupVO adapterGroupVoSource = null;
			AdapterGroupVO adapterGroupVoTarget = null;
			try {
				adapterManager = AdapterManager.getInstance();
				adapterGroupVoSource = adapterManager.getAdapterGroupVO(sngSysItfTp);
				// 어댑터메시지구분코드 //ASC/EBC/JOB/FML/F32/XML
				messageTypeSource = adapterGroupVoSource.getMessageType();
			} catch (Exception ee) {
				if (logger.isError())
					logger.error("ExceptionHandler] 기동어댑터그룹명 = " + adapterGroupVoSource);
				throw new Exception("기동어댑터가 정의되지 않았습니다. - " + adapterGroupVoSource);
			}
			try {
				adapterGroupVoTarget = adapterManager.getAdapterGroupVO(psvSysItfTp);
				// 수동 어댑터메시지구분코드 //ASC/EBC/JOB/FML/F32/XML
				messageTypeTarget = adapterGroupVoTarget.getMessageType();
				tgtStdMsgUsgCls = adapterGroupVoTarget.getAdptrMsgPtrnCd();
			} catch (Exception ee) {
				if (logger.isError())
					logger.error("ExceptionHandler] 수동어댑터그룹명 = " + adapterGroupVoTarget);
				throw new Exception("수동어댑터가 정의되지 않았습니다. - " + adapterGroupVoTarget);
			}

			if (logger.isInfo()) {
				logger.info("ExceptionHandler] 요청거래 = " + transClassify);
				logger.info("ExceptionHandler] 서비스동기사용구분코드 = " + serviceType);
			}

			// -----------------------------------------------------
			// 통변환로직 및 Outbound 호출 로직 추가 필요
			// -----------------------------------------------------
			if (resEAISvcCode == null || resEAISvcCode.trim().length() == 0) {
				throw new Exception("ExceptionHandler] 오류EAI서비스명이 등록되지 않았습니다.");
			}

			if (!emptyRule(transClassify, serviceType, eaiMessage)) {
				// SS, SA 거래는 기존의 로직으로 처리
				if (serviceType.equals(EAIMessageKeys.SYNC_SVC)) {
					throw new Exception("Sync Service");
				}
				// AS 거래는 요청 업무데이터를 그대로 송신
				// AA 거래는 기동이 표준인 경우 요청업무데이터를 그대로
				// -> 메시지 변경없이 그대로 전달한다.2009.11.05
				else {
					data = orgBizDataStr;
				}
			} 
			else {
				// 5. 오류변환 처리
				// 요청거래 변환
				if (transClassify) {
					if (logger.isInfo()) {
						logger.info("ExceptionHandler] 요청오류변환ID명 = " + reqErrTransID);
						logger.info("ExceptionHandler] 요청에러필드명 = " + reqErrPosition);
						logger.info("ExceptionHandler] EAI에러코드 = " + errCode);
						logger.info("ExceptionHandler] makeTrans start request transaction");
					}
					data = makeTrans(reqErrTransID, orgBizDataStr, reqErrPosition, errCode, inboundCharset);
					if (logger.isInfo()) {
						logger.info("ExceptionHandler] 요청오류변환완료");
					}
				}
				// 응답거래 변환
				else {
					if (logger.isInfo()) {
						logger.info("ExceptionHandler] 응답오류변환ID명 = " + resErrTransID);
						logger.info("ExceptionHandler] 응답에러필드명 = " + resErrPosition);
						logger.info("ExceptionHandler] EAI에러코드 = " + errCode);
						logger.info("ExceptionHandler] makeTrans start response transaction");
					}
					data = makeTrans(resErrTransID, orgBizDataStr, resErrPosition, errCode, inboundCharset);
					if (logger.isInfo()) {
						logger.info("ExceptionHandler] 응답오류변환 완료");
					}
				}
			}

			boolean isXML = checkXML(serviceType, psvItfTp, messageTypeSource, messageTypeTarget, transClassify);
			if (logger.isInfo()) {
				logger.info("ExceptionHandler] 표준메시지 사용여부 =" + stdMsgUsgCls);
				logger.info("ExceptionHandler] XML 전문 = " + isXML);
			}

			// ----------------------------------------------------------------------
			// XML 인터페이스 방식인 경우 : 오류메시지에 대한 XML Tag를 생성한다
			// ----------------------------------------------------------------------
			if (isXML) {
//				String xmlString = null;
//				if (data instanceof byte[]) {
//					xmlString = new String((byte[]) data); // TODO check charset
//					
//				} else if (data instanceof String) {
//					xmlString = (String)data;
//				}
				String xmlString = data;
				if (logger.isInfo())
					logger.info("ExceptionHandler] XML 전문 = " + xmlString);
				xmlString = MessageUtil.replaceMsgXmlString(xmlString);
				xmlString = MessageUtil.makeErrMsgXmlString(xmlString);
				data = xmlString; 
			}
			
			if (logger.isInfo()) {
				logger.info("ExceptionHandler] serviceType=" + serviceType);
			}
			// 업무데이타를 EAIMessage에 저장하고
			// 에러응답메시지를 전송한다.
			// 기동이 동기(Sync)인 경우
			// 응답에러로그를 생성하여 전달한다.
			if (serviceType.equals(EAIMessageKeys.SYNC_SVC)) {
				if (psvItfTp.equals(EAIMessageKeys.ASYNC_SVC) && tmpTrans.equals(EAIKeys.TR_RES)) {
					if (logger.isInfo()) {
						logger.info("ExceptionHandler] SA Type 응답거래처리");
					}
					errorAsyncSend(eaiMessage);
					if (logger.isInfo())
						logger.info("ExceptionHandler] end");
					return eaiMessage;
				} else {
					if (logger.isInfo())
						logger.info("ExceptionHandler] SS, SA 요청 Type 거래처리");
					// eaiMessage 에 업무데이타 셋팅
					resultEAIMessage = normalSyncSend(eaiMessage, data, charset);
					if (logger.isInfo())
						logger.info("ExceptionHandler] end");
					return resultEAIMessage;
				}
			}
			// 기동이 비동기(Async)인 경우
			// 에러응답을 송신한다.
			else if (serviceType.equals(EAIMessageKeys.ASYNC_SVC) || serviceType.equals(EAIMessageKeys.ACKONLY_SVC)) {
				if (logger.isInfo()) {
					logger.info("ExceptionHandler] AA, AS Type 거래처리");
				}
				normalAsyncSend(resEAISvcCode, eaiMessage, data, transClassify, charset);
				if (logger.isInfo())
					logger.info("ExceptionHandler] end");
				return eaiMessage;
			}

		} catch (Exception e2) {
			if (logger.isWarn()) {
				logger.warn("ExceptionHandler] 내부 Exception 무응답 처리 거래타입[" + serviceType + "][" + psvItfTp + "] - "
						+ e2.getMessage());
			}
			// 동기일경우 메시지 조립해서 전달
			// 에러 코드 + 에러 메시지 + 기동서버 아답터 그룹명 + 요청전문
			// 비동기 일경우 거래로그(900)를 생성하고 SMS보냄
			if (EAIMessageKeys.SYNC_SVC.equals(serviceType)) {
				// SA 응답 거래는 900로그 생성 : 정상일 경우 100로그만 생성되는 거래
				if (psvItfTp.equals(EAIMessageKeys.ASYNC_SVC) && tmpTrans.equals(EAIKeys.TR_RES)) {
					if (logger.isInfo())
						logger.info("ExceptionHandler] SA 응답 900 Logging");
					errorAsyncSend(eaiMessage);
					return eaiMessage;
				} else {
					if (logger.isInfo())
						logger.info("ExceptionHandler] SS, SA 요청 Type 거래처리");
					// SS, SA요청 거래일 경우 에러메시지를 생성하여 RETURN
					resultEAIMessage = errorSyncSend(eaiMessage, transClassify, errCode, errMsg, sngSysItfTp, orgBizDataStr,
							messageTypeSource, messageTypeTarget, stdMsgUsgCls, serviceType, psvItfTp
							, charset);
					return resultEAIMessage;
				}

			} else if (EAIMessageKeys.ASYNC_SVC.equals(serviceType) || EAIMessageKeys.ACKONLY_SVC.equals(serviceType)) {
				// AA,AS 거래는 900 에러로그 생성
				if (logger.isInfo())
					logger.info("ExceptionHandler] AA, AS  900 Logging");
				errorAsyncSend(eaiMessage);
				return eaiMessage;
			}
		}
		return eaiMessage;
	}

	/**
	 * 1. 기능 : EAI메시지를 생성하는 메소드 2. 처리 개요 : - EAI메시지를 생성한다 3. 주의사항
	 *
	 * @param resEAISvcCode : 응답 EAI서비스명
	 * @param eaiMessage    : 요청 EAI메시지
	 * @return 응답EAI메시지
	 * @exception Exception SQLException
	 **/
	private static EAIMessage makeEAIMessage(String resEAISvcCode, EAIMessage eaiMessage) throws Exception {

		EAIMessageManager eaiMessageManager = EAIMessageManager.getInstance();
		EAIMessage resultEAIMessage = eaiMessageManager.getEAIMessage(resEAISvcCode);
		
		// --------------------------------------
		// 2009.10.05
		// EAI 서비스메시지의 Outbound 정보를 오류EAI서비스명의 정보로 변경한다.
		// --------------------------------------
//      기동서비스구분
		eaiMessage.setSngSvcCls("EXCEPTION");

		// AS 거래일 경우 등록된 거래로 송신한다.
		if (eaiMessage.getSvcMsgs().size() > 1) {
			String keyMgtMsgVl = eaiMessage.getCurrentSvcMsg().getKeyMgtMsgVl();
			eaiMessage.setSvcPssSeq(eaiMessage.getSvcPssSeq() + 1);
			eaiMessage.getCurrentSvcMsg().setKeyMgtMsgVl(keyMgtMsgVl);
			eaiMessage.getCurrentSvcMsg().setCnvEn("0");
			eaiMessage.getCurrentSvcMsg().setSupplDelYn("0");
			return eaiMessage;
		}

//      수동업무구분 : psvBwkSysNm
//      수동시스템ID : psvSysID
//      수동시스템서비스코드 : psvSysSvcCd
//      수동시스템인터페이스유형 : psvSysItfTp
//      Outbound라우팅명 : outbRtnNm
//      변환유무 : cnvEn - 없음 (0)
//      추가삭제여부 : supplDelYn - 없음 (0)

		ServiceMessage svcMsg = eaiMessage.getCurrentSvcMsg();
		ServiceMessage errSvcMsg = resultEAIMessage.getCurrentSvcMsg();

		if (svcMsg != null && errSvcMsg != null) {
			svcMsg.setPsvBwkSysNm(errSvcMsg.getPsvBwkSysNm());
			svcMsg.setPsvSysID(errSvcMsg.getPsvSysID());
			svcMsg.setPsvSysSvcCd(errSvcMsg.getPsvSysSvcCd());
			svcMsg.setPsvSysItfTp(errSvcMsg.getPsvSysItfTp());
			svcMsg.setOutbRtnNm(errSvcMsg.getOutbRtnNm());
			svcMsg.setCnvEn("0");
			svcMsg.setSupplDelYn("0");
		}
		// add default values

		return eaiMessage;
	}

	/**
	 * 1. 기능 : 에러 응답으로 변환하는 메소드 2. 처리 개요 : - 에러 응답으로 변환한다 3. 주의사항
	 *
	 * @param errTransID  : 변환ID
	 * @param tmpMsg      : 업무데이타
	 * @param errPosition : 레이아웃위치
	 * @param errCode     : 에러코드값
	 * @return 변환된 업무데이타
	 * @exception Exception SQLException
	 **/
	private static String makeTrans(String errTransID, Object tmpMsg, String errPosition, String errCode,
			String charset)
			throws Exception {
//        TransformResult result =null;
		try {
			TransformEngine engine = TransformEngine.getInstance();
			Transformer transformer = engine.getTransformer();

			TransformManager manager = TransformManager.getManager();
			Transform info = manager.getTransform(errTransID);
			if (info == null) {
				throw new Exception("Transform is NULL - " + errTransID);
			}
			Layout ls = info.getSourceLayout(0);
			com.eactive.eai.transformer.message.Message source = MessageFactory.getFactory().getMessage(ls.getName());
			// xml일 경우 root를 만들어야 한다.
			LayoutType type = ls.getLayoutType();
			if (type == null) {
				throw new Exception("Transform getLayoutType is NULL - " + errTransID);
			}
			if (MessageType.XML.equals(type.getName())) {
				if (logger.isInfo())
					logger.info("makeTrans] is xml , add root tag ");
				String xmlString = "";
				if (tmpMsg instanceof byte[]) {
					xmlString = new String((byte[]) tmpMsg);
				} else {
					xmlString = (String) tmpMsg;
				}
				Item item = ls.getRootItem();
				if (item != null) {
					String rootName = "<" + item.getName() + ">";
					String rootNameTail = "</" + item.getName() + ">";
					xmlString = rootName + xmlString + rootNameTail;
					source.setData(xmlString);
				} else {
					source.setData(xmlString);
				}
			} else {
				source.setData(tmpMsg);
			}

			if (logger.isInfo())
				logger.info("makeTrans] source => " + source);
			// 변환
			Message target = transformer.transform(errTransID, new Message[] { source });

			if (logger.isInfo())
				logger.info("makeTrans] target => " + target);

			// errorcode setting
			target.setString(errPosition, errCode);

			if (logger.isInfo())
				logger.info("makeTrans] errorCode setting => " + target);

			// xml일 경우 root를 제거해야 한다.
			// if(ls.getLayoutType().getName().equals(MessageType.XML)) {
			Layout targetLayout = info.getTargetLayout();
			if (targetLayout == null) {
				throw new Exception("TargetLayout is NULL");
			}

			LayoutType targetType = targetLayout.getLayoutType();
			if (targetType == null) {
				throw new Exception("TargetLayout Type is NULL");
			}

			String targetData = null;
			if (MessageType.XML.equals(targetType.getName())) {
				if (logger.isInfo())
					logger.info("makeTrans] is xml , delete root tag ");
				Layout tls = info.getTargetLayout();
				String rootNameTarget = "<" + tls.getRootItem().getName() + ">";
				String rootNameTargetTail = "</" + tls.getRootItem().getName() + ">";

				targetData = target.getData().toString().replaceAll(rootNameTarget, "");
				targetData = targetData.replaceAll(rootNameTargetTail, "");
			} else {				
				Object targetObject = target.getData();
				if(targetObject instanceof String) {
					targetData = (String)targetObject;
				}
				else if(targetObject instanceof byte[]) {
					targetData = new String((byte[])targetObject, charset);
				}
			}
			return targetData;
		} catch (Exception e) {
			throw new Exception(ExceptionUtil.getErrorCode(e, "RECEAICEU104"));
		}
	}

	/**
	 * 1. 기능 : 에러 메시지를 조합하는 메소드 2. 처리 개요 : - 에러 메시지를 조합한다. 3. 주의사항
	 *
	 * @param errCode     : 에러코드
	 * @param errMsg      : 에러메시지
	 * @param sngSysItfTp : 기동시스템어댑터업무그룹명
	 * @param Msg         : 업무데이타
	 * @param SourceType  : 소스 어댑터메시지구분코드
	 * @param TargetType  : 타겟 어댑터메시지구분코드
	 * @return 변환된 업무데이타
	 * @exception Exception SQLException
	 **/
//    private static Object errorTrans(String errCode , String errMsg , String sngSysItfTp, Object msgObject,String SourceType,String TargetType ,String TransID )throws Exception{
	private static String errorTrans(String errCode, String errMsg, String sngSysItfTp, String msgObject,
			String SourceType, String TargetType, String TransID) throws Exception {
		if (logger.isInfo()) {
			logger.info("ExceptionHandler] errorTrans SourceType=>" + SourceType);
			logger.info("ExceptionHandler] errorTrans TargetType=>" + TargetType);
		}
//        byte[] msg = null;
//        if(msgObject instanceof byte[]) {
//        	msg = (byte[])msgObject; 
//        }
//        else if(msgObject instanceof byte[]) {
//        	msg = ((String)msgObject).getBytes();
//        }
		String msg = msgObject;
		String error = null;

		String tmpErrCode = "[errCd]" + errCode + "[/errCd]";
		String tmpErrMsg = "[errMsg]" + errMsg + "[/errMsg]";
		String tmpSngSysItfTp = "[GstatSysAdptrBzwkGroupName]" + sngSysItfTp + "[/GstatSysAdptrBzwkGroupName]";
		String tmpdatafront = "[data]";
		String tmpdataback = "[/data]";

		if (TargetType.equals(MessageType.ASC) || TargetType.equals(MessageType.EBC)) {
			StringBuilder sb = new StringBuilder();
			sb.append(tmpErrCode);
			sb.append(tmpErrMsg);
			sb.append(tmpSngSysItfTp);
			sb.append(tmpdatafront);
			if (msg != null) {
				sb.append(msg);
			}
			sb.append(tmpdataback);
			error = sb.toString();
		} else if (TargetType.equals(MessageType.JSON)) {
			error = MessageUtil.makeJsonErrorMessage(errCode, errMsg);
		} else if (TargetType.equals(MessageType.XML)) {
			error = MessageUtil.makeXmlErrorMessage(errCode, errMsg, "UTF-8");
		} else if (TargetType.equals(MessageType.JOB)) {
			throw new Exception("not support JOB MessageType ");
		} else if (TargetType.equals(MessageType.FML)) {
			throw new Exception("not support FML MessageType ");
		} else if (TargetType.equals(MessageType.F32)) {
//            //--------------------------------------------------------------------------
//            // 에러일 경우 TPURCODE, STATLIN 에 설정한다.
//            //--------------------------------------------------------------------------
//            if (logger.isInfo()){
//                logger.info("ExceptionHandler] FML32 Error Setting START");
//            }
//
//            TypedFML32 errorFml = new TypedFML32(new CrmFmlTable());
//
//            try {
//                errorFml.Fchg(CrmFmlTable.TPURCODE , 0,  "-1");
//                errorFml.Fchg(167772165, 0,  "[" + errCode + "] " + errMsg);
//            } catch(Exception e) {
//                if (logger.isError()){
//                    logger.error("ExceptionHandler] FML32 Setting Error - " + e.toString());
//                }
//            }
//
//            error = errorFml;
//
//            if (logger.isInfo()){
//                logger.info("ExceptionHandler] FML32 Error Setting END");
//            }
//            //--------------------------------------------------------------------------
//
//            //throw new Exception ("not support F32 MessageType ");
//            //juns 다시 확인
//            //error = errCode+errMsg+ sngSysItfTp + (String)tmpMsg;
		}
		return error;

	}

	/**
	 * 1. 기능 : 에러 메시지를 조합하는 메소드 2. 처리 개요 : - 에러 메시지를 조합한다. 3. 주의사항
	 *
	 * @param errCode     : 에러코드
	 * @param errMsg      : 에러메시지
	 * @param sngSysItfTp : 기동시스템어댑터업무그룹명
	 * @param Msg         : 업무데이타
	 * @param SourceType  : 소스 어댑터메시지구분코드
	 * @param TargetType  : 타겟 어댑터메시지구분코드
	 * @return 변환된 업무데이타
	 * @exception Exception SQLException
	 **/
	private static boolean emptyRule(boolean transClassify, String serviceType, EAIMessage eaiMessage) {

		String prefix = "ExceptionHandler]  RuleCheck ";
		if (logger.isInfo())
			logger.info(prefix + " EAI서비스코드 = " + eaiMessage.getEAISvcCd());

		boolean result = true;
		// 비동기의 경우
		if (!serviceType.equals(EAIMessageKeys.SYNC_SVC)) {
			if (logger.isInfo())
				logger.info(prefix + "오류EAI서비스코드명(errEAISvcName) =" + eaiMessage.getErrEAISvcName());
			// 오류EAI서비스명
			if (eaiMessage.getErrEAISvcName() == null || eaiMessage.getErrEAISvcName().equals("")) {
				if (logger.isInfo())
					logger.info(prefix + "RuleCheck emptyRule 오류EAI서비스코드명 미등록");
				return false;
			}
		}

		// 요청거래
		if (transClassify) {
			if (logger.isInfo()) {
				logger.info(prefix + "요청오류변환ID명 (reqErrTransID)=" + eaiMessage.getDmndErrChngIDName());
				logger.info(prefix + "요청에러필드명 (reqErrPosition)=" + eaiMessage.getDmndErrFldName());
			}
			// 요청오류변환ID명
			if (eaiMessage.getDmndErrChngIDName() == null || eaiMessage.getDmndErrChngIDName().equals("")) {
				if (logger.isInfo())
					logger.info(prefix + "emptyRule 요청오류변환ID명 ");
				return false;
			}
			// 요청에러필드명
			if (eaiMessage.getDmndErrFldName() == null || eaiMessage.getDmndErrFldName().equals("")) {
				if (logger.isInfo())
					logger.info(prefix + "emptyRule 요청에러필드명 ");
				return false;
			}

		} else {
			if (logger.isInfo()) {
				logger.info(prefix + "응답오류변환ID명 (resErrTransID)=" + eaiMessage.getRspnsErrChngIDName());
				logger.info(prefix + "응답에러필드명  (resErrPosition)=" + eaiMessage.getRspnsErrFldName());
			}
			// 응답 거래
			// 응답오류변환ID명
			if (eaiMessage.getRspnsErrChngIDName() == null || eaiMessage.getRspnsErrChngIDName().equals("")) {
				if (logger.isInfo())
					logger.info(prefix + "emptyRule 응답오류변환ID명");
				return false;
			}
			// 응답에러필드명
			if (eaiMessage.getRspnsErrFldName() == null || eaiMessage.getRspnsErrFldName().equals("")) {
				if (logger.isInfo())
					logger.info(prefix + " emptyRule 응답에러필드명");
				return false;
			}
		}
		return result;
	}

	/**
	 * 1. 기능 : 동기개별 메시지를 셋팅하는 메소드 2. 처리 개요 : - 동기개별 메시지를 셋팅한다. 3. 주의사항
	 *
	 * @param eaiMessage : EAIMessage
	 * @param data       : 개별메시지
	 * @return 개별메시지가 셋팅된 EAIMessage
	 * @exception Exception SQLException
	 **/
	private static EAIMessage normalSyncSend(EAIMessage eaiMessage, String data, String charset) {
		EAIMessage resultEAIMessage = null;
		resultEAIMessage = eaiMessage;
		try {
			resultEAIMessage.getStandardMessage().setBizData(data, charset);
		} catch (Exception e) {
			logger.error("setBizData error", e);
		}
		// Outbound에서 변환을 하지 못하게 하는 셋팅
		resultEAIMessage.getCurrentSvcMsg().setCnvEn("0");
		return resultEAIMessage;
	}

	/**
	 * 1. 기능 : 비동기 메시지를 전송하는 메소드 2. 처리 개요 : - 비동기 메시지를 전송한다. 3. 주의사항
	 *
	 * @param resEAISvcCode : 오류EAI서비스명
	 * @param eaiMessage    : EAIMessage
	 * @param data          : 개별메시지
	 * @exception Exception SQLException
	 **/
	private static void normalAsyncSend(String resEAISvcCode, EAIMessage eaiMessage, String data
			, boolean transClassify, String charset)
			throws Exception {
		EAIMessage resultEAIMessage = null;
		if (logger.isInfo()) {
			logger.info("ExceptionHandler] 비동기 에러응답 송신 : 오류EAI서비스명 = " + resEAISvcCode);
		}
		resultEAIMessage = makeEAIMessage(resEAISvcCode, eaiMessage);
		try {
			resultEAIMessage.getStandardMessage().setBizData(data, charset);
		} catch (Exception e) {
			logger.error("setBizData error", e);
		}

		// --------------------------------------
		// Outbound 호출시 사용됨
		// 2009.10.06
		// Outbound를 호출하지 않고 별도의 ErrorResponseSender를
		// 호출하여 처리하도록 한다.
		// --------------------------------------
//        Properties callProp = new Properties();
//        callProp.setProperty(RouteKeys.ROUTING_TYPE, RouteKeys.ROUT_JPD);
//        try{
//            //Outbound에서 변환을 하지 못하게 하는 셋팅
//            resultEAIMessage.getCurrentSvcMsg().setCnvEn("0");
//
//            // Default error code를 설정하여 에러가 발생한 것을 확인
//            // 에러코드를 그대로 유지 - 주석처리함  : 2009.10.05
//            // resultEAIMessage.setRspErrCd(EAIMessageKeys.EAI_DEFAULT_CODE);
//
//            EAIMessage retEaiMsg =  IFRouter.process(resultEAIMessage, callProp);
//            String error = retEaiMsg.getRspErrCd();
//            if( !MessageUtil.checkRspErrCd(error)){
//                throw new Exception ("");
//            }
//        }catch(Exception e1){
//            //e1.printStackTrace();
//            throw new Exception(ExceptionUtil.getErrorCode(e1,"RECEAICEU101"));
//        }
		ErrorResponseSender.sendErrorResponseMessage(resultEAIMessage, charset);
	}

	/**
	 * 1. 기능 : ExceptionHandler에서 에러가 발생한 비동기 거래를 전송하는 메소드 2. 처리 개요 : -
	 * ExceptionHandler에서 에러가 발생한 비동기 거래를 전송한다. 3. 주의사항
	 *
	 * @param eaiMessage : EAIMessage
	 * @exception Exception SQLException
	 **/
	private static void errorAsyncSend(EAIMessage eaiMessage) {
		eaiMessage.setLogPssSno(900);
		try {
			EAILogSender.send(eaiMessage, null);
		} catch (Exception e) {
			logger.error("ExceptionHandler] EAILogSender send fail", e);
		}
	}

	/**
	 * 1. 기능 : ExceptionHandler에서 에러가 발생한 비동기 거래를 전송하는 메소드 2. 처리 개요 : -
	 * ExceptionHandler에서 에러가 발생한 비동기 거래를 전송한다. 3. 주의사항
	 *
	 * @param eaiMessage : EAIMessage
	 * @exception Exception SQLException
	 **/
	private static EAIMessage errorSyncSend(EAIMessage eaiMessage, boolean transClassify, String errCode, String errMsg,
			String sngSysItfTp, String tmpMsg, String messageTypeSource, String messageTypeTarget, String stdMsgUsgCls,
			String serviceType, String psvItfTp, String charset) {
		String error = null;
		EAIMessage resultEAIMessage = null;

		// AdapterErrorMessageHandler(TemplateAdapterErrorMsgHandler) 설정이 있으면 우선 호출
		try {
			AdapterGroupVO inboundAdapterGroupVO = AdapterManager.getInstance().getAdapterGroupVO(sngSysItfTp);
			if (inboundAdapterGroupVO != null) {
				AdapterVO inboundAdapterVO = inboundAdapterGroupVO.nextAdapterVO();
				if (inboundAdapterVO != null) {
					String errorHandlerClass = AdapterPropManager.getInstance().getProperty(
							inboundAdapterVO.getPropGroupName(), "ERR_MSG_HANDLER");
					if (StringUtils.isNotBlank(errorHandlerClass)) {
						if (logger.isInfo())
							logger.info("ExceptionHandler] errorSyncSend ERR_MSG_HANDLER=" + errorHandlerClass);
						AdapterErrorMessageHandler handler = AdapterErrorMessageHandlerFactory.createHandler(errorHandlerClass);
						if (handler != null) {
							// 표준전문에 에러코드/에러메시지 세팅
							try {
								StandardMessageManager standardManager = StandardMessageManager.getInstance();
								standardManager.getMessageCoordinator().coordinateSetStandardMessageError(
										eaiMessage.getStandardMessage(), eaiMessage.getMapper(), errCode, errMsg);
							} catch (Exception e) {
								if (logger.isWarn())
									logger.warn("ExceptionHandler] errorSyncSend coordinateSetStandardMessageError 처리 실패: " + e.getMessage());
							}
							
							Object responseObj = handler.generateNonStandardInternalErrorResponseMessage(
									sngSysItfTp, inboundAdapterVO.getName(), null, tmpMsg, eaiMessage);
							if (responseObj != null) {
								resultEAIMessage = eaiMessage;
								try {
									resultEAIMessage.getStandardMessage().setBizData(responseObj, charset);
								} catch (Exception e) {
									logger.error("setBizData error", e);
								}
								resultEAIMessage.getMapper().setResponseType(
										resultEAIMessage.getStandardMessage(), STDMessageKeys.RESPONSE_TYPE_CODE_E);
								resultEAIMessage.setRspErrCd(EAIMessageKeys.EAI_SUCCESS_CODE, false);
								return resultEAIMessage;
							}
						}
					}
				}
			}
		} catch (Exception e) {
			if (logger.isWarn())
				logger.warn("ExceptionHandler] errorSyncSend AdapterErrorMessageHandler 처리 실패: " + e.getMessage());
		}

		try {
			if (transClassify) {
				if (logger.isInfo()) {
					StringBuilder sb = new StringBuilder();
					sb.append("ExceptionHandler] errorSyncSend errCode=" + errCode);
					sb.append(", errMsg=" + errMsg);
					sb.append(", sngSysItfTp=" + sngSysItfTp);
					sb.append(", messageTypeSource=" + messageTypeSource);
					sb.append("\n tmpMsg=" + tmpMsg);
					logger.info(sb.toString());
				}
				// 요청거래
				// messageType 이 source ,messageTypeTarget이 target
				if (logger.isInfo())
					logger.info("ExceptionHandler] 요청 에러변환(errorTrans)");
				error = errorTrans(errCode, errMsg, sngSysItfTp, tmpMsg, messageTypeSource, messageTypeSource,
						eaiMessage.getCurrentSvcMsg().getCnvMsgID());
			} else {
				if (logger.isInfo()) {
					StringBuilder sb = new StringBuilder();
					sb.append("ExceptionHandler] errorSyncSend errCode=" + errCode);
					sb.append(", errMsg=" + errMsg);
					sb.append(", sngSysItfTp=" + sngSysItfTp);
					sb.append(", messageTypeSource=" + messageTypeSource);
					sb.append(", stdMsgUsgCls=" + stdMsgUsgCls);
					sb.append(", messageTypeTarget=" + messageTypeTarget);
//					if (tmpMsg instanceof byte[]) {
//						sb.append("\n tmpMsg=>" + new String((byte[]) tmpMsg));
//					} else if (tmpMsg instanceof String) {
						sb.append("\n tmpMsg=>" + tmpMsg);
//					}
					logger.info(sb.toString());
				}
				// 응답거래
				// messageTypeTarget이 이 source ,messageType이 target
				if (logger.isInfo())
					logger.info("ExceptionHandler] 응답 에러변환(errorTrans)");
				error = errorTrans(errCode, errMsg, sngSysItfTp, tmpMsg, messageTypeTarget, messageTypeSource,
						eaiMessage.getCurrentSvcMsg().getBsRspCnvMsgID());
			}
		} catch (Exception e) {
			if (logger.isError())
				logger.error("ExceptionHandler] handler request return", e);
			error = tmpMsg;
		}

		if (logger.isInfo()) {
			logger.info("ExceptionHandler] stdMsgUsgCls=" + stdMsgUsgCls);
		}

		if (com.eactive.eai.adapter.Keys.IF_STANDARD.equals(stdMsgUsgCls)) {
			if (MessageType.JSON.equals(messageTypeSource)) {
				if (logger.isInfo())
					logger.info("ExceptionHandler] handler byte[] IF_STANDARD JSON");
				try {
					StandardMessageManager standardManager = StandardMessageManager.getInstance();
					boolean isBodyErrorSet = standardManager.getMessageCoordinator().coordinateSetStandardMessageError(eaiMessage.getStandardMessage(), eaiMessage.getMapper(), errCode, errMsg);
					if(!isBodyErrorSet) {
						error = null;
					}
					//eaiMessage.getMapper().setErrorCode(eaiMessage.getStandardMessage(), errCode);
					//eaiMessage.getMapper().setErrorMsg(eaiMessage.getStandardMessage(), errMsg);

				} catch (Exception e) {
					logger.error("ExceptionHandler] handler byte[] IF_STANDARD JSON", e);
				}
			} else {
				StandardMessageManager standardManager = StandardMessageManager.getInstance();
				standardManager.getMessageCoordinator().coordinateSetStandardMessageError(eaiMessage.getStandardMessage(), eaiMessage.getMapper(), errCode, errMsg);
				//eaiMessage.getMapper().setErrorCode(eaiMessage.getStandardMessage(), errCode);
				//eaiMessage.getMapper().setErrorMsg(eaiMessage.getStandardMessage(), errMsg);

				if (logger.isInfo())
					logger.info("ExceptionHandler] handler String IF_STANDARD : " + error);
				error = null;
			}
		} else {
			if (checkXML(serviceType, psvItfTp, messageTypeSource, messageTypeTarget, transClassify)) {
				error = MessageUtil.replaceMsgXmlString(error);
				error = MessageUtil.makeErrMsgXmlString(error);
				if (logger.isInfo())
					logger.info("ExceptionHandler] handler String xml tag add " + error);
			}
		}

		resultEAIMessage = eaiMessage;

		try {
			if(StringUtils.isNotBlank(error))
				resultEAIMessage.getStandardMessage().setBizData(error, charset);
		} catch (Exception e) {
			logger.error("setBizData error", e);
		}

		resultEAIMessage.getMapper().setResponseType(resultEAIMessage.getStandardMessage(),
				STDMessageKeys.RESPONSE_TYPE_CODE_E);
		// TODO 표준관련 확인필요
		return resultEAIMessage;
	}

	/**
	 * 1. 기능 : ExceptionHandler에서 에러가 발생한 비동기 거래를 전송하는 메소드 2. 처리 개요 : -
	 * ExceptionHandler에서 에러가 발생한 비동기 거래를 전송한다. 3. 주의사항
	 *
	 * @param eaiMessage : EAIMessage
	 * @exception Exception SQLException
	 **/
	private static boolean checkXML(String serviceType, String psvItfTp, String messageTypeSource,
			String messageTypeTarget, boolean transClassify) {
		if (logger.isInfo()) {
			StringBuilder sb = new StringBuilder();
			sb.append("ExceptionHandler] checkStandard : serviceType=" + serviceType);
			sb.append(", psvItfTp=" + psvItfTp);
			sb.append(", messageTypeSource=" + messageTypeSource);
			sb.append(", messageTypeTarget=" + messageTypeTarget);
			sb.append(", transClassify=" + transClassify);
			logger.info(sb.toString());
		}

		// 동기-동기 일경우 adptrMsgPtrnCdSource 기준 으로 표준일 경우 tag를 붙인다.
		// 동기-비동기 일경우 adptrMsgPtrnCdSource 기준 으로 표준일 경우 tag를 붙인다.
		// 비동기-비동기 일경우 요청거래일 경우 adptrMsgPtrnCdSource 기준으로 표준일 경우 tag를 붙인다.
		// 비동기-비동기 일경우 응답거래일 경우 adptrMsgPtrnCdTarget 기준으로 표준일 경우 tag를 붙인다.
		// 비동기-동기 일경우 adptrMsgPtrnCdSource 표준일 경우 tag를 붙인다.

		if (serviceType.equals(EAIMessageKeys.SYNC_SVC)) {
//			if (messageTypeSource.equals(MessageType.XML) || messageTypeSource.equals(MessageType.UXML)) {
			if (messageTypeSource.equals(MessageType.XML)) {
				return true;
			}
		} else if (serviceType.equals(EAIMessageKeys.ASYNC_SVC) || serviceType.equals(EAIMessageKeys.ACKONLY_SVC)) {
			if (psvItfTp.equals(EAIMessageKeys.SYNC_SVC)) {
//				if (messageTypeSource.equals(MessageType.XML) || messageTypeSource.equals(MessageType.UXML)) {
				if (messageTypeSource.equals(MessageType.XML)) {
					return true;
				}
			} else {
				if (transClassify) {
//					if (messageTypeSource.equals(MessageType.XML) || messageTypeSource.equals(MessageType.UXML)) {
					if (messageTypeSource.equals(MessageType.XML)) {
						return true;
					}
				} else {
//					if (messageTypeTarget.equals(MessageType.XML) || messageTypeSource.equals(MessageType.UXML)) {
					if (messageTypeTarget.equals(MessageType.XML)) {
						return true;
					}
				}
			}
		}
		return false;
	}
	
	private static boolean checkJSON(String serviceType, String psvItfTp, String messageTypeSource,
			String messageTypeTarget, boolean transClassify) {
		if (logger.isInfo()) {
			StringBuilder sb = new StringBuilder();
			sb.append("ExceptionHandler] checkStandard : serviceType=" + serviceType);
			sb.append(", psvItfTp=" + psvItfTp);
			sb.append(", messageTypeSource=" + messageTypeSource);
			sb.append(", messageTypeTarget=" + messageTypeTarget);
			sb.append(", transClassify=" + transClassify);
			logger.info(sb.toString());
		}

		// 동기-동기 일경우 adptrMsgPtrnCdSource 기준 으로 표준일 경우 tag를 붙인다.
		// 동기-비동기 일경우 adptrMsgPtrnCdSource 기준 으로 표준일 경우 tag를 붙인다.
		// 비동기-비동기 일경우 요청거래일 경우 adptrMsgPtrnCdSource 기준으로 표준일 경우 tag를 붙인다.
		// 비동기-비동기 일경우 응답거래일 경우 adptrMsgPtrnCdTarget 기준으로 표준일 경우 tag를 붙인다.
		// 비동기-동기 일경우 adptrMsgPtrnCdSource 표준일 경우 tag를 붙인다.

		if (serviceType.equals(EAIMessageKeys.SYNC_SVC)) {
			if (messageTypeSource.equals(MessageType.JSON)) {
				return true;
			}
		} else if (serviceType.equals(EAIMessageKeys.ASYNC_SVC) || serviceType.equals(EAIMessageKeys.ACKONLY_SVC)) {
			if (psvItfTp.equals(EAIMessageKeys.SYNC_SVC)) {
				if (messageTypeSource.equals(MessageType.JSON)) {
					return true;
				}
			} else {
				if (transClassify) {
					if (messageTypeSource.equals(MessageType.JSON)) {
						return true;
					}
				} else {
					if (messageTypeTarget.equals(MessageType.JSON)) {
						return true;
					}
				}
			}
		}
		return false;
	}

	/**
	 * 1. 기능 : SMS를 전송하기 위한 로그를 쓰는 메소드 2. 처리 개요 : 
	 * - SMS 를 전송 하기 위한 로그를 쓴다.
	 *
	 * @param eaiMessage : EAIMessage
	 * @exception Exception SQLException
	 **/
	private static void smsLogging(EAIMessage eaiMessage) {
		// SMS=>[SMS][EAI][E:EAI서비스일련번호][업무구분코드] 에러코드:에러메시지
		// 에러메시지80byte로 자름
		SMSLogUtil.loggingSMSWithCode(eaiMessage.getEAISvcCd(), eaiMessage.getRspErrCd());

		logger.error("[SMS] [EAI] [E:" + eaiMessage.getSvcOgNo() + "] [" + eaiMessage.getBwkCls() + "] "
				+ eaiMessage.getRspErrCd() + ":" + eaiMessage.getRspErrMsg());
	}
}
