package com.eactive.eai.common.logger;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Properties;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;

import com.eactive.eai.adapter.AdapterGroupVO;
import com.eactive.eai.adapter.AdapterManager;
import com.eactive.eai.agent.encryption.EncryptionManager;
import com.eactive.eai.common.dao.DAOException;
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.message.MessageType;
import com.eactive.eai.common.message.ServiceMessage;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.util.DatetimeUtil;
import com.eactive.eai.common.util.LogKeys;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.MessageUtil;
import com.eactive.eai.common.util.NullControl;
import com.eactive.eai.common.util.StringUtil;
import com.eactive.eai.transformer.layout.Item;
import com.eactive.eai.transformer.layout.Layout;
import com.eactive.eai.transformer.transform.Transform;
import com.eactive.eai.transformer.transform.TransformManager;
import com.eactive.eai.transformer.util.IConv;
import com.eactive.eai.util.HexaConverter;
import com.ext.eai.common.stdmessage.STDMessageKeys;

/** 
* 1. 기능 : DAO 객체를 생성하기 위한 Factory 클래스
* 2. 처리 개요 : DAO 객체를 생성하는 Factory 메서드를 정의한다.
* *     - 
* 3. 주의사항 
*
* @author  : 
* @version : v 1.0.0
* @see : 관련 기능을 참조
* @since   : 
*  : 
*/
public class EAIFileLogger 
{ 
    private static EAIFileLogger instance ;
    
    static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
    static Logger tranLogger = Logger.getLogger(Logger.LOGGER_TRAN);
    
    private static final String DELIMITER = "#|@";
    private static final String EOL = "EOL$$;";

    private EAIFileLogger() {
    	
    }
    
    /** 
    * 1. 기능 :  EAI File Logger 객체를 생성 반환하는 메서드
    * 2. 처리 개요 : EAI File Logger 객체를 생성 반환한다.
    *     - 
    * 3. 주의사항 
    *
    * @return   DAOFactory
    **/
    public static EAIFileLogger getInstance() {
    	if (instance == null){
    		instance = new EAIFileLogger();
    	}
        return instance;   
    }
    
    /**
     * 1. 기능 : 메시지의 Type이 EBCDIC인지 판단
     * 2. 처리 개요 : 
     *    - 로그시퀀스에 맞는 Adapter의 메시지 type을 비교
     *    - EBC인지 판별
     * 3. 주의사항
     * 
     * @param    srcIfType   String
     * @param    tgtIfType   String
     * @param    logPssSno   int
     * @param    srcAdapterMsgType   String
     * @param    tgtAdapterMsgType   String
     * @return   boolean
     **/
    public boolean isEBC(String srcIfType, String tgtIfType, int logPssSno,
                String srcAdapterMsgType, String tgtAdapterMsgType) {

        boolean isEBCDIC = false;

        // SS. SA Type
        if(logPssSno == 100) {
            if( "EBC".equals(srcAdapterMsgType) ) {
                isEBCDIC = true;
            }
        }
        else if(logPssSno == 200) {
            if( "EBC".equals(tgtAdapterMsgType) ) {
                isEBCDIC = true;
            }
        }
        else if(logPssSno == 300) {
            if (EAIMessageKeys.ASYNC_SVC.equals(srcIfType) &&
                EAIMessageKeys.ASYNC_SVC.equals(tgtIfType)) {
                if( "EBC".equals(srcAdapterMsgType) ) {
                    isEBCDIC = true;
                }
            }
            else {
                if( "EBC".equals(tgtAdapterMsgType) ) {
                    isEBCDIC = true;
                }
            }
        }
        // 400
        else if(logPssSno == 400) {
        	if (EAIMessageKeys.ASYNC_SVC.equals(srcIfType) &&
                EAIMessageKeys.ASYNC_SVC.equals(tgtIfType)) {
                if( "EBC".equals(tgtAdapterMsgType) ) {
                    isEBCDIC = true;
                }
            }
            else {
                if( "EBC".equals(srcAdapterMsgType) ) {
                    isEBCDIC = true;
                }
            }
        }
        // 900
        else {
        	if (EAIMessageKeys.ASYNC_SVC.equals(srcIfType) &&
                EAIMessageKeys.ASYNC_SVC.equals(tgtIfType)) {
                if( "EBC".equals(tgtAdapterMsgType) ) {
                    isEBCDIC = true;
                }
            }
            else {
                if( "EBC".equals(srcAdapterMsgType) ) {
                    isEBCDIC = true;
                }
            }
        }
        return isEBCDIC;
    }
    
    public boolean isUTF8(String srcIfType, String tgtIfType, int logPssSno,
    		String srcAdapterMsgEncode, String tgtAdapterMsgEncode) {
    	boolean isUTF = false;
    	if (logger.isInfo()) {
    		logger.info(String.format("EAIFileLogger] isUTF8 %s  %s  %s  %s  %s", srcIfType, tgtIfType, logPssSno, srcAdapterMsgEncode, tgtAdapterMsgEncode));
    	}
    	
    	String adapterMsgEncode = "";
    	// SS. SA Type
    	if(logPssSno == 100) {
    		adapterMsgEncode = srcAdapterMsgEncode;
    	}
    	else if(logPssSno == 200) {
    		adapterMsgEncode = tgtAdapterMsgEncode;
    	}
    	else if(logPssSno == 300) {
    		if (EAIMessageKeys.ASYNC_SVC.equals(srcIfType) &&
    				EAIMessageKeys.ASYNC_SVC.equals(tgtIfType)) {
    			adapterMsgEncode = srcAdapterMsgEncode;
    		}
    		else {
    			adapterMsgEncode = tgtAdapterMsgEncode;
    		}
    	}
    	// 400
    	else if(logPssSno == 400) {
    		if (EAIMessageKeys.ASYNC_SVC.equals(srcIfType) &&
    				EAIMessageKeys.ASYNC_SVC.equals(tgtIfType)) {
    			adapterMsgEncode = tgtAdapterMsgEncode;
    		}
    		else {
    			adapterMsgEncode = srcAdapterMsgEncode;
    		}
    	}
    	// 900
    	else {
    		if (EAIMessageKeys.ASYNC_SVC.equals(srcIfType) &&
    				EAIMessageKeys.ASYNC_SVC.equals(tgtIfType)) {
    			adapterMsgEncode = tgtAdapterMsgEncode;
    		}
    		else {
    			adapterMsgEncode = srcAdapterMsgEncode;
    		}
    	}
    	isUTF =  StringUtils.equalsIgnoreCase(adapterMsgEncode, "UTF-8");
    	return isUTF;
    }
    
    protected String removeXMLHeaderAll(String xmlMsg) {
		
        if(xmlMsg == null) {
        	return "";
        }
        else {
        	xmlMsg = xmlMsg.trim();
        }
        int sPos = xmlMsg.indexOf("<Individual>");
		int ePos = xmlMsg.indexOf("</Individual>");
		
		// 중간에 있는 경우 - CDATA 의 내용 
		if(sPos > -1 && ePos > -1) {
			xmlMsg = xmlMsg.substring(sPos+12, ePos);
		}
		return xmlMsg;
	}
    
//    private String removeXMLRootItem(String xmlString, String rootItemName) {
//		String prefix = "<" + rootItemName + ">";
//		String suffix = "</" + rootItemName + ">";
//
//		int s_idx = xmlString.indexOf(prefix);
//		int e_idx = xmlString.indexOf(suffix);
//		if (s_idx == -1 || e_idx == -1) {
//			return xmlString;
//		} else {
//			return xmlString.substring(s_idx + prefix.length(), e_idx);
//		}
//	}
        
//    private String addJsonRootItem(String jsonString, String rootItemName) {
//    	JSONObject value = (JSONObject)JSONValue.parse(jsonString);
//        JSONObject root = new JSONObject();
//        root.put(rootItemName, value);
//        return root.toJSONString();
//    }
    
//    private String removeJsonRootItem(String jsonString, String rootItemName) {
//    	JSONObject value = (JSONObject)JSONValue.parse(jsonString);
//		JSONObject sub   = (JSONObject) value.get(rootItemName);
//		return sub.toJSONString();
//    }
    
    
    /**
     * 1. 기능 : EAI 서비스 로그 셋팅
     * 2. 처리 개요 :
     *    - tran.log(EAI서비스로그) 로그값 셋팅
     * 3. 주의사항
     *
     * @param    message   EAIMessage
     * @exception    DAOException
     **/
    public void setLog(EAIMessage message, Properties prop) throws Exception{
    	
    	if(!tranLogger.isError())
    		return;
    	
        // 업무데이터 size 체크하여 업무데이터1,2에 insert하고
        // addBwkDataSub(message) 호출 여부 결정

        String apndBwkDataYn = "N"; //추가업무데이터 여부
    	int dayOfWeek = DatetimeUtil.getDayOfWeekNum(message.getMsgRcvTm());
    	
        // 개별메시지
//        Object bizMsg = message.getBizMsg()[0];
//        Object bizMsg = message.getExtMsg().getBizData()[0];
        Object bizMsg = message.getStandardMessage().getBizData();
        
        ServiceMessage svcMsg = message.getCurrentSvcMsg();
        String bizMsgStr = "";

        //transformer 적용
        String svcTsmtUsgTp = message.getSvcTsmtUsgTp(); // 기동 Syunc/Async
        String psvItfTp     = svcMsg.getPsvItfTp();      // 수동 Syunc/Async
        int logPssSno       = message.getLogPssSno();
        String rspErrCd = message.getRspErrCd();

        // Duplication Error 방지를 위해
        // 원 로그처리일련번호를 저장 : 2009.07.13
        int orglogPssSno    = logPssSno;

//        int svcLogLvl = message.getSvcLogLvl();
        boolean loggingBizData = true;
//      if(svcLogLvl > 3) {
//      	loggingBizData = false;
//      }
        
        if (logger.isWarn()) logger.warn("EAIFileLogger] loggingBizData - " + loggingBizData);
        
		// 복합거래인 경우 2X1,3X1 -> 200, 2X2,3X2 -> 300 처럼 처리한다.
		if( (logPssSno > 200 && logPssSno < 300)
				|| (logPssSno > 300 && logPssSno < 400) ) {
            if( (logPssSno % 2) == 1) {
                logPssSno = 200;
            }
            else {
                logPssSno = 300;
            }
        }        

		// 업무테이터 처리
        // 1. Get Source, Target Adapter Group Name
        String srcAdapterGroupName = message.getSngSysItfTp();
		String tgtAdapterGroupName = message.getCurrentSvcMsg().getPsvSysItfTp();

        // 2. Get Source, Target Adapter GroupVO
        AdapterManager adapterManager = AdapterManager.getInstance();
        AdapterGroupVO srcAdapterGrpVO = adapterManager.getAdapterGroupVO(srcAdapterGroupName);
        AdapterGroupVO tgtAdapterGrpVO = adapterManager.getAdapterGroupVO(tgtAdapterGroupName);

        // 3. Get Source, Target Adapter Message Type
        /*
        String srcAdapterMsgType = srcAdapterGrpVO.getMessageType();
        String tgtAdapterMsgType = tgtAdapterGrpVO != null ? tgtAdapterGrpVO.getMessageType() : "N/A";
        */
        String srcAdapterMsgType = null;
        String tgtAdapterMsgType = null;
        //String srcAdptrMsgPtrnCd = null;
        String tgtAdptrMsgPtrnCd = null;
        
        String srcAdapterMsgEncode = null;
        String tgtAdapterMsgEncode = null;

//        String s = System.getProperty("os.name");
//		if (s.indexOf("Window") < 0){

//	        srcAdptrMsgPtrnCd = srcAdapterGrpVO.getAdptrMsgPtrnCd();
	        if (srcAdapterGrpVO == null){
	        	srcAdapterMsgType = MessageType.ASC;
	        	srcAdapterMsgEncode = Charset.defaultCharset().name();
	        	if (logger.isWarn()){
	        		logger.warn("EAIFileLogger] Source Adapter null. eai service code="+message.getEAISvcCd());
	        	}
	        }
	        else {
	        	srcAdapterMsgType = srcAdapterGrpVO.getMessageType();
	        	srcAdapterMsgEncode = StringUtils.defaultIfBlank(srcAdapterGrpVO.getMessageEncode(), Charset.defaultCharset().name());
	        }
	        if (tgtAdapterGrpVO == null){
	        	tgtAdapterMsgType = MessageType.ASC;
	        	tgtAdapterMsgEncode = Charset.defaultCharset().name();
	        	if (logger.isWarn()){
	        		logger.warn("EAIFileLogger] Target Adapter null. eai service code="+message.getEAISvcCd());
	        	}
	        }
	        else{
	        	tgtAdapterMsgType = tgtAdapterGrpVO.getMessageType();
	        	tgtAdptrMsgPtrnCd = tgtAdapterGrpVO.getAdptrMsgPtrnCd();
	        	tgtAdapterMsgEncode = StringUtils.defaultIfBlank(tgtAdapterGrpVO.getMessageEncode(), Charset.defaultCharset().name());
	        }
//		}else{
//	        srcAdapterMsgType = MessageType.ASC;
//	        tgtAdapterMsgType = MessageType.ASC;
//		}

	        

	String bwkData = "";
	String addBwkData = "";
	String refMsgID = "";
	
	if(loggingBizData) {
		//---------------------------------------------------
		// LogMasking 을 위해 변환이 등록된 경우에만
		// 변환을 통해 처리하도록 수정 : 20080827 DHLEE
		//---------------------------------------------------
		boolean isMasked  = false;
		boolean isMasking = false;

		// 변환이 등록된 경우
		if ("1".equals(svcMsg.getCnvEn())) {
            TransformManager manager = TransformManager.getManager();
            Transform info = null;
            Layout l = null;

            // AA - 요청변환에서
            if (EAIMessageKeys.ASYNC_SVC.equals(svcTsmtUsgTp) && EAIMessageKeys.ASYNC_SVC.equals(psvItfTp)) {
                info = manager.getTransform(svcMsg.getCnvMsgID()); //요청변환메시지ID명
            }
            // AA이 아닌 경우
            // - 100, 200 요청변환에서
            // - 300, 400 응답변환에서
            else {
                if (logPssSno == 100 || logPssSno == 200) {
                    info = manager.getTransform(svcMsg.getCnvMsgID()); //요청변환메시지ID명
                } else {
                    if (rspErrCd.equals(EAIMessageKeys.BWK_ERRMSG_CODE)) { //업무에러(RIBEAI999999)
                        info = manager.getTransform(svcMsg.getErrRspCnvMsgID()); //오류응답변환메시지ID명
                        if(info == null) {
                        	info = manager.getTransform(svcMsg.getBsRspCnvMsgID()); //기본응답변환메시지ID명
                        }
                    } else if(MessageUtil.checkRspErrCd(rspErrCd)) {
                        info = manager.getTransform(svcMsg.getBsRspCnvMsgID()); //기본응답변환메시지ID명
                    }
                }
            }

            // 등록된 변환이 있는 경우
            if (info != null) {
            	if (logger.isInfo()) logger.info("EAIFileLogger] Masking Log Message - " + message.getEAISvcCd());

            	// 변환은 등록되어 있으나 레이아웃정보가 삭제된 경우
            	// 정삭적인 Case 가 아님.
            	try {
	            	if (logPssSno == 100 || logPssSno == 300  || logPssSno == 900)
	                    l = info.getSourceLayout(0);
	                else
	                    l = info.getTargetLayout();
            	}
            	catch(Exception e) {
            		if (logger.isInfo()) logger.info("getTargetLayout error" + e.getMessage());
            	}

            	// Layout 에 Mask 필드가 없는 경우 SKIP 하도록 한다.
            	if(l != null) {
            		try {
            			Item root = l.getRootItem();
                		isMasking = root.existMask();
            		}
            		catch(Exception e) {
            			if (logger.isWarn()) logger.info("EAIFileLogger] Check Masking field Error - " + e.getMessage());
            			isMasking = false;
            		}
            		if (logger.isInfo()) logger.info("EAIFileLogger] Message has Masking field [" + l.getName() + "][ " + isMasking+"]");
            	}
            	
            	if(isMasking) {
	                try {
                        bizMsgStr = LogMessageUtil.makeMaskData(message, bizMsg, l, logPssSno,tgtAdptrMsgPtrnCd
                    			, svcTsmtUsgTp, psvItfTp );
	                    isMasked = true;
	                } catch(Exception e) {
	                    if (logger.isInfo()) logger.info("EAIFileLogger] LogMasking Error - " + e.getMessage());
	                    isMasked = false;
	                }
            	}
            	else {
            		if (logger.isInfo()) {
            			logger.info("EAIFileLogger] Masking is unnecessary - Skip Masking ");
            		}
                    isMasked = false;
            	}
            }
            else {
            	if (logger.isInfo()) {
            		logger.info("EAIFileLogger]  Transform Not Found - Masking Unable");
            	}
                isMasked = false;
            }
            // Masking check END
        }

//		boolean isUtf8 = isUTF8(svcTsmtUsgTp, psvItfTp, logPssSno, srcAdapterMsgType, tgtAdapterMsgType);
		boolean isUtf8 = isUTF8(svcTsmtUsgTp, psvItfTp, logPssSno, srcAdapterMsgEncode, tgtAdapterMsgEncode);
		// 요청 변환이 등록되지 않은 경우 또는 Masking 처리를 실패한 경우 
		if(!isMasked) {
			if (bizMsg == null) {
	            if (logger.isInfo()) logger.info("EAIFileLogger] Message is NULL");
	            bizMsgStr = "";
	        } else if (bizMsg instanceof String) {
	            if (logger.isInfo()) logger.info("EAIFileLogger] Message is String Type");
	            bizMsgStr = (String)bizMsg;
	        } else if (bizMsg instanceof byte[]) {
	            if(isEBC(svcTsmtUsgTp, psvItfTp, logPssSno, srcAdapterMsgType, tgtAdapterMsgType)) {
	                if (logger.isInfo()) logger.info("EAIFileLogger] Message is EBCDIC bytes Type");
	                try {
	                    bizMsgStr = IConv.ebcdicToASCIIWithSOSIEX( (byte[])bizMsg );                    
	                } catch(Exception ex) {
	                    if (logger.isInfo()) logger.info("EAIFileLogger] 타입변환오류 - " + ex.getMessage());
	                    bizMsgStr = new String((byte[])bizMsg);
	                }
	            }
	            else if(isUtf8) {
                	if (logger.isInfo()) logger.info("EAIFileLogger] Message is ASCII-UTF8 bytes Type");
                	bizMsgStr = new String((byte[])bizMsg, StandardCharsets.UTF_8);
					
                }
                else {
                	if (logger.isInfo()) logger.info("EAIFileLogger] Message is ASCII bytes Type");
                	bizMsgStr = new String((byte[])bizMsg);
//                	bizMsgStr = new String((byte[])bizMsg,JSONMessage.encode);
	            }
	        } else {
	            if (logger.isInfo()) logger.info("EAIFileLogger] Message is Object or UNKNOWN Type");
	            try {
	                StringBuilder sbuff = new StringBuilder();
	                bizMsgStr = sbuff.append(PropertyUtils.describe(bizMsg)).toString();
	            } catch (Exception e) {
	                if (logger.isWarn()) logger.warn("EAIFileLogger] Object Message Parsing Error - " + e.getMessage());                
	            }
	        }
		}
		//-------------------------------------------------------------------------	

		// EAI 업무 개별부(32,000bytes)
		/**
		 * 업무데이터에 대한정의
		 * 1. biz 데이터
		 * 2. 표준전문 JSON 데이터
		 * 3. 전장표
		 */
		StringBuilder sb = new StringBuilder();
		String biz ="";
//		String header = ExtMessageConverter.getSTDLog(message.getExtMsg());
		String header = message.getStandardMessage().toFixedString(false);
		//20220405
//		String header = "";
//		if (logPssSno ==100 || logPssSno ==300){
//			header = ExtMessageConverter.getOriginalSTDLog(message.getExtMsg());
//		}else{
//			header = ExtMessageConverter.getSettingSTDLog(message.getExtMsg());
//		}
		String mdclData ="";
		if (bizMsgStr == null) {
			bizMsgStr = "";
		}

	   	//전장표 데이터부 JSON Array로 저장
	   	//암호화
		biz = EncryptionManager.getInstance().encryptDBData(bizMsgStr);
//		Charset hexaCharset = Charset.forName("euc-kr");
//        if("Y".equalsIgnoreCase(EncryptionManager.getInstance().getEncryptYN()) ){
//			try{
//				biz = HexaConverter.bytesToHexa(bizMsgStr.getBytes(hexaCharset));
//			}catch(Exception e){
//				logger.error("EAIFileLogger] bizMsgStr encryption Error - " + e.getMessage());
//			}
//			try{
//				header = HexaConverter.bytesToHexa(header.getBytes(hexaCharset));
//			}catch(Exception e){
//				logger.error("EAIFileLogger] header encryption Error - " + e.getMessage());
//			}
//			try{
//				mdclData = HexaConverter.bytesToHexa(mdclData.getBytes(hexaCharset));
//			}catch(Exception e){
//				logger.error("EAIFileLogger] mdclData encryption Error - " + e.getMessage());
//			}
//
//        }else {
//        	biz = bizMsgStr;
//        }

	   	 //임시코드 시작
	   	String logType = PropManager.getInstance().getProperty("BIZ_LOG_TYPE");
	   	if (!StringUtils.isBlank(logType)){
	   		if ("ALL".equals(logType)){
	   			sb.append(header).append("|").append(biz).append("|").append(mdclData);
	   		}else if ("HEADER".equals(logType)){
	   			sb.append(header).append("|").append("|");
	   		}else if ("BODY".equals(logType)){
	   			sb.append("|").append(biz).append("|");
	   		}else if ("NONE".equals(logType)){
	   			sb.append("|").append("|");
	   		}
	   	}else{
	   		sb.append(header).append("|").append(biz).append("|").append(mdclData);
	   	}
	   	
	   	//임시코드 종료

        // File은 전체전문을 남기도록 한다.
	   	String tmpStr = sb.toString();
	   	bwkData = tmpStr.length() > 4000 ? StringUtils.substring(tmpStr, 0, 4000) : tmpStr;
	   	addBwkData = tmpStr.length() > 4000 ? StringUtils.substring(tmpStr, 4000) : "";

        // 업무데이터 사이즈가 4000byte 이상이면 추가업무데이터 테이블에 insert
        if (!"".equals(addBwkData))
            apndBwkDataYn = "Y";
        
        String[] refMsgIDs = svcMsg.getRefMsgIDs();
        
        // 입력메시지IDS 배열은 delimiter로 구분하여 200byte 만 insert
        StringBuilder sbMsgIds = new StringBuilder();
        if (refMsgIDs != null && refMsgIDs.length > 0) {
            for (int i = 0; i < refMsgIDs.length - 1; i++) {
                sbMsgIds.append(refMsgIDs[i]).append(", ");
            }
            sbMsgIds.append(refMsgIDs[refMsgIDs.length - 1]);
            refMsgID = sbMsgIds.toString();
            
            if (refMsgID.getBytes().length > 200) {
            	refMsgID = StringUtil.chunkString(refMsgID, 200);                
            }
        }
	} // 업무데이터 로깅을 할 경우에만 END loggingBizData
	
//        ExtMessage extMessage = message.getExtMsg();
        
        // 메시지수신시각으로 테이블명 설정
//    	int dayOfWeek = DatetimeUtil.getDayOfWeekNum(message.getMsgRcvTm());


        try {
        	// 1/1000초로 변경
        	//String msgPssTm = DatetimeUtil.getTimeCenti(message.getMsgPssTm());
        	String msgPssTm = DatetimeUtil.getCurrentTime(message.getMsgPssTm());
        	
        	CustomStringBuffer sb = new CustomStringBuffer(DELIMITER);
			
			String serverName = EAIServerManager.getInstance().getLocalServerName();
			String serverGroupName = EAIServerManager.getInstance().getServerType();
			
            // EAI 업무 공통부(100 bytes)
            sb.appendAndDelimeter( NullControl.addSpace(message.getBwkCls()));   //EAI업무구분코드
            sb.appendAndDelimeter( DatetimeUtil.getCurrentTime(message.getMsgRcvTm()));   //메시지수신시각
            sb.appendAndDelimeter( NullControl.addSpace(message.getSvcOgNo()));  //EAI서비스일련번호
            
            // 2009.07.13 공동망 통신망관련 수정 - 로그 저장시 원 로그처리일련번호를 저장 
//            sb.appendAndDelimeter(4, String.valueOf(logPssSno));  //로그처리일련번호
            sb.appendAndDelimeter( String.valueOf(orglogPssSno));  //로그처리일련번호
            
//            sb.appendAndDelimeter(5, NullControl.addSpace(message.getEAISvrInstNm())); //EAI서버인스탄스명
            sb.appendAndDelimeter( NullControl.addSpace(serverName)); //EAI서버인스탄스명

            sb.appendAndDelimeter( NullControl.addSpace(message.getEAISvcCd())); //EAI서비스명
            sb.appendAndDelimeter( NullControl.addSpace(message.getSvcTmEn()));  //서비스시각유무
            sb.appendAndDelimeter( NullControl.addSpace(message.getSvcTsmtUsgTp())); //서비스동기사용구분코드
            sb.appendAndDelimeter( NullControl.addSpace(message.getSvcPssTp())); //서비스처리구분명
            sb.appendAndDelimeter( NullControl.addSpace(message.getFlwCntlRtnNm()));    //흐름통제라우팅명
            //index 10
            
            sb.appendAndDelimeter( NullControl.addSpace(message.getUnifTp()));  //통합구분명
            sb.appendAndDelimeter( NullControl.addSpace(message.getSngSvcCls()));   //기동서비스구분명
            sb.appendAndDelimeter( String.valueOf(message.getSvcPssSeq()));  //서비스처리번호
            sb.appendAndDelimeter( NullControl.addSpace(message.getSvcWlColLogYn()));   //서비스전컬럼로그여부
            sb.appendAndDelimeter( NullControl.addSpace(message.getStdMsgUsgCls()));    //표준메시지사용여부

            sb.appendAndDelimeter( NullControl.addSpace(message.getSngSysItfTp())); //기동시스템어댑터업무그룹명
            sb.appendAndDelimeter( NullControl.addSpace(message.getLydMsgID()));    //현재메시지ID명
            sb.appendAndDelimeter( NullControl.addSpace(message.getRspErrCd()));    //응답에러코드명
            sb.appendAndDelimeter( msgPssTm);   //메시지처리시각
            sb.appendAndDelimeter( String.valueOf(message.getSvrLogLvl()));  //서버로그레벨번호
            //index 20
            
            sb.appendAndDelimeter( String.valueOf(message.getSvcLogLvl()));  //서비스로그레벨번호
            sb.appendAndDelimeter( NullControl.addSpace(message.getErrEAISvcName()));   //오류EAI서비스명
            sb.appendAndDelimeter( NullControl.addSpace(message.getDmndErrChngIDName()));   //요청오류변환ID명
            sb.appendAndDelimeter( NullControl.addSpace(message.getDmndErrFldName()));  //요청에러필드명
            sb.appendAndDelimeter( NullControl.addSpace(message.getRspnsErrChngIDName()));  //응답오류변환ID명

            sb.appendAndDelimeter( NullControl.addSpace(message.getRspnsErrFldName())); //응답에러필드명
            sb.appendAndDelimeter( NullControl.addSpace(svcMsg.getPsvItfTp())); //수동인터페이스구분명
            sb.appendAndDelimeter( NullControl.addSpace(svcMsg.getPsvBwkSysNm()));  //수동업무시스템명
            sb.appendAndDelimeter( NullControl.addSpace(svcMsg.getPsvSysID())); //수동시스템ID명
            sb.appendAndDelimeter( NullControl.addSpace(svcMsg.getPsvSysSvcCd()));  //수동시스템서비스구분명
            //index 30
            
            sb.appendAndDelimeter( NullControl.addSpace(svcMsg.getPsvSysItfTp()));  //수동시스템어댑터업무그룹명
            sb.appendAndDelimeter( NullControl.addSpace(svcMsg.getFlOvrCls())); //장애극복여부
            sb.appendAndDelimeter( NullControl.addSpace(svcMsg.getCnvEn()));    //변환여부
            sb.appendAndDelimeter( NullControl.addSpace(svcMsg.getCnvMsgID())); //변환메시지ID명
            sb.appendAndDelimeter( NullControl.addSpace(refMsgID)); //입력메시지ID명

            sb.appendAndDelimeter( NullControl.addSpace(svcMsg.getBsRspMsgCprVl()));    //기본응답메시지비교내용
            sb.appendAndDelimeter( NullControl.addSpace(svcMsg.getBsRspCnvEn()));   //기본응답변환여부
            sb.appendAndDelimeter( NullControl.addSpace(svcMsg.getBsRspCnvMsgID()));    //기본응답변환메시지ID명
            sb.appendAndDelimeter( NullControl.addSpace(svcMsg.getErrRspMsgCprVl()));   //오류응답메시지비교내용
            sb.appendAndDelimeter( NullControl.addSpace(svcMsg.getErrRspCnvEn()));  //오류응답변환여부
            //index 40
            
            sb.appendAndDelimeter( NullControl.addSpace(svcMsg.getErrRspCnvMsgID()));   //오류응답변환메시지ID명
            sb.appendAndDelimeter( String.valueOf(svcMsg.getNxtSvcPssSeq()));    //다음서비스처리번호
            sb.appendAndDelimeter( NullControl.addSpace(svcMsg.getOutbRtnNm()));    //아웃바운드라우팅명
            sb.appendAndDelimeter(svcMsg.getTmoVl());   //타임아웃값
            sb.appendAndDelimeter( NullControl.addSpace(svcMsg.getCpnsSvcPssCd())); //보상서비스처리명

            sb.appendAndDelimeter( NullControl.addSpace(apndBwkDataYn));    //추가업무데이터여부
            sb.appendAndDelimeter( NullControl.addSpace(svcMsg.getKeyMgtMsgVl()));  //키관리메시지내용


            // SS,SA - Send - 100
            // AA    - Send - 100
            // AA    - Recv - 100, 300
            // AS    - 100
//            String telgmDmndDstcd = kbheader.getTelgmDmndDstcd();
//            String telgmDmndDstcd = message.getExtMsg().getSendRecv();
            String telgmDmndDstcd = message.getMapper().getSendRecvDivision(message.getStandardMessage()); // S|R
            if (prop != null &&
            	((EAIMessageKeys.SYNC_SVC.equals(svcTsmtUsgTp)
            		&& logPssSno == 100)
	             || (EAIMessageKeys.ASYNC_SVC.equals(svcTsmtUsgTp)
	                && EAIMessageKeys.ASYNC_SVC.equals(psvItfTp)
	                && STDMessageKeys.SEND_RECV_CD_RECV.equals(telgmDmndDstcd)
	                && (logPssSno == 100 || logPssSno == 300))
	             || (EAIMessageKeys.ASYNC_SVC.equals(svcTsmtUsgTp)
	                && EAIMessageKeys.ASYNC_SVC.equals(psvItfTp)
	                && STDMessageKeys.SEND_RECV_CD_SEND.equals(telgmDmndDstcd)
	                && logPssSno == 100)
	             || (EAIMessageKeys.ASYNC_SVC.equals(svcTsmtUsgTp)
	                && EAIMessageKeys.SYNC_SVC.equals(psvItfTp)
	                && logPssSno == 100))) {
            	
        		sb.appendAndDelimeter( NullControl.addSpace(prop.getProperty(Keys.LOG_ALT_KEY1)));   //추적보조키1내용
        		sb.appendAndDelimeter( NullControl.addSpace(prop.getProperty(Keys.LOG_ALT_KEY2)));   //추적보조키2내용
        		
        		sb.appendAndDelimeter( NullControl.addSpace(prop.getProperty(Keys.LOG_ALT_KEY3)));   //추적보조키3내용
        		sb.appendAndDelimeter( NullControl.addSpace(prop.getProperty(Keys.LOG_ALT_KEY4)));   //추적보조키4내용
            } else {
                sb.appendAndDelimeter( " ");   //추적보조키1내용
                sb.appendAndDelimeter( " ");   //추적보조키2내용
                sb.appendAndDelimeter( " ");   //추적보조키3내용
                sb.appendAndDelimeter( " ");   //추적보조키4내용
            }
            //index 51
            
            sb.appendAndDelimeter( NullControl.addSpace(message.getGroupCoCd())); //EAI서비스코드의 그룹회사코드
            
//            sb.appendAndDelimeter( kbheader.getGuIdNo().substring(0,33));   // PGUID
//            sb.appendAndDelimeter( extMessage.getGuid());   // PGUID
            sb.appendAndDelimeter( message.getMapper().getGuid(message.getStandardMessage()));   // PGUID
            
            sb.appendAndDelimeter( message.getTranType());   // 거래처리구분
            sb.appendAndDelimeter( NullControl.addSpace(message.getRspnsChngMsgType()));   // 응답변환유형

            // log level 'E' or 'F'
            if ("E".equals(message.getRspErrCd().substring(1, 2)) || "F".equals(message.getRspErrCd().substring(1, 2))) {
                sb.appendAndDelimeter( NullControl.addSpace(message.getRspErrCd())); //EAI에러코드
                sb.appendAndDelimeter( StringUtil.chunkString(message.getRspErrMsg(),1000)); //EAI에러내용
            }
            else {
                sb.appendAndDelimeter( " "); //EAI에러코드
                sb.appendAndDelimeter( " "); //EAI에러내용
            }

    		//juns 서버명 변경에 따른 인스턴스 룰 추출변경 
            //ex)EAIDSG_i11 => EAIDS01_i01
            //sb.appendAndDelimeter( serverName.substring(3, 6));	//서버그룹명
            sb.appendAndDelimeter( serverGroupName);	//서버그룹명

            sb.appendAndDelimeter( NullControl.addSpace(message.getCompanyCode()) );	//업체코드, add 20190625
            sb.appendAndDelimeter( message.getSplizLength());	//전문크기, add 20190625
            //index 60
            
            sb.appendAndDelimeter( NullControl.addSpace(message.getAdptrInstiCode()));	// add 20190404 // adapterNickName         
            sb.appendAndDelimeter( NullControl.addSpace(message.getTxId()));// add 20210331 //TODO 거래ID
            sb.appendAndDelimeter( NullControl.addSpace(message.getRefKey()));// add 20210331 //TODO 참조ID
            sb.appendAndDelimeter( NullControl.addSpace(message.getExtBizCd()));// add 20210402 //TODO 대외업무구분코드
            // EAI 업무 개별부(32,000bytes)
            // 전체업무데이터를 HEXA String 으로 변경해서 저장한다. (newline 등의 문제로)
            // Read시에는 HexaConverter.hexaToBytes 를 사용
//            String hexaData = HexaConverter.bytesToHexa(bizMsgStr.getBytes());
//            sb.appendAndDelimeter(hexaData);
            // 에러메시지에도 newline이 있을 수 있으므로 다른 방안으로 처리 (2019.06.25)
            // - EOL 라인을 추가한다.
            if(bwkData == null || bwkData.equals(""))
                bwkData = " ";
            sb.appendAndDelimeter(bwkData);
            
            String standardLayoutName = System.getProperty("STANDARD_LAYOUT_NAME");
            sb.appendAndDelimeter( NullControl.addSpace(standardLayoutName));
            sb.appendAndDelimeter( NullControl.addSpace(message.getClientId()));
            
            // DATA에 NewLine이 있을 경우가 있으므로
            // 데이터 라인 마지막에 추가하여 Loading 시에 EOL로 시작하는 라인이 올때까지 읽도록 처리해야 함.
            // 데이터룰 HEXA로 저장하므로 필요없음
            sb.append("\n"+EOL);

//			tranLogger.info(sb.toString());
			// 2025.04.10 tran.log 생성 로그 레벨 변경 info -> error
            tranLogger.error(sb.toString());
            
//        	String sLogDirectory = PropManager.getInstance().getProperty(LogKeys.LOGGER_INFO, LogKeys.LOG_DIRECOTRY_PREFIX);
//        	String localServer = EAIServerManager.getInstance().getLocalServerName();
//        	String type = "TSEAILG1" + dayOfWeek;
//        	String serialNo = message.getSvcOgNo();
//        	String logSeq = String.valueOf(message.getSvcPssSeq());
//        	String logPath = sLogDirectory + localServer + File.separator + type + File.separator + serialNo+ File.separator;
//        	
//            FileWrite(logPath, logSeq, sb.toString());
            
            if ("Y".equals(apndBwkDataYn)) {
                addBwkDataSub(message, addBwkData, dayOfWeek); // 업무데이터서브
            }
        } catch(Exception e) {
//        	logger.error("File Logging[MASTER] Failed - " + message.getEAISvcCd() + "|" + orglogPssSno 
//        			+ "|" + message.getSvcOgNo() + "|" + kbheader.getGuIdNo());
        	logger.error("File Logging[MASTER] Failed - " + message.getEAISvcCd() + "|" + orglogPssSno 
        			+ "|" + message.getSvcOgNo() + "|" + message.getMapper().getGuid(message.getStandardMessage()));
        	throw new DAOException(ExceptionUtil.getErrorCode(e, "RECEAICLG001"));
        }  
    }
    /**
     * 1. 기능 : 업무데이터 서브 로그 셋팅
     * 2. 처리 개요 :info[3]
     *    - TSEAILG03(EAI로그업무데이터서브정보) 로그값 셋팅
     *    - 매 4000byte 마다 row 증가
     * 3. 주의사항
     *
     * @param   message EAIMessage
     * @param   subBizMsgStr    추가 업무 데이터
     * @exception    DAOException
     **/
    public void addBwkDataSub(EAIMessage message, String subBizMsgStr, int dayOfWeek) {

        try {
        	String sLogDirectory = PropManager.getInstance().getProperty(LogKeys.LOGGER_INFO, LogKeys.LOG_DIRECOTRY_PREFIX);
        	String localServer = EAIServerManager.getInstance().getLocalServerName();
        	String type = "TSEAILG2" + dayOfWeek;
        	String serialNo = message.getSvcOgNo();
        	String logSeq = String.valueOf(message.getLogPssSno());
        	String logPath = sLogDirectory + localServer + File.separator + type + File.separator + serialNo + File.separator;
        	
        	FileWrite(logPath, logSeq, subBizMsgStr);
        }catch(Exception e) {
        	logger.error("Log Sub Data write error.",e);
        }
    }

    /**
     * 1. 기능 : 모니터링을 위한 별도의 에러로그테이블에 에러정보를 저정
     * 2. 처리 개요 :
     *    - TSEAILG03(EAI로그업무데이터서브정보) 로그값 셋팅
     * 3. 주의사항
     *
     * @param   message EAIMessage
     * @exception    DAOException
     **/
    public void addErrorLog(EAIMessage message, int dayOfWeek) {

        try {
        	CustomStringBuffer sb = new CustomStringBuffer();
            String serverName = EAIServerManager.getInstance().getLocalServerName();

            sb.appendAndDelimeter(message.getBwkCls());   //EAI업무구분코드
            sb.appendAndDelimeter(DatetimeUtil.getCurrentTime(message.getMsgRcvTm()));   //메시지수신시각
            sb.appendAndDelimeter(message.getSvcOgNo());  //EAI거래일련번호
            sb.appendAndDelimeter(String.valueOf(message.getLogPssSno()));  //로그처리일련번호

            sb.appendAndDelimeter(message.getEAISvcCd());   //EAI서비스명
            sb.appendAndDelimeter(message.getRspErrCd());   //응답에러코드명

            sb.appendAndDelimeter(message.getSngSysItfTp());   //기동시스템어댑터업무그룹명
            sb.appendAndDelimeter(message.getCurrentSvcMsg().getPsvSysItfTp());   //수동시스템어댑터업무그룹명

            if ("E".equals(message.getRspErrCd().substring(1, 2)) || "F".equals(message.getRspErrCd().substring(1, 2))) {
            	sb.appendAndDelimeter(NullControl.addSpace(message.getRspErrCd())); //EAI에러코드
            	sb.appendAndDelimeter(StringUtil.chunkString(message.getRspErrMsg(),500)); //EAI에러내용
            }
            else {
            	sb.appendAndDelimeter(" "); //EAI에러코드
            	sb.appendAndDelimeter(" "); //EAI에러내용
            }

            sb.appendAndDelimeter(NullControl.addSpace(serverName));   //EAI서버인스턴스명
            sb.appendAndDelimeter(NullControl.addSpace(EAIServerManager.getInstance().getEAIServer(serverName).getHostName()));   //로깅시스템ID
            sb.appendAndDelimeter(DatetimeUtil.getCurrentTime(message.getMsgPssTm()));   // 메시지처리일시

            // TODO DB 필드매핑 2010.12.21
            sb.appendAndDelimeter(message.getGroupCoCd());   // EAI그룹회사코드


        	String sLogDirectory = PropManager.getInstance().getProperty(LogKeys.LOGGER_INFO, LogKeys.LOG_DIRECOTRY_PREFIX);
        	String localServer = EAIServerManager.getInstance().getLocalServerName();
        	String type = "TSEAILG3" + dayOfWeek;
        	String serialNo = message.getSvcOgNo();
        	String logSeq = String.valueOf(message.getLogPssSno());
        	String logPath = sLogDirectory + localServer + File.separator + type + File.separator + serialNo + File.separator;
        	
        	FileWrite(logPath, logSeq, sb.toString());
        } catch(Exception e) {
        	logger.error("Error Log Data write error.",e);
        } 
    }

	public void FileWrite(String path, String fileName, String data)throws Exception{
		File directory = new File(path);
		directory.setWritable(true,false);
		directory.setReadable(true,false);
		directory.setExecutable(true,true);
		if (!directory.exists()){
			if (!directory.mkdirs()){
				throw new Exception("디렉토리 생성 오류입니다."+path);
			}
		}
		
		File file = new File(path+fileName);
		FileOutputStream os = null;
		BufferedOutputStream bos = null;
		try {
			os = new FileOutputStream(file);
			bos = new BufferedOutputStream(os); 
			bos.write(data.getBytes());
			bos.flush();
			file.setWritable(true,false);
			file.setReadable(true,false);
			file.setExecutable(true,true);

			if (logger.isDebugEnabled()){
				logger.debug(data);
			}
		}
		catch(Exception ex) {
			logger.error("file error", ex);
			throw ex;
		}
		finally {
			try { if(bos != null) bos.close(); } catch(Exception e) {}
			try { if(os != null) os.close(); } catch(Exception e) {}
		}
	}
} 
