package com.eactive.eai.adapter.ftp;

import java.io.File;
import java.io.IOException;
import java.net.Socket;
import java.nio.file.Files;
import java.util.Properties;

import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.util.Timeout;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.core5.http.ContentType;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTPFile;
import org.quartz.JobKey;
import org.quartz.SchedulerException;
import org.quartz.impl.matchers.GroupMatcher;
import com.eactive.eai.common.util.Logger;

import com.eactive.eai.adapter.socket.config.ConfigurationContext;
import com.eactive.eai.adapter.socket.service.SocketService;
import com.eactive.eai.agent.web.FepFileSupport;
import com.eactive.eai.batch.common.CalendarUtil;
import com.eactive.eai.batch.common.CommonKeys;
import com.eactive.eai.batch.common.LogUtil;
import com.eactive.eai.batch.common.StringUtil;
import com.eactive.eai.batch.doc.BatchDoc;
import com.eactive.eai.batch.doc.Header;
import com.eactive.eai.batch.ftp.SFTPAdaptor;
import com.eactive.eai.batch.message.EAIBatchMsgManager;
import com.eactive.eai.batch.running.BatchRunningJobManager;
import com.eactive.eai.batch.scheduler.SchedulerMessageManager;
import com.eactive.eai.batch.scheduler.SchedulerMessageVO;
import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.scheduler.Scheduler;
import com.eactive.eai.common.scheduler.SchedulerKeys;
import com.eactive.eai.common.scheduler.SchedulerManager;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpATTRS;

/**
 * 차세대 지방세입 자동이체를 지원한다.
 * 
 * 1. SFTPClient를 하나 만들어서 사용한다.
 * 2. 전송할 파일이 검사한 후 계속 전송한다.(send.max.iteration 기관 프로퍼티: 없으면 하나만 전송)
 *
 */
public class FTPNT extends Transfer implements SocketService {
    /** 송신 폴더 */
    private static final String SEND_REMOTE_PATH = "send.remote.path";
    /** 수신 폴더 */
    private static final String RECV_REMOTE_PATH = "recv.remote.path";

    
    // 송신완료파일 생성관련 프로퍼티
    private static final String SEND_COMPLETE_CREATE_YN = "send.complete.create.yn";
    private static final String SEND_COMPLETE_FILE_EXT = "send.complete.file.ext";

    /** 인증 방법 1 = id, 2 = key 방식 */
    private static final String AUTH_TYPE = "sftp.auth.type";

    /** 큐에서 가져오는 최대 갯수. 없으면 하나만 전송 */
    private static final String SEND_MAX_ITERATION = "send.max.iteration";

    public final static String PHASECODE_NORMAL_END = "END";
    
    /** 송신 완료 전송 */
    private static final String SEND_NOTIFY_YN = "send.notify.yn";
    /** 송신 완료을 알릴 송신 파일 이름 Regular Expression */
    private static final String SEND_NOTIFY_FILENAME_PATTERN = "send.notify.filename.pattern";
    
    /** , 로 구분한 송신 완료 전송 URL  */
    private static final String SEND_NOTITY_URLS = "send.notify.urls";
    private static final String SEND_NOTITY_CONNECTION_TIMEOUT = "send.notify.connection.timeout";
    private static final String SEND_NOTITY_READ_TIMEOUT = "send.notify.read.timeout";

    /** 수신 완료 전송 여부 */
    private static final String RECV_NOTIFY_YN = "recv.notify.yn";
    
    /** 파일 수신 후 계정계로 파일 전송 Job 실행 */
    private static final String RECV_ROOT_JOB_NAME = "EF003";

	@Override
	public void sendFile(BatchDoc batchDoc) throws Exception {
		ChannelSftp channelSftp = null;
		Session session = null;
		try {
			logger = (com.eactive.eai.common.util.Logger) batchDoc.getLogger();
	        String propName = FtpSupport.getInstitutionPropertyName(batchDoc);
			Properties institutionProperties = PropManager.getInstance().getProperties(propName);
	        
			String ipaddress = batchDoc.getBatchMsg().getHeader().getRemoteIP();
			int    port      = Integer.parseInt(batchDoc.getBatchMsg().getHeader().getPort());
			String userid    = batchDoc.getBatchMsg().getHeader().getUserID();
			String passwd    = batchDoc.getBatchMsg().getHeader().getUserPassword();
			
	        String authType = institutionProperties.getProperty(AUTH_TYPE, AUTH_TYPE_ID);
	    	// 설정이 없으면 기존 처럼 한 번만 돈다.
	        int iteration = FtpSupport.getIntProperty(institutionProperties, SEND_MAX_ITERATION, 1, (Logger) logger);
	        int connTimeout = FtpSupport.getIntProperty(institutionProperties, CONNECTION_TIMEOUT, 10, (Logger) logger);
	        int setTimeout = FtpSupport.getIntProperty(institutionProperties, READ_TIMEOUT, 10, (Logger) logger);
			String bandWidthLimit = institutionProperties.getProperty(BADNWIDTH, "0");
			bandWidthLimit = bandWidthLimit.replace("K", "000").replace("M", "000000").replaceAll(",", "");
			int bandWidth = Integer.parseInt(bandWidthLimit);		
			
			session = SFTPAdaptor.getSessionJSCH(ipaddress, port, userid, passwd, authType, connTimeout, setTimeout, (Logger) logger);

	    	internalSendFile(session, batchDoc, bandWidth, (Logger) logger);
	    	
	    	for (int i = 1; i < iteration; i++) {
	    		// Queue에 있는 지 확인한다.
	    		BatchDoc newDoc = checkMoreFile(batchDoc);
	    		if (newDoc == null) {
	    			break;
	    		}
	    		String uuid = newDoc.getBatchMsg().getHeader().getUUID();
	    		String subUuid = newDoc.getBatchMsg().getBody().getSubUUID();
	    		try {
		    		internalSendFile(session, newDoc, bandWidth, logger);
	
		    		newDoc.getBatchMsg().getBody().setPhaseEndTime(CalendarUtil.getCurrentTimeNoDash());
		    		setDefaultEndStage(newDoc);
		    		// FlowController Log
		    		LogUtil.setLog(newDoc);
		    		// master 정보
		    		LogUtil.updateLogMaster(newDoc);
		    		// master 작업상태 정보: 정상 종료
		    		LogUtil.setEndLog(newDoc);
	    		} finally {
		    		// 진행중에서 삭제. 반드시 삭제되어야 함
		    		SchedulerMessageManager.getInstance().deleteJobFromProcessing(uuid, subUuid);
	    		}
	    	}	
        } finally {
        	closeJsch(logger, session, channelSftp);
        }
	}

	/**
	 * 파일 하나를 전송한다.
	 */
	protected void internalSendFile(Session session, BatchDoc batchDoc, int bandWidthLimit, Logger logger) throws Exception {
		logger.info("[FTPNT] ■ 대외기관→FEP 파일 송신 시작...... ");
		firstActivity = System.currentTimeMillis();
		setLastActivity();
		BatchRunningJobManager.getInstance().addRunningJobInfo(batchDoc.getBatchMsg().getHeader().getUUID(), this, batchDoc);
		
		// 전송 성공 여부
		boolean result = false;
		// 계정계 통보
		String notifyCBSFilename = null;
		String remoteFileName = batchDoc.getBatchMsg().getHeader().getFileName();
		String sendNotifyYn = "N";
		try {
	        String propName = FtpSupport.getInstitutionPropertyName(batchDoc);
			Properties institutionProperties = PropManager.getInstance().getProperties(propName);

			String hdrInfo = batchDoc.getBatchMsg().getHeader().getHdrInfoName();
			String hdrfileName = hdrInfo.substring(19, hdrInfo.length() - 2).trim();
			
			String remotePath = null;
			if (hdrfileName.contains("/")) {
				int position = hdrfileName.lastIndexOf("/");
				remotePath = hdrfileName.substring(0, position);
				remoteFileName = hdrfileName.substring(position + 1);
			}

	        if (remotePath == null) {
				remotePath = institutionProperties.getProperty(SEND_REMOTE_PATH);
	        }
			if (remotePath == null) {
				throw new Exception("해당 기관에 전송 경로가 지정되어 있지 않습니다. -propName:" + propName + "," + SEND_REMOTE_PATH);
			}


	        if ( !remotePath.endsWith("/") )
				remotePath = remotePath + "/";
	        
	        String sendCompleteCreateYn = institutionProperties.getProperty(SEND_COMPLETE_CREATE_YN, "n");
	        String sendCompleteFileExt = "";
	        if (!sendCompleteCreateYn.equalsIgnoreCase("y") ) {
	        	sendCompleteCreateYn = "n";
	        }
	        else {
	        	sendCompleteCreateYn = "y";
	        	sendCompleteFileExt = institutionProperties.getProperty(SEND_COMPLETE_FILE_EXT, "done");
	        }
	        
	        notifyCBSFilename = institutionProperties.getProperty(SEND_NOTIFY_FILENAME_PATTERN);
	        sendNotifyYn = institutionProperties.getProperty(SEND_NOTIFY_YN, "N");

	        // 실제 파일이름
//	        String orgFileName = batchDoc.getBatchMsg().getHeader().getFileName();
	        // FEP 에서 Rename(송신Real->송신Arch)한 파일이름
			String sendFileName = batchDoc.getBatchMsg().getHeader().getRenamedFileName();
			
			logger.debug( "[FTPNT]sendFileName:" + remoteFileName);
			logger.debug( "[FTPNT]remotePath:" + remotePath);			
			
	        //File 시작시간 설정
			batchDoc.getBatchMsg().getBody().setPhaseStartTime(CalendarUtil.getCurrentTimeNoDash());
			LogUtil.setLogFileStart(batchDoc);

	        String sendFilePath = batchDoc.getBatchMsg().getHeader().getFilePath();
	        	        
	        ChannelSftp channelSftp = null;
	        try {
				channelSftp = (ChannelSftp) session.openChannel("sftp");
				channelSftp.connect();
	        	SFTPAdaptor.storeJSCH(batchDoc, channelSftp, remotePath, remoteFileName, sendFilePath + File.separator + sendFileName, bandWidthLimit, logger);
	        	
	        	// 송신완료파일 생성 및 업로드
	        	if ( sendCompleteCreateYn == "y" ) {
	        		String completeFileName = remoteFileName + "." + sendCompleteFileExt;
	                File completeFile = new File(sendFilePath + File.separatorChar + completeFileName);
	                completeFile.createNewFile();
	                
	                SFTPAdaptor.storeJSCH(batchDoc, channelSftp, remotePath, completeFileName, sendFilePath + File.separator + completeFileName, bandWidthLimit, logger);
	                Files.delete(completeFile.toPath());
	        	}
	        } catch (Exception e) {
	        	logger.error("[SFTP1]파일송신에 실패하였습니다.", e);
	        	throw e;
	        } finally {
	        	if (channelSftp != null) {
	        		channelSftp.disconnect();
	        	}
	        }
	        
			//File 종료시간 설정
	        setLastActivity();
			batchDoc.getBatchMsg().getBody().setPhaseEndTime(CalendarUtil.getCurrentTimeNoDash());
			LogUtil.setLogFileEnd(batchDoc);
	        result = true;
		} catch(Exception ex) {
            String[] msgArgs = new String[1];
            msgArgs[0] = batchDoc.getBatchMsg().getHeader().getProcessCode();
            String errCode = "BECEAIFJI002";
            String errMsg = ExceptionUtil.getErrorCode (ex, errCode, msgArgs);
            batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
            LogUtil.setErrorLog(batchDoc, ex.getMessage());
            logger.error( errMsg, ex );
            throw ex;
		} finally {
			BatchRunningJobManager.getInstance().removeRunningJobInfo( batchDoc.getBatchMsg().getHeader().getUUID());
			// SFTP는 실제 disconnect는 FTPUtil-SFTPAdaptor에서 하지만, 연결해제 로그를 찍어주기 위해 호출.
			this.disconnect();
			
			// 파일 이름 패턴이 통보하는 이름과 매칭되면
			if ("y".equalsIgnoreCase(sendNotifyYn) && StringUtils.isNotBlank(notifyCBSFilename) && remoteFileName.matches(notifyCBSFilename)) {
				sendResult("S", result, batchDoc, "", "", 1, remoteFileName);
			}
        }

		logger.info("[FTPNT] ■ FEP → VAN사 파일 송신 완료.");
	}
	
	/**
	 * 송신 결과를 계정계로 알려준다.
	 * 
	 * @param sendOrReceive 송수신 구분. S: 송신, R: 수신
	 * @param batchDoc
	 * @param remoteFileName
	 * @param result
	 */
	private void sendResult(String sendOrReceive, boolean resultCode, BatchDoc batchDoc, String listFileName, String listFileYn, int fileCount, String remoteFilename) {
		logger = batchDoc.getLogger();
        String propName = FtpSupport.getInstitutionPropertyName(batchDoc);
        Properties institutionProperties = PropManager.getInstance().getProperties(propName);

		String notifyUrls = institutionProperties.getProperty(SEND_NOTITY_URLS);
		int connectionTimeout = FtpSupport.getIntProperty(institutionProperties, SEND_NOTITY_CONNECTION_TIMEOUT, 10, logger);
		int readTimeout = FtpSupport.getIntProperty(institutionProperties, SEND_NOTITY_READ_TIMEOUT, 10, logger);
			
		//PostMethod method = null;
		if (StringUtils.isBlank(notifyUrls)) {
			logger.error("notifyUrls is blank");
			return;
		}
		
		notifyUrls = notifyUrls.trim();
		String message =  FepFileSupport.getNotifyMessage(sendOrReceive, resultCode, batchDoc, listFileName, listFileYn, fileCount, remoteFilename);
		for (String notifyUrl : notifyUrls.split("\\s*,\\s*")) {
			try {
				HttpPost post = new HttpPost(notifyUrl);
				
				RequestConfig requestConfig = RequestConfig.custom()
			            .setConnectTimeout(Timeout.ofSeconds(connectionTimeout))
			            .setResponseTimeout(Timeout.ofSeconds(readTimeout))
			            .build();
			    post.setConfig(requestConfig);
				
			    StringEntity entity = new StringEntity(
			            "msg=" + message,
			            ContentType.create("application/x-www-form-urlencoded", "EUC-KR")
			    );

			    post.setEntity(entity);
			    
			    try (CloseableHttpClient client = HttpClients.createDefault();
			            CloseableHttpResponse response = client.execute(post)) {

			           int status = response.getCode();
			           if (status != HttpStatus.SC_OK) {
			               logger.error("http status error {" + status + "}, url = {" + notifyUrl + "}");
			           }

			           // 응답 읽기
			           String responseMessage = EntityUtils.toString(response.getEntity(), "EUC-KR");
			           logger.info("Url {" + notifyUrl + "} response = {" + responseMessage + "}");
			       }
			    break;
			} catch (Exception e) {
				logger.error("url = {"+notifyUrl+"}, msg={"+message+"}");
				logger.error(e.getLocalizedMessage(), e);
			}
		    
			
		}
	}
	
	
	/**
	 * 수신 결과를 계정계로 알려준다.
	 * 수신 이벤트 job을 trigger한다.
	 * 
	 * @param batchDoc
	 * @param remoteFileName
	 * @param result
	 * @throws SchedulerException 
	 */
	private void sendReceiveResult(boolean resultCode, BatchDoc batchDoc, String listFileName, String listFileYn, int fileCount, String remoteFilename) throws SchedulerException {
		logger = batchDoc.getLogger();
		SchedulerManager schedulerManager = SchedulerManager.getInstance();
		Scheduler scheduler = schedulerManager.getScheduler(SchedulerKeys.DEFAULT_SCHEDULER_ID);
		org.quartz.Scheduler quartzScheduler = scheduler.getQuartzScheduler();
		for (String groupName : quartzScheduler.getJobGroupNames()) {
		    // get jobkey
		    for (JobKey jobKey : quartzScheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
		        String jobName = jobKey.getName();
		        String jobGroup = jobKey.getGroup();
		        if (jobName.equals(RECV_ROOT_JOB_NAME)) {
			        logger.info("triggering jobName = {"+jobName+"}, jogGroup = {"+jobGroup+"}");
			        quartzScheduler.triggerJob(jobKey);
			        break;
		        }
		    }
		}
		
		sendResult("R", resultCode, batchDoc, listFileName, listFileYn, fileCount, remoteFilename);
	}

	public void recvFile(BatchDoc batchDoc) throws Exception {
		logger = batchDoc.getLogger();
		logger.info("[FTPNT] ■ 대외기관→FEP 파일 수신 시작...... ");
		firstActivity = System.currentTimeMillis();
		setLastActivity();
		BatchRunningJobManager.getInstance().addRunningJobInfo(batchDoc.getBatchMsg().getHeader().getUUID(), this, batchDoc);
		ChannelSftp channelSftp = null;
		Session session = null;
		String recvNotifyYn = "N";
		int fileCount = 0;
		boolean resultCode = false;
		try {
			String ipaddress = batchDoc.getBatchMsg().getHeader().getRemoteIP();
			int    port      = Integer.parseInt(batchDoc.getBatchMsg().getHeader().getPort());
			String userid    = batchDoc.getBatchMsg().getHeader().getUserID();
			String passwd    = batchDoc.getBatchMsg().getHeader().getUserPassword();
			
	        String propName = FtpSupport.getInstitutionPropertyName(batchDoc);
	        Properties institutionProperties = PropManager.getInstance().getProperties(propName);
			
			String hdrInfo = batchDoc.getBatchMsg().getHeader().getHdrInfoName();
			
			String hdrFileName = hdrInfo.substring(19, hdrInfo.length() - 2).trim();
			String remoteFileName = batchDoc.getBatchMsg().getHeader().getFileName();
			String requestFileName = remoteFileName;
			
			String remotePath = null;
			if (hdrFileName.contains("/")) {
				requestFileName = hdrFileName;
				int position = hdrFileName.lastIndexOf("/");
				remotePath = hdrFileName.substring(0, position);
				remoteFileName = hdrFileName.substring(position + 1);
			}
	        if (remotePath == null) {
	        	remotePath = institutionProperties.getProperty(RECV_REMOTE_PATH);
	        }
			if (remotePath == null) {
				throw new Exception("해당 기관에 전송 경로가 지정되어 있지 않습니다. -propName:" + propName + "," + RECV_REMOTE_PATH);
			}

	        if ( !remotePath.endsWith("/") )
				remotePath = remotePath + "/";
	        
	        String authType = institutionProperties.getProperty(AUTH_TYPE, AUTH_TYPE_ID);
	        recvNotifyYn = institutionProperties.getProperty(RECV_NOTIFY_YN, "N");
	        
	        int connTimeout = FtpSupport.getIntProperty(institutionProperties, CONNECTION_TIMEOUT, 10, logger);
	        int setTimeout = FtpSupport.getIntProperty(institutionProperties, READ_TIMEOUT, 10, logger);
			String bandWidthLimit = institutionProperties.getProperty(BADNWIDTH, "0");
			bandWidthLimit = bandWidthLimit.replace("K", "000").replace("M", "000000").replaceAll(",", "");
			int bandWidth = Integer.parseInt(bandWidthLimit);		
	        
	        String listFileName = "";	// 수신한 LIST 파일:EBG00_EBGR_LISTTR 형식
	        String listFileYn = "N"; // LIST 파일 수신 여부
	        
			logger.debug( "[FTPNT]FileName:" + batchDoc.getBatchMsg().getHeader().getFileName());
			
			try {
				session = SFTPAdaptor.getSessionJSCH(ipaddress, port, userid, passwd, authType, connTimeout, setTimeout, logger);
				channelSftp = (ChannelSftp) session.openChannel("sftp");
				channelSftp.connect();

				// 파일을 가져올지 디렉터리를 가져올지 
				boolean oneFile = false;
				if (!FtpSupport.hasWildcard(remoteFileName)) {
					SftpATTRS sa = SFTPAdaptor.lstatJSCH(channelSftp, remotePath, remoteFileName);
					if (sa.isReg()) {
						oneFile = true;	
					}
				}
				// 파일 하나만 수신한다.
				if (oneFile) {
    				LogUtil.setLogFileStart(batchDoc);
    				batchDoc.getBatchMsg().getBody().setRecCnt(1);
    				batchDoc.getBatchMsg().getBody().setPhaseStartTime(CalendarUtil.getCurrentTimeNoDash());
    	            batchDoc.getBatchMsg().getHeader().setFileName(remoteFileName);

    	            SFTPAdaptor.cdJSCH(channelSftp, remotePath);
    				SFTPAdaptor.retrieveJSCH(batchDoc, channelSftp, remoteFileName, batchDoc.getBatchMsg().getHeader().getFilePath(), bandWidth, logger);
    				
    				File file = new File(batchDoc.getBatchMsg().getHeader().getFilePath() + "/" + remoteFileName);
    				batchDoc.getBatchMsg().getHeader().setFileSize(file.length());
    				
    				String recvFile = batchDoc.getBatchMsg().getHeader().getFilePath() + File.separator +  remoteFileName;
    				File rcvRealFile = new File( recvFile );  					

    				try {
    					File rcvArchFile = new File( StringUtil.realToArchDir(recvFile) );
    					if (rcvRealFile.exists() && rcvRealFile.length() == batchDoc.getBatchMsg().getHeader().getFileSize() ) {
    						rcvRealFile.renameTo(rcvArchFile);
    						File rcvRootFile = new File( StringUtil.realToRootDir(recvFile) );
    						rcvRootFile.createNewFile();
    						
    						// LIST 파일이면 통보 내용으로 설정한다. 
    						if (remoteFileName.toUpperCase().startsWith("LIST")) {
    							listFileYn = "Y";
    							Header header = batchDoc.getBatchMsg().getHeader();
    							
    							listFileName = header.getProcessCode() + "_" + header.getInstitutionCode() + "_" + remoteFileName;
    						}
    					} else {
    						throw new Exception("[FTPNT]파일수신에 실패하였습니다.");
    					}
    					//File 종료시간 설정
    					batchDoc.getBatchMsg().getBody().setPhaseEndTime(CalendarUtil.getCurrentTimeNoDash());
    					LogUtil.setLogFileEnd(batchDoc);
    					resultCode = true;
    				} catch (Exception e) {
    					throw e;
    				}
				} else {					
		    		FTPFile[] list = SFTPAdaptor.lsJSCH(channelSftp, remotePath, remoteFileName, logger);
	
		    		SFTPAdaptor.cdJSCH(channelSftp, remotePath);
		    		for ( int inx = 0 ; inx < list.length; inx++ ){
						//강제중지 설정시
						if (batchDoc.isUserCancel()){
							throw new Exception("사용자가 전송을 중지 했습니다.");
						}
		    			
		    			FTPFile file = list[inx];
		    			
		    			if (!file.isFile()) {
		    				continue;
		    			}
		    			
	    				batchDoc.getBatchMsg().getHeader().setFileSize(file.getSize());
	    				batchDoc.getBatchMsg().getBody().setRecCnt(1);
	    				batchDoc.getBatchMsg().getBody().setPhaseStartTime(CalendarUtil.getCurrentTimeNoDash());
	    	            batchDoc.getBatchMsg().getHeader().setFileName(file.getName());
	    				LogUtil.setLogFileStart(batchDoc);
	    				SFTPAdaptor.retrieveJSCH(batchDoc, channelSftp, file.getName(), batchDoc.getBatchMsg().getHeader().getFilePath(), bandWidth, logger);
	    				
	    				String recvFile = batchDoc.getBatchMsg().getHeader().getFilePath() + File.separator +  file.getName();
	    				File rcvRealFile = new File( recvFile );  					
	
	    				try {
	    					File rcvArchFile = new File( StringUtil.realToArchDir(recvFile) );
	    					if (rcvRealFile.exists() && rcvRealFile.length() == batchDoc.getBatchMsg().getHeader().getFileSize() ) {
	    						rcvRealFile.renameTo(rcvArchFile);
	    						File rcvRootFile = new File( StringUtil.realToRootDir(recvFile) );
	    						rcvRootFile.createNewFile();
	    						
	    						// LIST 파일이면 통보 내용으로 설정한다. 
	    						if (file.getName().toUpperCase().startsWith("LIST")) {
	    							listFileYn = "Y";
	    							Header header = batchDoc.getBatchMsg().getHeader();
	    							
	    							listFileName = header.getProcessCode() + "_" + header.getInstitutionCode() + "_" + file.getName();
	    						}
	    					} else {
	    						throw new Exception("[FTPNT]파일수신에 실패하였습니다.");
	    					}
	    					fileCount++;
	    					//File 종료시간 설정
	    					batchDoc.getBatchMsg().getBody().setPhaseEndTime(CalendarUtil.getCurrentTimeNoDash());
	    					LogUtil.setLogFileEnd(batchDoc);
	    					resultCode = true;
	    				} catch (Exception e) {
	    					throw e;
	    				}
		    		}
				}
            } catch ( Exception e ){
            	if ( !e.getMessage().contains("No such file") ) {
            		resultCode = false;
            		throw e;
            	}
            } finally {
            	closeJsch(logger, session, channelSftp);
    			
    			if ("y".equalsIgnoreCase(recvNotifyYn)) {
    				sendReceiveResult(resultCode, batchDoc, listFileName, listFileYn,  fileCount, requestFileName);
    			}
            }
        } catch(Exception ex) {
            String[] msgArgs = new String[1];
            msgArgs[0] = batchDoc.getBatchMsg().getHeader().getProcessCode();
            String errCode = "BECEAIFJI002";
            String errMsg = ExceptionUtil.getErrorCode (ex, errCode, msgArgs);
            batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
            LogUtil.setErrorLog(batchDoc, ex.getMessage());
            logger.error( errMsg, ex );
            throw ex;
		} finally {
			batchDoc.setSftpChannel(null);
			this.disconnect();
        }

		logger.info("[FTPNT] ■ VAN사 → FEP 파일 수신 완료.");
	}

	@Override
	public void shutdown() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public Socket getCurrentSocket() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean connect() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public ConfigurationContext getContext() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void setControl(Object control) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void notifyMessage() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public boolean idle(long timeout) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public int getCurrentState() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public boolean isConnected() throws IOException {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean isActive() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void checkActivity() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public String getRemoteIPAddress() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void setLastActivity() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public long getFirstActivity() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public long getLastActivity() {
		// TODO Auto-generated method stub
		return 0;
	}
	
    /** 
     * FlowController END를 위한 값으로 설정한다.
     * @param batchDoc 설정 값을 변경할 배치 작업
     */
	private void setDefaultEndStage(BatchDoc batchDoc) {
        batchDoc.getBatchMsg().getBody().setFlowPhaseCode(PHASECODE_NORMAL_END);
        batchDoc.getBatchMsg().getBody().setPhaseType(PHASECODE_NORMAL_END);
        //Phase 쪽 단계정보 설정
		batchDoc.getBatchMsg().getPhaseinfo().setRuleCode          (this.getClass().getSimpleName());
		batchDoc.getBatchMsg().getPhaseinfo().setPhaseCode         (PHASECODE_NORMAL_END);
		batchDoc.getBatchMsg().getPhaseinfo().setPhaseType         (PHASECODE_NORMAL_END);
		batchDoc.getBatchMsg().getPhaseinfo().setFlowClassName     ("com.eactive.eai.batch.job.jobModule.Component.END");
		batchDoc.getBatchMsg().getPhaseinfo().setLengthFieldIndex  (0);
		batchDoc.getBatchMsg().getPhaseinfo().setLengthTelegramID  ("");
		batchDoc.getBatchMsg().getPhaseinfo().setLengthClassName   ("");
		batchDoc.getBatchMsg().getPhaseinfo().setLengthMsgCode     ("");
		batchDoc.getBatchMsg().getPhaseinfo().setPhaseSeq          ("1");
		batchDoc.getBatchMsg().getPhaseinfo().setPhaseTelegramID   ("");
		batchDoc.getBatchMsg().getPhaseinfo().setPhaseClassName    ("");
		batchDoc.getBatchMsg().getPhaseinfo().setPhaseMsgCode      ("");
		batchDoc.getBatchMsg().getPhaseinfo().setTelegramTypeValue ("");
		batchDoc.getBatchMsg().getPhaseinfo().setBizCodeValue      ("");
		batchDoc.getBatchMsg().getPhaseinfo().setControlCodeValue  ("");
		batchDoc.getBatchMsg().getPhaseinfo().setResponseCodeValue ("");	
	}
	
	/**
	 * 같은 업무, 기관 코드의 작업이 큐에 있는지 확인한다.
	 * 
	 * @param batchDoc
	 * @return 큐에서 가져온 배치 잡 
	 */
    private BatchDoc checkMoreFile(BatchDoc batchDoc) {
		logger = batchDoc.getLogger();

		BatchDoc newDoc = null;
    	String processCode = batchDoc.getBatchMsg().getHeader().getProcessCode(); 
    	String institutionCode = batchDoc.getBatchMsg().getHeader().getInstitutionCode();
    	SchedulerMessageVO info;
    	try{
    		info = SchedulerMessageManager.getInstance().getSendJobFromQueue(processCode, institutionCode );
    		if ( info == null ) {
    			return null;
    		}
    		newDoc = EAIBatchMsgManager.createBatchMsg(true);

			//해당 작업을 Job_Queue 테이블에서 Job_Processing 테이블로 이동
    		SchedulerMessageManager.getInstance().moveJobQueueToHandle(info);
    		//BatchMsgDoc Layer, SubLayer, StartTime 설정
    		EAIBatchMsgManager.updateBatchMsgWithStageTime(newDoc, CommonKeys.LAYER_FLOW_CONTROLLER, CommonKeys.SUB_LAYER_FLOW_CONTROLLER);

    		//BatchMsgDoc 값 설정
    		newDoc.getBatchMsg().getHeader().setUUID(info.getUUID());
    		newDoc.getBatchMsg().getBody().setSubUUID(info.getSubUUID());
    		newDoc.getBatchMsg().getHeader().setProcessCode(info.getProcessCode());
    		newDoc.getBatchMsg().getHeader().setProcessName(info.getProcessName());
    		newDoc.getBatchMsg().getHeader().setProcessType(info.getProcessType());
    		newDoc.getBatchMsg().getHeader().setInstitutionCode(info.getInstitutionCode());
    		newDoc.getBatchMsg().getHeader().setInstitutionName(info.getInstitutionName());
    		newDoc.getBatchMsg().getHeader().setScheduleCode(info.getScheduleCode());
    		newDoc.getBatchMsg().getHeader().setScheduleSTime(info.getStartTime());
    		newDoc.getBatchMsg().getHeader().setScheduleETime(info.getEndTime());
    		newDoc.getBatchMsg().getHeader().setFilePath(info.getFilePath());
    		newDoc.getBatchMsg().getHeader().setFileName(info.getFileName());
    		newDoc.getBatchMsg().getHeader().setRenamedFileName(info.getRenamedFileName());
    		newDoc.getBatchMsg().getHeader().setJobCode(info.getJobCode());
    		newDoc.getBatchMsg().getHeader().setBizCode(info.getBizCode());
    		newDoc.getBatchMsg().getHeader().setFlowCode(info.getFlowRuleCode());
    		newDoc.getBatchMsg().getHeader().setRuleCode(info.getFlowRuleCode());
    		newDoc.getBatchMsg().getHeader().setBlockSize(info.getBlockSize());
    		newDoc.getBatchMsg().getHeader().setSequenceSize(info.getSequenceSize());
    		newDoc.getBatchMsg().getHeader().setPacketSize(info.getPacketSize());
    		newDoc.getBatchMsg().getHeader().setUserID(batchDoc.getBatchMsg().getHeader().getUserID());
    		newDoc.getBatchMsg().getHeader().setUserPassword(batchDoc.getBatchMsg().getHeader().getUserPassword());
    		newDoc.getBatchMsg().getHeader().setPort(batchDoc.getBatchMsg().getHeader().getPort());
    		newDoc.getBatchMsg().getHeader().setSystemConnCode(info.getSystemConnCode());
    		newDoc.getBatchMsg().getHeader().setRequestResponse(info.getRqstRspnsDstcd());
    		newDoc.getBatchMsg().getHeader().setRemoteIP(batchDoc.getBatchMsg().getHeader().getRemoteIP());

			// 다음 파일의 체크 파일 가져오기
			if (info.getProcessType().equals(CommonKeys.PROCESS_REQUEST_SEND)
					|| info.getProcessType().equals(CommonKeys.PROCESS_RESPONSE_SEND)) {
				String hdrInfoName = info.getHdrInfoName();
				newDoc.getBatchMsg().getHeader().setHdrInfoName(hdrInfoName);
				newDoc.getBatchMsg().getHeader().setTotRecCnt(StringUtil.getTotRecCountFromHeader(hdrInfoName));
				newDoc.getBatchMsg().getHeader().setBaseDate(StringUtil.getBaseDateFromHeader(hdrInfoName));

				String dirPath = newDoc.getBatchMsg().getHeader().getFilePath();
				String renamedFileName = newDoc.getBatchMsg().getHeader().getRenamedFileName();
				File file = new File(dirPath + File.separatorChar + renamedFileName);
				if (!file.exists()) {
					throw new Exception();
				}
				long fileLen = file.length();

				newDoc.getBatchMsg().getHeader().setFileSize(fileLen);
			}
    	} catch ( Exception e){
    		logger.error(newDoc == null ? "batchDoc is null" : newDoc.toString(), e);
    		return null;
    	}
    	
    	return newDoc;
    }
    
    private void closeJsch(Logger logger, Session session, ChannelSftp channelSftp) {
		if (channelSftp != null && channelSftp.isConnected()) {
			try {
				channelSftp.disconnect();
			} catch (Exception e) {
				logger.error(e.getLocalizedMessage(), e);
			}
		}
		if (session != null) {
			try {
				session.disconnect();
			} catch (Exception e) {
				logger.error(e.getLocalizedMessage(), e);
			}

		}
    }
}
