package com.eactive.eai.batch.logger;

import java.sql.ResultSet;
import java.util.ArrayList;

import com.eactive.eai.batch.common.CommonKeys;
import com.eactive.eai.batch.common.StringUtil;
import com.eactive.eai.batch.doc.BatchDoc;
import com.eactive.eai.batch.scheduler.JobFileTransferVO;
import com.eactive.eai.common.dao.BaseDAO;
import com.eactive.eai.common.dao.DAOException;
import com.eactive.eai.common.exception.ExceptionUtil;

public class LogDAO extends BaseDAO implements LogQuery
{
    
    public static final int LOG_MASTER_ERROR_DESC_FIELD_LENGTH = 1000;
    public static final int LOG_STAGE_ERROR_DESC_FIELD_LENGTH  = 1000;
    public static final int LOG_FILE_ERROR_DESC_FIELD_LENGTH   = 1000;

    /**
    * 1. 기능 : 해당 배치 Job의 Master, Stage 로그가 존재하는지를 조회한다.
    * 2. 처리 개요 :
    * 3. 주의사항
    *
    * @param		msgDoc			배치메시지 Document
	* @return		Master 로그 존재여부
    * @exception	DAOException	DB select 가 실패한 경우, 조회 건수가 없는 경우
    **/
	public int[] existLogCount(BatchDoc msgDoc) throws DAOException {

		ResultSet rs = null;
		int index    = 0;

		String uuid            = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getUUID()                );  //UUID
		String subUuid         = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getSubUUID()               );  //sub UUID
		String layerCode       = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getLayerCode()      , " ");  //Layer구분코드
		String subLayerCode    = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getSubLayerCode()     , " ");  //Sub_Layer구분코드
//		String ruleCode        = StringUtil.nvlTrim(msgDoc.getEAIBatchMessage().getPhaseinfo().getRuleCode()    , " ");  //Rule코드
//		String phaseCode       = StringUtil.nvlTrim(msgDoc.getEAIBatchMessage().getPhaseinfo().getPhaseCode()   , " ");  //Rule단계코드
		int    nodeCount       = msgDoc.getBatchMsg().getBody().getNodeCount();                                   //NodeCount
		String fileName        = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getFileName()       , " ");  //실제파일명

		try {

			this.connect(SELECT_EXIST_LOG_COUNT); //			logger.debug("{ LogDAO.existLogCount() } 수행 SQL 문 : \n"+ SELECT_EXIST_LOG_COUNT);

			index = 1;
			this.preparedStatement.setString(index++, uuid        );	//			logger.debug("{ LogDAO.existLogCount() } 바인드("+(index-1)+") : ["+ uuid         +"]");
			this.preparedStatement.setString(index++, subUuid     );	//			logger.debug("{ LogDAO.existLogCount() } 바인드("+(index-1)+") : ["+ subUuid      +"]");
			this.preparedStatement.setString(index++, uuid        );	//			logger.debug("{ LogDAO.existLogCount() } 바인드("+(index-1)+") : ["+ uuid         +"]");
			this.preparedStatement.setString(index++, subUuid     );	//			logger.debug("{ LogDAO.existLogCount() } 바인드("+(index-1)+") : ["+ subUuid      +"]");
			this.preparedStatement.setString(index++, layerCode   );	//			logger.debug("{ LogDAO.existLogCount() } 바인드("+(index-1)+") : ["+ layerCode    +"]");
			this.preparedStatement.setString(index++, subLayerCode);	//			logger.debug("{ LogDAO.existLogCount() } 바인드("+(index-1)+") : ["+ subLayerCode +"]");
			//this.preparedStatement.setString(index++, ruleCode    );	//logger.debug("{ LogDAO.existLogCount() } 바인드("+(index-1)+") : ["+ ruleCode     +"]");
			//this.preparedStatement.setString(index++, phaseCode   );	//logger.debug("{ LogDAO.existLogCount() } 바인드("+(index-1)+") : ["+ phaseCode    +"]");
			this.preparedStatement.setString   (index++, "" + nodeCount   );	//			logger.debug("{ LogDAO.existLogCount() } 바인드("+(index-1)+") : ["+ nodeCount    +"]");
			this.preparedStatement.setString(index++, uuid        );	//			logger.debug("{ LogDAO.existLogCount() } 바인드("+(index-1)+") : ["+ uuid         +"]");
			this.preparedStatement.setString(index++, subUuid     );	//			logger.debug("{ LogDAO.existLogCount() } 바인드("+(index-1)+") : ["+ subUuid      +"]");
			this.preparedStatement.setString(index++, fileName    );	//			logger.debug("{ LogDAO.existLogCount() } 바인드("+(index-1)+") : ["+ fileName     +"]");

			rs = executeQuery();

			rs.next();
			int[] existLogCnt = new int[3];
			existLogCnt[0] = rs.getInt("LogMasterCnt");
			existLogCnt[1] = rs.getInt("LogStageCnt");
			existLogCnt[2] = rs.getInt("LogFileCnt");
			logger.info("[ DB로그 ] ==> DB로그 존재 건수 : MASTER_LOG="+ existLogCnt[0] +", STAGE_LOG="+ existLogCnt[1] +", FILE_LOG="+ existLogCnt[2] +"  [UUID: "+ uuid +", SUB_UUID: "+ subUuid +"]");

			return existLogCnt;


		} catch (DAOException ex) {
			throw ex;
		} catch (Exception ex) {
			String errMsg = ExceptionUtil.getErrorCode(ex, "BECEAICLG019", new String[] {uuid, subUuid});
			throw new DAOException(errMsg);  //배치 DB로그 존재여부 조회시 오류가 발생하였습니다.[UUID: {1}] [SUB_UUID: {2}]
		} finally {
			disconnect();
		}
	}


    /**
    * 1. 기능 : 배치 Job 시작 시 Master 로그를 insert 한다.
    * 2. 처리 개요 :
    * 3. 주의사항
    *
    * @param		msgDoc			배치메시지 Document
	* @return		Master 로그 테이블의 insert Row 수
    * @exception	DAOException	DB insert 가 실패한 경우, insert 건수가 없는 경우
    **/
	public int insertLogMaster(BatchDoc msgDoc) throws DAOException {

		int       retValue = 0;
		int       index    = 0;

		String uuid            = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getUUID()                );  //UUID
		String subUuid         = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getSubUUID()               );  //sub UUID
		int    retryCount      = msgDoc.getBatchMsg().getBody().getRetryCount();                                  //작업재시도회수
		String scheduleCode    = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getScheduleCode()   , " ");  //스케쥴코드
		String msgCreateTime   = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getBatchStartTime() , " ");  //메시지생성시간
		String institutionCode = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getInstitutionCode(), " ");  //대외기관코드
		String processCode     = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getProcessCode()    , " ");  //Process 테이블 FK
		String processType     = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getProcessType()    , " ");  //Job 유형구분
		String userID          = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getUserID()         , " ");  //사용자ID
		String userName        = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getUserName()       , " ");  //사용자명
		String sysConnCode     = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getSystemConnCode() , " ");  //연결정보ID
		String remoteIP        = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getRemoteIP()       , " ");  //Remote IP
		String ruleCode        = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getRuleCode()       , " ");  //RuleCode
		String weblogicName    = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getWLIServerName()    , " ");  //웹로직서버명
		String phaseStartTime  = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getPhaseStartTime()   , " ");  //단계시작시간
		String phaseEndTime    = " ";                                                                                    //단계종료시간 (공백 설정)
		String errorDesc       = " ";                                                                                    //에러메시지 (공백 설정)

		//진행상태: SocketServer 에서 호출된 경우 '시작'상태로, 그 외 '대기'상태로 설정
		String layerCode       = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getLayerCode()           );  //Layer구분코드
		String status          = layerCode.equals(CommonKeys.LAYER_SOCKET_SERVER)? LogManager.LOG_TYPE_START : LogManager.LOG_TYPE_QUEUE;

		try {

			this.connect(INSERT_LOG_MASTER);

			index = 1;
			this.preparedStatement.setString(index++, uuid           );
			this.preparedStatement.setString(index++, subUuid        );
			this.preparedStatement.setInt   (index++, retryCount     );
			this.preparedStatement.setString(index++, scheduleCode   );
			this.preparedStatement.setString(index++, msgCreateTime  );
			this.preparedStatement.setString(index++, institutionCode);
			this.preparedStatement.setString(index++, processCode    );
			this.preparedStatement.setString(index++, processType    );
			this.preparedStatement.setString(index++, userID         );
			this.preparedStatement.setString(index++, userName       );
			this.preparedStatement.setString(index++, sysConnCode    );
			this.preparedStatement.setString(index++, remoteIP       );
			this.preparedStatement.setString(index++, ruleCode       );
			this.preparedStatement.setString(index++, weblogicName   );
			this.preparedStatement.setString(index++, phaseStartTime );
			this.preparedStatement.setString(index++, phaseEndTime   );
			this.preparedStatement.setString(index++, status         );
			this.preparedStatement.setString(index++, errorDesc      );

			retValue = this.executeUpdate();
			logger.info("[ DB로그 ] ==> Master DB로그 INSERT 건수 : "+ retValue +"  ["+ uuid +" / "+ subUuid +"]");

			if (retValue == 0) throw new DAOException("BECEAICLG008");  //배치로그 Master 테이블 insert 건수가 0 건입니다.

		} catch (DAOException ex) {
			throw ex;
		} catch (Exception ex) {
			String errMsg = ExceptionUtil.getErrorCode(ex, "BECEAICLG009");  //배치로그 Master 테이블 insert 시 오류가 발생하였습니다.
			throw new DAOException(errMsg);
		} finally {
			disconnect();
		}
		return retValue;
	}


    /**
    * 1. 기능 : 배치 Job 단계 시작 시 Stage 로그를 insert 한다.
    * 2. 처리 개요 :
    * 3. 주의사항
    *
    * @param		msgDoc			배치메시지 Document
	* @return		Stage 로그 테이블의 insert Row 수
    * @exception	DAOException	DB insert 가 실패한 경우, insert 건수가 없는 경우
    **/
	public int insertLogStage(BatchDoc msgDoc, String logType, String errorDesc) throws DAOException {

		int       retValue = 0;
		int       index    = 0;

		String uuid            = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getUUID()                );  //UUID
		String subUuid         = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getSubUUID()               );  //SUB_UUID
		String layerCode       = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getLayerCode()           );  //Layer구분코드
		String subLayerCode    = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getSubLayerCode()          );  //Sub_Layer구분코드
		String ruleCode          = " ";
		String phaseCode         = " ";
		String phaseType         = " ";
		String flowClassName     = " ";
		String lengthTelegramId  = " ";
		String lengthClassName   = " ";
		String lengthMsgCode     = " ";
		String phaseSeq          = " ";
		String phaseTelegramId   = " ";
		String phaseClassName    = " ";
		String phaseMsgCode      = " ";
		String telegramTypeValue = " ";
		String bizCodeValue      = " ";
		String controlCodeValue  = " ";
		String responseCodeValue = " ";
		if (msgDoc.getBatchMsg().getPhaseinfo() != null) {
			ruleCode           = StringUtil.nvlTrim(msgDoc.getBatchMsg().getPhaseinfo().getRuleCode()         , " ");  //규칙코드
			phaseCode          = StringUtil.nvlTrim(msgDoc.getBatchMsg().getPhaseinfo().getPhaseCode()        , " ");  //단계코드
			phaseType          = StringUtil.nvlTrim(msgDoc.getBatchMsg().getPhaseinfo().getPhaseType()        , " ");  //단계유형 (SEND/RECV/END/EEND)
			flowClassName      = StringUtil.nvlTrim(msgDoc.getBatchMsg().getPhaseinfo().getFlowClassName()    , " ");  //유형별수행클래스
			lengthTelegramId   = StringUtil.nvlTrim(msgDoc.getBatchMsg().getPhaseinfo().getLengthTelegramID() , " ");  //전문결정TelegramID (RECV 일때 사용)
			lengthClassName    = StringUtil.nvlTrim(msgDoc.getBatchMsg().getPhaseinfo().getLengthClassName()  , " ");  //전문결정수행클래스 (RECV 일때 사용)
			lengthMsgCode      = StringUtil.nvlTrim(msgDoc.getBatchMsg().getPhaseinfo().getLengthMsgCode()    , " ");  //전문결정전문메시지코드 (RECV 일때 사용)
			phaseSeq           = StringUtil.nvlTrim(msgDoc.getBatchMsg().getPhaseinfo().getPhaseSeq()         , " ");  //단계순번
			phaseTelegramId    = StringUtil.nvlTrim(msgDoc.getBatchMsg().getPhaseinfo().getPhaseTelegramID()  , " ");  //단계TelegramID
			phaseClassName     = StringUtil.nvlTrim(msgDoc.getBatchMsg().getPhaseinfo().getPhaseClassName()   , " ");  //단계수행클래스
			phaseMsgCode       = StringUtil.nvlTrim(msgDoc.getBatchMsg().getPhaseinfo().getPhaseMsgCode()     , " ");  //단계전문메시지코드
			telegramTypeValue  = StringUtil.nvlTrim(msgDoc.getBatchMsg().getPhaseinfo().getTelegramTypeValue()," ");   //전문종별코드 값
			bizCodeValue       = StringUtil.nvlTrim(msgDoc.getBatchMsg().getPhaseinfo().getBizCodeValue()     ," ");   //거래구분코드 값
			controlCodeValue   = StringUtil.nvlTrim(msgDoc.getBatchMsg().getPhaseinfo().getControlCodeValue() ," ");   //업무관리코드 값
			responseCodeValue  = StringUtil.nvlTrim(msgDoc.getBatchMsg().getPhaseinfo().getResponseCodeValue()," ");   //응답코드 값
		}
		int    nodeCount       = msgDoc.getBatchMsg().getBody().getNodeCount();                                   //NodeCount
		String jobCode         = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getJobCode()        , " ");  //Job 테이블 FK
		String institutionCode = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getInstitutionCode(), " ");  //대외기관코드
		String processCode     = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getProcessCode()    , " ");  //Process 테이블 FK
		String processType     = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getProcessType()    , " ");  //Job 유형구분
		String bizCode         = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getBizCode()        , " ");  //거래구분코드
		String filePath        = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getFilePath()       , " ");  //파일패스
		String realFileName    = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getFileName()       , " ");  //실제파일명
		String renamedFileName = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getRenamedFileName(), " ");  //변경된파일명
		String weblogicName    = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getWLIServerName()    , " ");  //웹로직서버명
		String phaseStartTime  = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getPhaseStartTime()   , " ");  //단계시작시간
		String phaseEndTime    = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getPhaseEndTime()     , " ");  //단계종료시간

		String telegramHeader  = " ";
		String telegramBody    = " ";
		//DB로그 레벨이 '전문저장'인 경우 전문 설정
		if (LogManager.mBatchDBLogLevel != null && LogManager.mBatchDBLogLevel.equals(LogManager.BATCH_DBLOG_LEVEL_ALL)) {
			//telegramHeader     = StringUtil.nvlTrim(msgDoc.getEAIBatchMessage().getTelegramHeader()             , " ");  //전문Header
			//telegramBody       = StringUtil.nvlTrim(msgDoc.getEAIBatchMessage().getTelegramBody()               , " ");  //전문Body
			telegramHeader     = splitStringByByteSize(msgDoc.getBatchMsg().getTelegramHeader(), 1, 4000, " ")[0];  //전문Header
			telegramBody       = splitStringByByteSize(msgDoc.getBatchMsg().getTelegramBody()  , 1, 4000, " ")[0];  //전문Body
		}

		//파라미터로 받은 errorDesc 은 무시하고 batchMsgDod 에 있는 메시지를 저장한다.
		errorDesc              = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getErrorMsg()         , " ");   //에러메시지
        errorDesc              = tailStringByByteSize(errorDesc, LOG_STAGE_ERROR_DESC_FIELD_LENGTH, "(상위메시지절삭)...");  //길이 초과시 잘라냄
		if (!errorDesc.equals(" ")) logType = LogManager.LOG_TYPE_ERROR;

//		int seqNum = msgDoc.getEAIBatchMessage().getBody().getSeqNum();
//		int BlockNum = msgDoc.getEAIBatchMessage().getBody().getBlockNum();
//		logger.debug("[ DB로그 DEBUG ] ==> BlockNum[" +BlockNum + "]seqNum ["+ seqNum +"]");

//		if (  (1==0) && seqNum != 0 && seqNum != 1  && BlockNum != 0  ){
//			try {
//				this.connect(UPDATE_LAST_LOG_STAGE);
//				index = 1;
//				this.preparedStatement.setString(index++, ruleCode         );
//				this.preparedStatement.setString(index++, phaseCode        );
//				this.preparedStatement.setString(index++, phaseSeq         );
//				this.preparedStatement.setString(index++, phaseType        );
//				this.preparedStatement.setString(index++, flowClassName    );
//				this.preparedStatement.setString(index++, lengthTelegramId );
//				this.preparedStatement.setString(index++, lengthClassName  );
//				this.preparedStatement.setString(index++, lengthMsgCode    );
//				this.preparedStatement.setString(index++, phaseTelegramId  );
//				this.preparedStatement.setString(index++, phaseClassName   );
//				this.preparedStatement.setString(index++, phaseMsgCode     );
//				this.preparedStatement.setString(index++, telegramTypeValue);
//				this.preparedStatement.setString(index++, bizCodeValue     );
//				this.preparedStatement.setString(index++, controlCodeValue );
//				this.preparedStatement.setString(index++, responseCodeValue);
//				this.preparedStatement.setInt   (index++, nodeCount        );
//				this.preparedStatement.setString(index++, jobCode          );
//				this.preparedStatement.setString(index++, institutionCode  );
//				this.preparedStatement.setString(index++, processCode      );
//				this.preparedStatement.setString(index++, processType      );
//				this.preparedStatement.setString(index++, bizCode          );
//				this.preparedStatement.setString(index++, filePath         );
//				this.preparedStatement.setString(index++, realFileName     );
//				this.preparedStatement.setString(index++, renamedFileName  );
//				this.preparedStatement.setString(index++, weblogicName     );
//				this.preparedStatement.setString(index++, phaseStartTime   );
//				this.preparedStatement.setString(index++, phaseEndTime     );
//				this.preparedStatement.setString(index++, logType          );
//				this.preparedStatement.setString(index++, errorDesc        );
//				this.preparedStatement.setString(index++, telegramHeader   );
//				this.preparedStatement.setString(index++, telegramBody     );
//				this.preparedStatement.setString(index++, uuid             );
//				this.preparedStatement.setString(index++, subUuid          );
//				this.preparedStatement.setString(index++, layerCode        );
//				this.preparedStatement.setString(index++, subLayerCode     );
//				this.preparedStatement.setString(index++, uuid             );
//				this.preparedStatement.setString(index++, subUuid          );
//				this.preparedStatement.setString(index++, layerCode        );
//				this.preparedStatement.setString(index++, subLayerCode     );
//
//				retValue = this.executeUpdate();
//				logger.info("[ DB로그 ] ==> Stage  DB로그 UPDATE 건수 : "+ retValue +"  ["+ uuid +" / "+ layerCode +" / "+ subLayerCode +" / "+ nodeCount +"]");
//				
//			} catch (DAOException ex) {
//				throw ex;
//			}catch (Exception ex) {
//				String errMsg = ExceptionUtil.getErrorCode(ex, "BECEAICLG011");  //배치로그 Stage 테이블 insert 시 오류가 발생하였습니다.
//				throw new DAOException(errMsg);
//			}finally {
//				disconnect();
//			}
//			if (retValue > 0) return retValue;
//		}
		
		try {
			this.connect(INSERT_LOG_STAGE);
			index = 1;
			this.preparedStatement.setString(index++, uuid             );
			this.preparedStatement.setString(index++, subUuid          );
			this.preparedStatement.setString(index++, layerCode        );
			this.preparedStatement.setString(index++, subLayerCode     );
			this.preparedStatement.setString(index++, ruleCode         );
			this.preparedStatement.setString(index++, phaseCode        );
			this.preparedStatement.setString(index++, phaseSeq         );
			this.preparedStatement.setString(index++, phaseType        );
			this.preparedStatement.setString(index++, flowClassName    );
			this.preparedStatement.setString(index++, lengthTelegramId );
			this.preparedStatement.setString(index++, lengthClassName  );
			this.preparedStatement.setString(index++, lengthMsgCode    );
			this.preparedStatement.setString(index++, phaseTelegramId  );
			this.preparedStatement.setString(index++, phaseClassName   );
			this.preparedStatement.setString(index++, phaseMsgCode     );
			this.preparedStatement.setString(index++, telegramTypeValue);
			this.preparedStatement.setString(index++, bizCodeValue     );
			this.preparedStatement.setString(index++, controlCodeValue );
			this.preparedStatement.setString(index++, responseCodeValue);
			this.preparedStatement.setInt   (index++, nodeCount        );
			this.preparedStatement.setString(index++, jobCode          );
			this.preparedStatement.setString(index++, institutionCode  );
			this.preparedStatement.setString(index++, processCode      );
			this.preparedStatement.setString(index++, processType      );
			this.preparedStatement.setString(index++, bizCode          );
			this.preparedStatement.setString(index++, filePath         );
			this.preparedStatement.setString(index++, realFileName     );
			this.preparedStatement.setString(index++, renamedFileName  );
			this.preparedStatement.setString(index++, weblogicName     );
			this.preparedStatement.setString(index++, phaseStartTime   );
			this.preparedStatement.setString(index++, phaseEndTime     );
			this.preparedStatement.setString(index++, logType          );
			this.preparedStatement.setString(index++, errorDesc        );
			this.preparedStatement.setString(index++, telegramHeader   );
			this.preparedStatement.setString(index++, telegramBody     );

			retValue = this.executeUpdate();
			logger.info("[ DB로그 ] ==> Stage  DB로그 INSERT 건수 : "+ retValue +"  ["+ uuid +" / "+ layerCode +" / "+ subLayerCode +" / "+ nodeCount +"]");

			if (retValue == 0) throw new DAOException("BECEAICLG010");  //배치로그 Stage 테이블 insert 건수가 0 건입니다.
		} catch (DAOException ex) {
			logger.info("[ DB로그 ] ==> Stage  DB로그 INSERT 건수 : "+ retValue +"  ["+ uuid +" / "+ layerCode +" / "+ subLayerCode +" / "+ nodeCount +"]");
			try {
				this.prepareStatement(UPDATE_LOG_STAGE);
				index = 1;
				this.preparedStatement.setString(index++, ruleCode         );
				this.preparedStatement.setString(index++, phaseCode        );
				this.preparedStatement.setString(index++, phaseSeq         );
				this.preparedStatement.setString(index++, phaseType        );
				this.preparedStatement.setString(index++, flowClassName    );
				this.preparedStatement.setString(index++, lengthTelegramId );
				this.preparedStatement.setString(index++, lengthClassName  );
				this.preparedStatement.setString(index++, lengthMsgCode    );
				this.preparedStatement.setString(index++, phaseTelegramId  );
				this.preparedStatement.setString(index++, phaseClassName   );
				this.preparedStatement.setString(index++, phaseMsgCode     );
				this.preparedStatement.setString(index++, telegramTypeValue);
				this.preparedStatement.setString(index++, bizCodeValue     );
				this.preparedStatement.setString(index++, controlCodeValue );
				this.preparedStatement.setString(index++, responseCodeValue);
				this.preparedStatement.setString(index++, jobCode          );
				this.preparedStatement.setString(index++, institutionCode  );
				this.preparedStatement.setString(index++, processCode      );
				this.preparedStatement.setString(index++, processType      );
				this.preparedStatement.setString(index++, bizCode          );
				this.preparedStatement.setString(index++, filePath         );
				this.preparedStatement.setString(index++, realFileName     );
				this.preparedStatement.setString(index++, renamedFileName  );
				this.preparedStatement.setString(index++, weblogicName     );
				this.preparedStatement.setString(index++, phaseStartTime   );
				this.preparedStatement.setString(index++, phaseEndTime     );
				this.preparedStatement.setString(index++, logType          );
				this.preparedStatement.setString(index++, errorDesc        );
				this.preparedStatement.setString(index++, telegramHeader   );
				this.preparedStatement.setString(index++, telegramBody     );
				this.preparedStatement.setString(index++, uuid             );
				this.preparedStatement.setString(index++, subUuid          );
				this.preparedStatement.setString(index++, layerCode        );
				this.preparedStatement.setString(index++, subLayerCode     );
				this.preparedStatement.setInt   (index++, nodeCount        );
				
				retValue = this.executeUpdate();
				logger.info("[ DB로그 ] ==> Stage  DB로그 UPDATE 건수 : "+ retValue +"  ["+ uuid +" / "+ layerCode +" / "+ subLayerCode +" / "+ nodeCount +"]");

			} catch (DAOException ex1) {
				logger.debug("INSERT_LOG_STAGE -->\n" + INSERT_LOG_STAGE );
				logger.debug("UPDATE_LOG_STAGE -->\n" + UPDATE_LOG_STAGE );
				logger.debug("[insertLogStage]uuid             -->"+uuid             .length()+"["+uuid             +"]");
				logger.debug("[insertLogStage]subUuid          -->"+subUuid          .length()+"["+subUuid          +"]");
				logger.debug("[insertLogStage]layerCode        -->"+layerCode        .length()+"["+layerCode        +"]");
				logger.debug("[insertLogStage]subLayerCode     -->"+subLayerCode     .length()+"["+subLayerCode     +"]");
				logger.debug("[insertLogStage]ruleCode         -->"+ruleCode         .length()+"["+ruleCode         +"]");
				logger.debug("[insertLogStage]phaseCode        -->"+phaseCode        .length()+"["+phaseCode        +"]");
				logger.debug("[insertLogStage]phaseSeq         -->"+phaseSeq         .length()+"["+phaseSeq         +"]");
				logger.debug("[insertLogStage]phaseType        -->"+phaseType        .length()+"["+phaseType        +"]");
				logger.debug("[insertLogStage]flowClassName    -->"+flowClassName    .length()+"["+flowClassName    +"]");
				logger.debug("[insertLogStage]lengthTelegramId -->"+lengthTelegramId .length()+"["+lengthTelegramId +"]");
				logger.debug("[insertLogStage]lengthClassName  -->"+lengthClassName  .length()+"["+lengthClassName  +"]");
				logger.debug("[insertLogStage]lengthMsgCode    -->"+lengthMsgCode    .length()+"["+lengthMsgCode    +"]");
				logger.debug("[insertLogStage]phaseTelegramId  -->"+phaseTelegramId  .length()+"["+phaseTelegramId  +"]");
				logger.debug("[insertLogStage]phaseClassName   -->"+phaseClassName   .length()+"["+phaseClassName   +"]");
				logger.debug("[insertLogStage]phaseMsgCode     -->"+phaseMsgCode     .length()+"["+phaseMsgCode     +"]");
				logger.debug("[insertLogStage]telegramTypeValue-->"+telegramTypeValue.length()+"["+telegramTypeValue+"]");
				logger.debug("[insertLogStage]bizCodeValue     -->"+bizCodeValue     .length()+"["+bizCodeValue     +"]");
				logger.debug("[insertLogStage]controlCodeValue -->"+controlCodeValue .length()+"["+controlCodeValue +"]");
				logger.debug("[insertLogStage]responseCodeValue-->"+responseCodeValue.length()+"["+responseCodeValue+"]");
				logger.debug("[insertLogStage]nodeCount        -->["+nodeCount        +"]");
				logger.debug("[insertLogStage]jobCode          -->"+jobCode          .length()+"["+jobCode          +"]");
				logger.debug("[insertLogStage]institutionCode  -->"+institutionCode  .length()+"["+institutionCode  +"]");
				logger.debug("[insertLogStage]processCode      -->"+processCode      .length()+"["+processCode      +"]");
				logger.debug("[insertLogStage]processType      -->"+processType      .length()+"["+processType      +"]");
				logger.debug("[insertLogStage]bizCode          -->"+bizCode          .length()+"["+bizCode          +"]");
				logger.debug("[insertLogStage]filePath         -->"+filePath         .length()+"["+filePath         +"]");
				logger.debug("[insertLogStage]realFileName     -->"+realFileName     .length()+"["+realFileName     +"]");
				logger.debug("[insertLogStage]renamedFileName  -->"+renamedFileName  .length()+"["+renamedFileName  +"]");
				logger.debug("[insertLogStage]weblogicName     -->"+weblogicName     .length()+"["+weblogicName     +"]");
				logger.debug("[insertLogStage]phaseStartTime   -->"+phaseStartTime   .length()+"["+phaseStartTime   +"]");
				logger.debug("[insertLogStage]phaseEndTime     -->"+phaseEndTime     .length()+"["+phaseEndTime     +"]");
				logger.debug("[insertLogStage]logType          -->"+logType          .length()+"["+logType          +"]");
				logger.debug("[insertLogStage]errorDesc        -->"+errorDesc        .length()+"["+errorDesc        +"]");
				logger.debug("[insertLogStage]telegramHeader   -->"+telegramHeader   .length()+"["+telegramHeader   +"]");
				logger.debug("[insertLogStage]telegramBody     -->"+telegramBody     .length()+"["+telegramBody     +"]");
				
				throw ex1;
			} catch (Exception ex2) {
				String errMsg = ExceptionUtil.getErrorCode(ex2, "BECEAICLG011");  //배치로그 Stage 테이블 insert 시 오류가 발생하였습니다.
				throw new DAOException(errMsg);
			}
		} catch(Exception ex3){
			String errMsg = ExceptionUtil.getErrorCode(ex3, "BECEAICLG011");  //배치로그 Stage 테이블 insert 시 오류가 발생하였습니다.
			throw new DAOException(errMsg);
		} finally {
			disconnect();
		}
		
		return retValue;
	}


    /**
    * 1. 기능 : 배치 Job  종료 시 (정상종료, 에러종료, 사용자중지) Master 로그를 update 한다.
    * 2. 처리 개요 :
    * 3. 주의사항
    *
    * @param		msgDoc			배치메시지 Document
	* @return		Master 로그 테이블의 update Row 수
    * @exception	DAOException	DB update 가 실패한 경우, update 건수가 없는 경우
    **/
	public int updateLogMasterFinish(BatchDoc msgDoc, String logType, String errorDesc) throws DAOException {

		int       retValue = 0;
		int       index    = 0;

		String uuid            = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getUUID()                );  //UUID
		String subUuid         = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getSubUUID()               );  //sub UUID
		String phaseEndTime    = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getPhaseEndTime()     , " ");  //단계종료시간

		//파라미터로 받은 errorDesc 은 무시하고 batchMsgDod 에 있는 메시지를 저장한다.
		errorDesc              = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getErrorMsg()         , " ");   //에러메시지
        errorDesc              = tailStringByByteSize(errorDesc, LOG_MASTER_ERROR_DESC_FIELD_LENGTH, "(상위메시지절삭)...");  //길이 초과시 잘라냄

		try {

			this.connect(UPDATE_MASTER_LOG_FINISH);

			index = 1;
			this.preparedStatement.setString(index++, phaseEndTime   );
			this.preparedStatement.setString(index++, logType        );		//처리결과 코드 (logType 값이랑 동일)
			this.preparedStatement.setString(index++, errorDesc      );
			this.preparedStatement.setString(index++, uuid           );
			this.preparedStatement.setString(index++, subUuid        );

			retValue = this.executeUpdate();
			logger.info("[ DB로그 ] ==> Master DB로그 작업종료 UPDATE 건수 : "+ retValue +"  ["+ uuid +", / "+ subUuid +"]");

			if (retValue == 0) {
				String errMsg = ExceptionUtil.getErrorCode("BECEAICLG012", new String[] {uuid, subUuid});  //배치로그 Master 테이블 종료 update 건수가 0 건입니다.(UUID: ?, subUUID: ?)
				throw new DAOException(errMsg);
			}

		} catch (DAOException ex) {
			throw ex;
		} catch (Exception ex) {
			String errMsg = ExceptionUtil.getErrorCode(ex, "BECEAICLG013", new String[] {uuid, subUuid});  //배치로그 Master 테이블 종료 update 시 오류가 발생하였습니다.(UUID: ?, subUUID: ?)
			throw new DAOException(errMsg);
		} finally {
			disconnect();
		}
		return retValue;
	}


    /**
    * 1. 기능 : 배치 Job  단계 진행시 로그 Master의 필드가 결정되는 경우 로그 Master를 update 한다.
    * 2. 처리 개요 :
    * 3. 주의사항
    *
    * @param		msgDoc			배치메시지 Document
	* @return		Master 로그 테이블의 update Row 수
    * @exception	DAOException	DB update 가 실패한 경우, update 건수가 없는 경우
    **/
	public int updateLogMaster(BatchDoc msgDoc) throws DAOException {

		int       retValue = 0;
		int       index    = 0;

		String uuid            = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getUUID()           );  //UUID
		String subUuid         = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getSubUUID()          );  //sub UUID
		String scheduleCode    = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getScheduleCode()   );  //스케쥴코드
		String institutionCode = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getInstitutionCode());  //대외기관코드
		String processCode     = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getProcessCode()    );  //Process 테이블 FK
		String processType     = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getProcessType()    );  //Job 유형구분
		String userID          = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getUserID()         );  //사용자ID
		String userName        = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getUserName()       );  //사용자명
		String sysConnCode     = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getSystemConnCode() );  //연결정보ID
		String ruleCode        = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getRuleCode()       );  //RuleCode
		String flowStartTime   = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getPhaseStartTime()   );  //단계시작시간

		//진행상태: ScheduleHandler 에서 호출된 경우 '시작'상태로 UPDATE, 그 외 '대기'상태로 UPDATE
		String subLayerCode    = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getSubLayerCode()     );  //Sub_Layer구분코드
		String status          = subLayerCode.equals(CommonKeys.SUB_LAYER_SCHEDULER_PROCESSING)? LogManager.LOG_TYPE_START : LogManager.LOG_TYPE_QUEUE;

		try {

			this.connect(UPDATE_MASTER_LOG_CONTINUE);

			index = 1;
			this.preparedStatement.setString(index++, scheduleCode   );
			this.preparedStatement.setString(index++, institutionCode);
			this.preparedStatement.setString(index++, processCode    );
			this.preparedStatement.setString(index++, processType    );
			this.preparedStatement.setString(index++, userID         );
			this.preparedStatement.setString(index++, userName       );
			this.preparedStatement.setString(index++, sysConnCode    );
			this.preparedStatement.setString(index++, ruleCode       );
			this.preparedStatement.setString(index++, flowStartTime  );
			this.preparedStatement.setString(index++, status         );
			this.preparedStatement.setString(index++, uuid           );
			this.preparedStatement.setString(index++, subUuid        );

			retValue = this.executeUpdate();
			logger.info("[ DB로그 ] ==> Master DB로그 추가 정의값 UPDATE 건수 : "+ retValue +"  ["+ uuid +", / "+ subUuid +"]");

			if (retValue == 0) {
				String errMsg = ExceptionUtil.getErrorCode("BECEAICLG014", new String[] {uuid, subUuid});  //배치로그 Master 테이블 진행 update 건수가 0 건입니다.(UUID: ?, subUUID: ?)
				throw new DAOException(errMsg);
			}

		} catch (DAOException ex) {
			throw ex;
		} catch (Exception ex) {
			String errMsg = ExceptionUtil.getErrorCode(ex, "BECEAICLG015", new String[] {uuid, subUuid});  //배치로그 Master 테이블 진행 update 시 오류가 발생하였습니다.(UUID: ?, subUUID: ?)
			throw new DAOException(errMsg);
		} finally {
			disconnect();
		}
		return retValue;
	}

	public int existLogFileCount(BatchDoc msgDoc) throws DAOException {

		ResultSet rs = null;
		int index    = 0;

		String uuid            = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getUUID()    );  //UUID
		String subUuid         = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getSubUUID()   );  //sub UUID
		String fileName        = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getFileName());  //실제파일명

		try {

			this.connect(SELECT_FILE_LOG_EXIST_COUNT);
			//logger.debug("{ LogDAO.existLogFileCount() } 수행 SQL 문 : \n"+ SELECT_FILE_LOG_EXIST_COUNT);

			index = 1;
			this.preparedStatement.setString(index++, uuid     );	//logger.debug("{ LogDAO.existLogFileCount() } 바인드("+(index-1)+") : ["+ uuid     +"]");
			this.preparedStatement.setString(index++, subUuid  );	//logger.debug("{ LogDAO.existLogFileCount() } 바인드("+(index-1)+") : ["+ subUuid  +"]");
			this.preparedStatement.setString(index++, fileName  );	//logger.debug("{ LogDAO.existLogFileCount() } 바인드("+(index-1)+") : ["+ fileName +"]");

			rs = executeQuery();
			rs.next();
			int logFileCnt = rs.getInt("LogFileCnt");
			logger.info("[ DB로그 ] ==> File DB로그 존재 건수 : "+ logFileCnt +"  ["+ uuid +" / "+ subUuid +" / "+ fileName +"]");

			return logFileCnt;


		} catch (DAOException ex) {
			throw ex;
		} catch (Exception ex) {
			String errMsg = ExceptionUtil.getErrorCode(ex, "BECEAICLG020", new String[] {uuid, subUuid, fileName});
			throw new DAOException(errMsg);  //배치 DB로그 File 데이터 존재여부 조회시 오류가 발생하였습니다. [UUID: {1}] [SUB_UUID: {2}]
		} finally {
			disconnect();
		}
	}

	public int insertLogFile(BatchDoc msgDoc) throws DAOException {

		int       retValue = 0;
		int       index    = 0;

		String uuid            = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getUUID()                );  //UUID
		String subUuid         = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getSubUUID()               );  //SUB_UUID
		String jobCode         = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getJobCode()        , " ");  //Job 테이블 FK
		String institutionCode = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getInstitutionCode(), " ");  //대외기관코드
		String processCode     = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getProcessCode()    , " ");  //Process 테이블 FK
		String processType     = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getProcessType()    , " ");  //Job 유형구분
		String bizCode         = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getBizCode()        , " ");  //거래구분코드
		String filePath        = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getFilePath()       , " ");  //파일패스
		String fileName        = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getFileName()       , " ");  //실제파일명
		String renamedFileName = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getRenamedFileName(), " ");  //변경된파일명
		long   recCnt          =                    msgDoc.getBatchMsg().getHeader().getTotRecCnt();              //자료건수
		long   fileSize        =                    msgDoc.getBatchMsg().getHeader().getFileSize();               //파일사이즈
		String weblogicName    = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getWLIServerName()    , " ");  //웹로직서버명
		String phaseStartTime  = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getPhaseStartTime()   , " ");  //단계시작시간
		String phaseEndTime    = " ";                                                                                    //단계종료시간 (공백 설정)
		String resultCode      = LogManager.LOG_TYPE_START;                                                              //처리구분코드 ('시작'값 설정)
		String errorDesc       = " ";                                                                                    //에러메시지 (공백 설정)
		String hdrInfoName     = StringUtil.nvl(msgDoc.getBatchMsg().getHeader().getHdrInfoName()    , " ");  //체크파일내용
		String fileHeader      = StringUtil.nvl(msgDoc.getBatchMsg().getFileHeader()                 , " ");  //파일Header
		String fileTrailer     = StringUtil.nvl(msgDoc.getBatchMsg().getFileTrailer()                , " ");  //파일Trailer
//		if ( fileHeader.getBytes().length > 4000){
//			fileHeader = fileHeader.substring(0, 4000);
//		}
//		if ( fileTrailer.getBytes().length > 4000){
//			fileTrailer = fileTrailer.substring(0, 4000);
//		}

		if ( fileHeader.getBytes().length > 4000){
			fileHeader = new String(fileHeader.getBytes(), 0, 2000);//20250312
		}
		if ( fileTrailer.getBytes().length > 4000){
			fileTrailer = new String(fileTrailer.getBytes(), 0, 2000);//20250312
		}
		try {

			this.connect(INSERT_LOG_FILE);

			index = 1;
			this.preparedStatement.setString(index++, uuid           );			
			this.preparedStatement.setString(index++, subUuid        );			
			this.preparedStatement.setString(index++, processCode    );			
			this.preparedStatement.setString(index++, institutionCode);			
			this.preparedStatement.setString(index++, jobCode        );			
			this.preparedStatement.setString(index++, processType    );			
			this.preparedStatement.setString(index++, bizCode        );			
			this.preparedStatement.setString(index++, filePath       );			
			this.preparedStatement.setString(index++, fileName       );			
			this.preparedStatement.setString(index++, renamedFileName);			
			this.preparedStatement.setLong  (index++, recCnt         );			
			this.preparedStatement.setLong  (index++, fileSize       );			
			this.preparedStatement.setString(index++, weblogicName   );			
			this.preparedStatement.setString(index++, phaseStartTime );			
			this.preparedStatement.setString(index++, phaseEndTime   );			
			this.preparedStatement.setString(index++, resultCode     );			
			this.preparedStatement.setString(index++, errorDesc      );			
			this.preparedStatement.setString(index++, hdrInfoName    );			
			this.preparedStatement.setString(index++, fileHeader     );			
			this.preparedStatement.setString(index++, fileTrailer    );			

			retValue = this.executeUpdate();
			logger.info("[ DB로그 ] ==> File DB로그 INSERT 건수 : "+ retValue +"  ["+ uuid +" / "+ subUuid +" / "+ fileName +"]");

			if (retValue == 0) {
				String errMsg = ExceptionUtil.getErrorCode("BECEAICLG021", new String[] {uuid, subUuid, fileName});
				throw new DAOException(errMsg);  //배치로그 File 테이블 insert 건수가 0 건입니다. [UUID: {1}] [SUB_UUID: {2}] [FILE_NAME: {3}]
			}

			return retValue;


		} catch (DAOException ex) {
			logger.debug( "LogDAO.insertLogFile() >>> 수행 SQL 문 : \n"+ INSERT_LOG_FILE);
			logger.debug( "LogDAO.insertLogFile() >>>[uuid           ][" + uuid            + "]");
			logger.debug( "LogDAO.insertLogFile() >>>[subUuid        ][" + subUuid         + "]");
			logger.debug( "LogDAO.insertLogFile() >>>[processCode    ][" + processCode     + "]");
			logger.debug( "LogDAO.insertLogFile() >>>[institutionCode][" + institutionCode + "]");
			logger.debug( "LogDAO.insertLogFile() >>>[jobCode        ][" + jobCode         + "]");
			logger.debug( "LogDAO.insertLogFile() >>>[processType    ][" + processType     + "]");
			logger.debug( "LogDAO.insertLogFile() >>>[bizCode        ][" + bizCode         + "]");
			logger.debug( "LogDAO.insertLogFile() >>>[filePath       ][" + filePath        + "]");
			logger.debug( "LogDAO.insertLogFile() >>>[fileName       ][" + fileName        + "]");
			logger.debug( "LogDAO.insertLogFile() >>>[renamedFileName][" + renamedFileName + "]");
			logger.debug( "LogDAO.insertLogFile() >>>[recCnt         ][" + recCnt          + "]");
			logger.debug( "LogDAO.insertLogFile() >>>[fileSize       ][" + fileSize        + "]");
			logger.debug( "LogDAO.insertLogFile() >>>[weblogicName   ][" + weblogicName    + "]");
			logger.debug( "LogDAO.insertLogFile() >>>[phaseStartTime ][" + phaseStartTime  + "]");
			logger.debug( "LogDAO.insertLogFile() >>>[phaseEndTime   ][" + phaseEndTime    + "]");
			logger.debug( "LogDAO.insertLogFile() >>>[resultCode     ][" + resultCode      + "]");
			logger.debug( "LogDAO.insertLogFile() >>>[errorDesc      ][" + errorDesc       + "]");
			logger.debug( "LogDAO.insertLogFile() >>>[fileHeader     ][" + fileHeader      + "]");
			logger.debug( "LogDAO.insertLogFile() >>>[fileTrailer    ][" + fileTrailer     + "]");

			throw ex;
		} catch (Exception ex) {
			String errMsg = ExceptionUtil.getErrorCode(ex, "BECEAICLG022", new String[] {uuid, subUuid,});
			throw new DAOException(errMsg);  //배치로그 File 테이블 insert 시 오류가 발생하였습니다. [UUID: {1}] [SUB_UUID: {2}] [FILE_NAME: {3}]
		} finally {
			disconnect();
		}
	}

	public int updateLogFileRetry(BatchDoc msgDoc) throws DAOException {

		int       retValue = 0;
		int       index    = 0;

		String uuid            = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getUUID()           );  //UUID
		String subUuid         = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getSubUUID()          );  //sub UUID
		String jobCode         = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getJobCode()        );  //Job 테이블 FK
		String bizCode         = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getBizCode()        );  //거래구분코드
		String filePath        = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getFilePath()       );  //파일패스
		String fileName        = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getFileName()       );  //실제파일명
		String renamedFileName = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getRenamedFileName());  //변경된파일명
		long   recCnt          = msgDoc.getBatchMsg().getHeader().getTotRecCnt();                            //자료건수
		long   fileSize        = msgDoc.getBatchMsg().getHeader().getFileSize();                             //파일사이즈
		String phaseStartTime  = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getPhaseStartTime()   );  //단계시작시간
		String phaseEndTime    = " ";                                                                        //단계종료시간 (공백 설정)
		String resultCode      = LogManager.LOG_TYPE_START;                                                  //처리구분코드 ('시작'값 설정)
		String errorDesc       = " ";                                                                        //에러메시지 (공백 설정)
		String hdrInfoName     = StringUtil.nvl(msgDoc.getBatchMsg().getHeader().getHdrInfoName()        );  //체크파일내용
		String fileHeader      = StringUtil.nvl(msgDoc.getBatchMsg().getFileHeader()                     );  //파일Header
		String fileTrailer     = StringUtil.nvl(msgDoc.getBatchMsg().getFileTrailer()                    );  //파일Trailer

//		if ( fileHeader.getBytes().length > 4000){
//			fileHeader = fileHeader.substring(0, 4000);
//		}
//		if ( fileTrailer.getBytes().length > 4000){
//			fileTrailer = fileTrailer.substring(0, 4000);
//		}
		if ( fileHeader.getBytes().length > 4000){
			fileHeader = new String(fileHeader.getBytes(), 0, 2000);//20250312
		}
		if ( fileTrailer.getBytes().length > 4000){
			fileTrailer = new String(fileTrailer.getBytes(), 0, 2000);//20250312
		}

		try {

			this.connect(UPDATE_FILE_LOG_RETRY);

			index = 1;
			this.preparedStatement.setString(index++, jobCode        );
			this.preparedStatement.setString(index++, bizCode        );
			this.preparedStatement.setString(index++, filePath       );
			this.preparedStatement.setString(index++, renamedFileName);
			this.preparedStatement.setLong  (index++, recCnt         );
			this.preparedStatement.setLong  (index++, fileSize       );
			this.preparedStatement.setString(index++, phaseStartTime );
			this.preparedStatement.setString(index++, phaseEndTime   );
			this.preparedStatement.setString(index++, resultCode     );
			this.preparedStatement.setString(index++, errorDesc      );
			this.preparedStatement.setString(index++, hdrInfoName     );
			this.preparedStatement.setString(index++, fileHeader     );
			this.preparedStatement.setString(index++, fileTrailer    );
			this.preparedStatement.setString(index++, uuid           );
			this.preparedStatement.setString(index++, subUuid        );
			this.preparedStatement.setString(index++, fileName       );

			retValue = this.executeUpdate();
			logger.info("[ DB로그 ] ==> File DB로그 재시도 UPDATE 건수 : "+ retValue +"  ["+ uuid +" / "+ subUuid +" / "+ fileName +"]");

			if (retValue == 0) {
				String errMsg = ExceptionUtil.getErrorCode("BECEAICLG023", new String[] {uuid, subUuid, fileName});
				throw new DAOException(errMsg);  //배치로그 File 테이블 종료 update 건수가 0 건입니다. [UUID: {1}] [SUB_UUID: {2}] [FILE_NAME: {3}]
			}
			return retValue;

		} catch (DAOException ex) {
			throw ex;
		} catch (Exception ex) {
			String errMsg = ExceptionUtil.getErrorCode(ex, "BECEAICLG024", new String[] {uuid, subUuid, fileName});
			throw new DAOException(errMsg);  //배치로그 File 테이블 종료 update 시 오류가 발생하였습니다. [UUID: {1}] [SUB_UUID: {2}] [FILE_NAME: {3}]
		} finally {
			disconnect();
		}
	}

	public int updateLogFileFinish(BatchDoc msgDoc, String logType, String errorDesc) throws DAOException {

		int       retValue = 0;
		int       index    = 0;

		String uuid            = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getUUID()           );  //UUID
		String subUuid         = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getSubUUID()          );  //sub UUID
		String jobCode         = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getJobCode()        );  //Job 테이블 FK
		String bizCode         = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getBizCode()        );  //거래구분코드
		String filePath        = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getFilePath()       );  //파일패스
		String fileName        = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getFileName()       );  //실제파일명
		String renamedFileName = StringUtil.nvlTrim(msgDoc.getBatchMsg().getHeader().getRenamedFileName());  //변경된파일명
		long   recCnt          = msgDoc.getBatchMsg().getHeader().getTotRecCnt();                            //자료건수
		long   fileSize        = msgDoc.getBatchMsg().getHeader().getFileSize();                             //파일사이즈
		String phaseEndTime    = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getPhaseEndTime()     );  //단계종료시간
		String hdrInfoName     = StringUtil.nvl(msgDoc.getBatchMsg().getHeader().getHdrInfoName()        );  //체크파일내용
		String fileHeader      = StringUtil.nvl(msgDoc.getBatchMsg().getFileHeader()                     );  //파일Header
		String fileTrailer     = StringUtil.nvl(msgDoc.getBatchMsg().getFileTrailer()                    );  //파일Trailer

//		if ( fileHeader.getBytes().length > 4000){
//			fileHeader = fileHeader.substring(0, 4000);
//		}
//		if ( fileTrailer.getBytes().length > 4000){
//			fileTrailer = fileTrailer.substring(0, 4000);
//		}
		if ( fileHeader.getBytes().length > 4000){
			fileHeader = new String(fileHeader.getBytes(), 0, 2000);//20250312
		}
		if ( fileTrailer.getBytes().length > 4000){
			fileTrailer = new String(fileTrailer.getBytes(), 0, 2000);//20250312
		}

		//파라미터로 받은 errorDesc 은 무시하고 batchMsgDod 에 있는 메시지를 저장한다.
		errorDesc              = StringUtil.nvlTrim(msgDoc.getBatchMsg().getBody().getErrorMsg()         , " ");   //에러메시지
        errorDesc              = tailStringByByteSize(errorDesc, LOG_FILE_ERROR_DESC_FIELD_LENGTH, "(상위메시지절삭)...");  //길이 초과시 잘라냄

		try {

			this.connect(UPDATE_FILE_LOG_FINISH);

			index = 1;
			this.preparedStatement.setString(index++, jobCode        );
			this.preparedStatement.setString(index++, bizCode        );
			this.preparedStatement.setString(index++, filePath       );
			this.preparedStatement.setString(index++, renamedFileName);
			this.preparedStatement.setLong  (index++, recCnt         );
			this.preparedStatement.setLong  (index++, fileSize       );
			this.preparedStatement.setString(index++, phaseEndTime   );
			this.preparedStatement.setString(index++, logType        );
			this.preparedStatement.setString(index++, errorDesc      );
			this.preparedStatement.setString(index++, hdrInfoName     );
			this.preparedStatement.setString(index++, fileHeader     );
			this.preparedStatement.setString(index++, fileTrailer    );
			this.preparedStatement.setString(index++, uuid           );
			this.preparedStatement.setString(index++, subUuid        );
			this.preparedStatement.setString(index++, fileName       );

			retValue = this.executeUpdate();
			logger.info("[ DB로그 ] ==> File DB로그 작업종료 UPDATE 건수 : "+ retValue +"  ["+ uuid +" / "+ subUuid +" / "+ fileName +"]");

			if (retValue == 0) {
				String errMsg = ExceptionUtil.getErrorCode("BECEAICLG025", new String[] {uuid, subUuid, fileName});
				throw new DAOException(errMsg); //배치로그 File 테이블 종료 update 건수가 0 건입니다. [UUID: {1}] [SUB_UUID: {2}] [FILE_NAME: {3}]
			}
			return retValue;

		} catch (DAOException ex) {
			logger.error("updateLogFileFinish 에러 발생 uuid:["+ uuid + "], subuuid:[" + subUuid + "],fileName:["+fileName+"]");
			logger.debug("UPDATE_FILE_LOG_FINISH :" + UPDATE_FILE_LOG_FINISH);
			logger.debug("jobCode        ->[" + jobCode         + "]");
			logger.debug("bizCode        ->[" + bizCode         + "]");
			logger.debug("filePath       ->[" + filePath        + "]");
			logger.debug("renamedFileName->[" + renamedFileName + "]");
			logger.debug("recCnt         ->[" + recCnt          + "]");
			logger.debug("fileSize       ->[" + fileSize        + "]");
			logger.debug("phaseEndTime   ->[" + phaseEndTime    + "]");
			logger.debug("logType        ->[" + logType         + "]");
			logger.debug("errorDesc      ->[" + errorDesc       + "]");
			logger.debug("fileHeader     ->[" + fileHeader      + "]");
			logger.debug("fileTrailer    ->[" + fileTrailer     + "]");
			logger.debug("uuid           ->[" + uuid            + "]");
			logger.debug("subUuid        ->[" + subUuid         + "]");
			logger.debug("fileName       ->[" + fileName        + "]");
			throw ex;
		} catch (Exception ex) {
			String errMsg = ExceptionUtil.getErrorCode(ex, "BECEAICLG026", new String[] {uuid, subUuid, fileName});
			throw new DAOException(errMsg);  //배치로그 File 테이블 종료 update 시 오류가 발생하였습니다. [UUID: {1}] [SUB_UUID: {2}] [FILE_NAME: {3}]
		} finally {
			disconnect();
		}
	}


    /**
    * 1. 기능 : 문자열을 주어진 크기의 Byte 길이로 주어진 분할개수 만큼 분할해서 배열로 리턴한다.
    * 2. 처리 개요 :
    * 3. 주의사항
    *
    * @param		srcString			소스 문자열
    * @param		splitCount			분할 개수
    * @param		splitByteSize		분할 Byte 길이
    * @param		defaultValue		소스 문자열이 분할 개수에 못미치는 경우 디폴트 문자열
	* @return		소스 문자열을 분할 Byte 길이로 분할 개수 만큼 분할된 배열
    **/
	private static String[] splitStringByByteSize(String srcString, int splitCount, int splitByteSize, String defaultValue) {

		//파라미터 오류 체크
		if (splitCount <= 0 || splitByteSize <= 0) return null;
		if (defaultValue != null && defaultValue.getBytes().length > splitByteSize) return null;

		//리턴 배열 생성
		String[] splitArray = new String[splitCount];
		for (int i=0; i<splitArray.length; i++) splitArray[i] = defaultValue;	//디폴트값 설정

		//분할 저장 배열 index
		int splitIndex = 0;

		//소스 String이 공백이면 디폴트배열 리턴
		if (srcString == null || srcString.equals("")) return splitArray;

		//소스 byte 배열 생성
		byte[] srcByteArray = srcString.getBytes();
		int    srcIndex     = 0;	//소스 byte 배열의 현재 index
		int    leftByteSize = 0;	//소스 byte 배열

		//분할 수행 (분할개수만큼 완료되지 않았고, 소스배열에 분할할 값이 남아있으면 분할 수행)
		while (splitIndex < splitArray.length && (leftByteSize = srcByteArray.length - srcIndex) > 0) {

			//배열 복사 길이 계산
			//(분할위치가 한글을 깨지게 하는위치인지 체크하여 깨지는 위치이면 1 byte 적게 복사)
			int copyByteSize = (leftByteSize < splitByteSize)? leftByteSize : splitByteSize - (StringUtil.isCrackedHangleIndex(srcByteArray, srcIndex+splitByteSize)? 1 : 0);

			//배열 복사
			byte[] destByteArray = new byte[copyByteSize];
			System.arraycopy(srcByteArray, srcIndex, destByteArray, 0, copyByteSize);
			//목적 배열에 String으로 저장
			splitArray[splitIndex++] = new String(destByteArray);
			srcIndex += copyByteSize;

			//logger.debug(splitArray[splitIndex-1]);  //잘라낸 데이터 로그 프린트
		}

		return splitArray;
	}
    
    //문자열이 byteSize를 초과하면 byteSize 만큼의 tail 문자열을 리턴한다.
    //(옵션) tail 된 경우 맨앞에 특정문자열을 붙일 수 있다. 예) "(앞문자열절삭)"
    private static String tailStringByByteSize(String srcString, int byteSize, String truncPrefixMsg) {
		if (srcString == null || byteSize <= 0) return srcString;
        
        byte[] srcByteArray = srcString.getBytes();
        int offset = srcByteArray.length - byteSize;
        if (offset <= 0) return srcString;  //잘라낼 필요가 없으면 그대로 리턴
        
        if (StringUtil.isCrackedHangleIndex(srcByteArray, offset) == true) offset++;
        int tailLength = srcByteArray.length - offset;  //offset 부터 문자열 끝까지
        String tailString = new String(srcByteArray, offset, tailLength);
        
        if (truncPrefixMsg == null) truncPrefixMsg = "";
        offset = truncPrefixMsg.getBytes().length;
        if (offset > 0 && offset < tailLength) {
            byte[] tailByteArray = tailString.getBytes();
            if (StringUtil.isCrackedHangleIndex(tailByteArray, offset) == true) offset++;
            tailString = truncPrefixMsg + new String(tailByteArray, offset, tailByteArray.length - offset);
        }
        
        return tailString;
    }

    public ArrayList<JobFileTransferVO> getFileLogSuccess() throws DAOException {

		try {

			this.connect(SELECT_FILE_LOG_SUCCESS);
			//logger.debug("{ LogDAO.getFileToolLogSuccess() } 수행 SQL 문 : \n"+ SELECT_FILE_TOOL_LOG_SUCCESS);

			ResultSet rs = executeQuery();
			ArrayList<JobFileTransferVO> alist = new ArrayList<JobFileTransferVO>();
			while (rs.next()) {
				JobFileTransferVO transLog = new JobFileTransferVO();
				transLog.setBjobBzwkDstcd    (rs.getString("BjobBzwkDstcd"    ));
				transLog.setOsidInstiDstcd   (rs.getString("OsidInstiDstcd"   ));
				transLog.setBjobTranDstcdName(rs.getString("BjobTranDstcdName"));
				transLog.setBjobMsgDstcd     (rs.getString("BjobMsgDstcd"     ));
				transLog.setSendRecvYn       (rs.getString("BjobPtrnDstcd"    ).substring(1,2));
				transLog.setSndrcvStartHMS   (rs.getString("FileTrsmtStartHMS").substring(8,12));
				transLog.setSndrcvEndHMS     (rs.getString("FileTrsmtEndHMS"  ).substring(8,12));
				
				alist.add(transLog);
			}
            return alist;


		} catch (DAOException ex) {
			throw ex;
		} catch (Exception e) {
        	String errMsg = ("당일 거래 로그  조회 중에 오류가 발생했습니다. - "+e.getMessage());
			throw new DAOException(errMsg);
		} finally {
			disconnect();
		}
	}

	public String getFileNameSeq(String procCode, String instiCode, String fileName, boolean flag) throws DAOException{

		ResultSet rs = null;
		int index    = 0;

		try {
			String sql = SELECT_FILE_NAME_SEQ;
			if ( !flag )
				sql = SELECT_RENAMED_FILE_NAME_SEQ;

			this.connect(sql); //
			logger.debug("{ LogDAO.getFileNameSeq() } 수행 SQL 문 : \n"+ SELECT_FILE_NAME_SEQ);

			index = 1;
			this.preparedStatement.setString(index++, procCode        );	
			logger.debug("{ LogDAO.getFileNameSeq() } 바인드("+(index-1)+") : ["+ procCode  +"]");
			this.preparedStatement.setString(index++, instiCode     );
			logger.debug("{ LogDAO.getFileNameSeq() } 바인드("+(index-1)+") : ["+ instiCode +"]");
			this.preparedStatement.setString(index++, fileName        );
			logger.debug("{ LogDAO.getFileNameSeq() } 바인드("+(index-1)+") : ["+ fileName  +"]");

			rs = executeQuery();

			rs.next();

			return rs.getString(1);

		} catch (Exception ex) {
			return "001";
		} finally {
			disconnect();
		}
	}

	public boolean getFileLogSuccessCheck(String procCode, String instiCode, String bizCode, String fileName) throws DAOException{

		ResultSet rs = null;
		int index    = 0;

		String sql = SELECT_FILE_LOG_SUCCESS_COUNT;
		try {

			this.connect(sql);
			logger.debug("{ LogDAO.getFileLogSuccessCheck() } 수행 SQL 문 : \n"+ SELECT_FILE_LOG_SUCCESS_COUNT);

			index = 1;
			this.preparedStatement.setString(index++, procCode        );	
			logger.debug("{ LogDAO.getFileLogSuccessCheck() } 바인드("+(index-1)+") : ["+ procCode  +"]");
			this.preparedStatement.setString(index++, instiCode     );
			logger.debug("{ LogDAO.getFileLogSuccessCheck() } 바인드("+(index-1)+") : ["+ instiCode +"]");
			this.preparedStatement.setString(index++, bizCode     );
			logger.debug("{ LogDAO.getFileLogSuccessCheck() } 바인드("+(index-1)+") : ["+ instiCode +"]");
			this.preparedStatement.setString(index++, fileName        );
			logger.debug("{ LogDAO.getFileLogSuccessCheck() } 바인드("+(index-1)+") : ["+ fileName  +"]");

			rs = executeQuery();

			rs.next();

			return (rs.getInt(1) > 0) ? true : false;

		} catch (Exception e) {
        	String errMsg = ("당일 거래 로그  조회 중에 오류가 발생했습니다. - "+e.getMessage());
			throw new DAOException(errMsg);
		} finally {
			disconnect();
		}
	}
}
