package com.eactive.eai.adapter.ftp;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

import com.eactive.eai.batch.doc.BatchDoc;
import com.eactive.eai.batch.rule.dirInfo.BatchJobInfoVO;
import com.eactive.eai.batch.rule.dirInfo.DirInfoManager;
import com.eactive.eai.common.util.Logger;


//public abstract class Transfer extends Thread implements SocketService {
public abstract class Transfer{

	//리모트 전송 프라퍼티 정보
    public static final String DIRECTION_SEND     = "송신";   //DB에 입력되는 값
    public static final String DIRECTION_RECEIVE  = "수신";   //DB에 입력되는 값

	public static final String SEND_SCRIPT_PATH       = "script.send";  //VAN 송신 쉘스크립트 경로 
	public static final String RECV_SCRIPT_PATH       = "script.recv";  //VAN 수신 쉘스크립트 경로 
	public static final String SEND_TITLE             = "send.title";   //VAN 송신 TITLE
	public static final String RECV_TITLE             = "recv.title";   //VAN 송신 TITLE
	public static final String ORG_ID                 = "org.id";       //상대방 ID
	
	//sftp 20220713
	protected static final String CONNECTION_TIMEOUT = "connection.timeout";
	protected static final String READ_TIMEOUT = "read.timeout";
	protected static final String BADNWIDTH = "io.bandwidth";
	
    protected long				 	firstActivity;
    protected long				 	lastActivity;

    protected Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);

	protected String scriptErrorMsg  = "";
	protected String scriptOutputMsg = "";
	protected FTPClient ftpClient = null;

    /** 인증 방법 1 = id, 2 = key 방식 */
    public static final String AUTH_TYPE = "sftp.auth.type";
    public static final String AUTH_TYPE_ID = "1";
    public static final String AUTH_TYPE_KEY = "2";
    
	//protected static EAIBatchMessageDocument batchDoc;

	public static void sendFileByEvent(BatchDoc batchDoc) throws Exception {
		transferFileByEvent(DIRECTION_SEND, batchDoc);
	}

	public static void recvFileByEvent(BatchDoc batchDoc) throws Exception {
		transferFileByEvent(DIRECTION_RECEIVE, batchDoc);
	}
	//-------------------------------------------------------------------------------------------
	//
	//-------------------------------------------------------------------------------------------
	public static void transferFileByEvent(String sendRecvType, BatchDoc batchDoc) throws Exception {
		Logger logger = (Logger) batchDoc.getLogger(Logger.LOGGER_ADAPTER);

		logger.info("[com.eactive.eai.adapter.ftp.Transfer] ■ Event 송수신 시작......");

		//파라미터 체크
		if (!sendRecvType.equals(DIRECTION_SEND) && !sendRecvType.equals(DIRECTION_RECEIVE)) throw new Exception("{송수신구분} 파라미터 오류");

		String protocol = batchDoc.getBatchMsg().getHeader().getRuleCode();
		
		String className = Transfer.class.getName();
		className = className.substring(0, className.lastIndexOf('.')+1) + protocol;
//		logger.debug("[Transfer]className-->" + className + "<--");
		@SuppressWarnings("rawtypes")
		Class cl = Class.forName(className);
		Transfer transfer = (Transfer)cl.newInstance();

		//---------------------------------------------------------------------
		// 파일 송수신 수행
		transfer.transferFile(sendRecvType, batchDoc);

		logger.info("[com.eactive.eai.adapter.ftp.Transfer] ■ VAN사 모듈 송수신 완료.");
	}

	public void transferFile( String sendRecvType,	BatchDoc batchDoc) throws Exception {
		logger = (Logger) batchDoc.getLogger(Logger.LOGGER_ADAPTER);

		logger.info("[com.eactive.eai.adapter.ftp.Transfer] ■ 파일 송수신 수행 시작......");
		logger.info("[com.eactive.eai.adapter.ftp.Transfer] ⓟ 송수신구분      : ["+ sendRecvType +"] (송신: EAI→VAN사, 수신: VAN사→EAI)");

		try {
			if (sendRecvType.equals(DIRECTION_SEND)) {
////			=================================================================
////			 송신 (EAI -> VAN)
////			=================================================================
				logger.info("[com.eactive.eai.adapter.ftp.Transfer]    ▶ 파일 송신...");
				sendFile(batchDoc);
			} else if (sendRecvType.equals(DIRECTION_RECEIVE)) {
//				=================================================================
//				 수신 (VAN -> EAI)
//				=================================================================
				logger.info("[com.eactive.eai.adapter.ftp.Transfer]    ▶ 파일 수신...");
				recvFile(batchDoc);
			}
		} catch (Exception ex) {
			throw new Exception("FTP 모듈 이용한  파일 송수신 실패!\n caused by..."+ ex.toString());
		}
		logger.info("[com.eactive.eai.adapter.ftp.Transfer] ■ 파일 송수신 수행 완료.");

}

	protected void runSystemScript(String[] command) throws Exception {

		String cmdLine = command[0];
		for ( int inx=1; inx < command.length; inx++)
			cmdLine += " " + command[inx];
		logger.info("[VAN송수신] [Runtime.Exec]    ▶ System Command Runtime 수행 시작...");
		logger.info("[VAN송수신] [Runtime.Exec]    ⓟ Command : ["+ cmdLine +"]");

		//1. System Shell 명령어를 Runtime 으로 실행
		Process process = Runtime.getRuntime().exec(command);

		//2. Runtime 실행 결과 저장
		BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
		String errorLine = null;
		StringBuffer errorBuffer = new StringBuffer();
		try {
			while ((errorLine = errorReader.readLine()) != null) {
				if (errorBuffer.length() > 0) errorBuffer.append("\n");
				errorBuffer.append(errorLine);
				logger.debug("[VAN송수신] [Runtime.Exec]       stderr> "+ errorLine);
			}
		} catch (Exception e) {
			logger.error( e.getMessage(), e );
		}

		BufferedReader outputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
		String outputLine = null;
		StringBuffer outputBuffer = new StringBuffer();
		
		try {
			while ((outputLine = outputReader.readLine()) != null) {
				if (outputBuffer.length() > 0) outputBuffer.append("\n");
				outputBuffer.append(outputLine);
				logger.debug("[VAN송수신] [Runtime.Exec]       stdout> "+ outputLine);
			}
		} catch (Exception e) {
			logger.error( e.getMessage(), e );
		}

		int exitVal = process.waitFor();

		scriptErrorMsg  = errorBuffer.toString();
		scriptOutputMsg = outputBuffer.toString();

		logger.info("[VAN송수신] [Runtime.Exec]    ☞ Exit Value : "+ exitVal);
		logger.info("[VAN송수신] [Runtime.Exec]    ▶ System Command Runtime 수행 완료.");

		String errMsg = "Runtime.Exec 으로 실행한 Command exit value ("+ exitVal +") 가 정상이 아닙니다. \n" +
				        "(Command : "+ cmdLine +")\n" +
				        "(STDOUT  : "+ scriptErrorMsg +"\n" +
				        "(STDERR  : "+ scriptOutputMsg ;
		if (exitVal != 0) throw new Exception(errMsg);
	}	
	
	protected void connect(String ipaddress, int port) throws Exception {

		try {

			if (port < 1) {
				logger.warn("[com.eactive.eai.adapter.ftp.Transfer]해당 서버["+ port +"] 에 연결할 FTP 포트번호가 주어지지 않았습니다. 디폴트 포트번호 '21' 을 설정합니다.");
				port = 21;
			}
			logger.info("[com.eactive.eai.adapter.ftp.Transfer]▶ FTP 서버 연결 시도... " + ipaddress + ":" + port);


			if (ftpClient!=null && ftpClient.isConnected()) {
				logger.info("[com.eactive.eai.adapter.ftp.Transfer]▶ 해당 FTP 서버에 이미 연결되어 있습니다.");
				return;
			}

			ftpClient = new FTPClient();
			ftpClient.setControlEncoding("EUC-KR");
			ftpClient.connect(ipaddress, port);

			int reply = ftpClient.getReplyCode();
			logger.info("[com.eactive.eai.adapter.ftp.Transfer]    ☞ 응답코드 : "+ reply);

			if (!FTPReply.isPositiveCompletion(reply)) {
				try {
					logger.error("[com.eactive.eai.adapter.ftp.Transfer]    FTP 서버 연결에 실패하였습니다.");
					ftpClient.disconnect();

				} catch (Exception ex) {
					logger.error("[com.eactive.eai.adapter.ftp.Transfer]    FTP 서버 연결에 실패후 에러 발생하였습니다.", ex);
				}
				throw new Exception("FTP 연결 응답코드("+ reply +") 가 비정상입니다.");
			}
			logger.info("[com.eactive.eai.adapter.ftp.Transfer]    ▶ FTP 서버에 연결되었습니다.");

		} catch (Exception ex) {
			String errMsg = "FTP 연결 오류!\n caused by..."+ ex.toString();
			logger.error(errMsg, ex);
			throw new Exception(errMsg);
		}
	}

	//-------------------------------------------------------------------------------------------
	//
	//-------------------------------------------------------------------------------------------
	public void disconnect() {
		logger.info("[com.eactive.eai.adapter.ftp.Transfer]    ▶ FTP 서버 연결 해제 시도...");
		try {
			if (ftpClient!=null && ftpClient.isConnected()) ftpClient.disconnect();
			logger.info("[com.eactive.eai.adapter.ftp.Transfer]    ▶ FTP 서버 연결이 해제 되었습니다.");
		} catch (Exception ex) {
			logger.error( ex.getMessage(), ex);
		}
	}

	public abstract void sendFile( BatchDoc batchDoc) throws Exception;

	public abstract void recvFile( BatchDoc batchDoc ) throws Exception;

	//파일 송수신 시 파일의 헤더, 트레일러 값을 배치메시지에 설정
	public void setFileHeaderAndTrailer(BatchDoc batchDoc, File f) {

		//파일이 존재하지 않거나 디렉토리면 리턴
		if (f == null || !f.exists() || f.isDirectory()) {
			logger.info( "["+ (f==null? "": f.getAbsolutePath()) +"]: 파일이 존재하지 않거나 디렉토리입니다. 파일헤더,트레일러 설정안함.");
			return;
		}

		FileInputStream fin = null;
		try {
			long fileHeaderSize  = 500;  //파일헤더 로그 디폴트 사이즈
			long fileTrailerSize = 500;  //파일트레일러 로그 디폴트 사이즈
			BatchJobInfoVO jobInfo = DirInfoManager.getInstance().getFileInfo(batchDoc.getBatchMsg().getHeader().getJobCode());
			if (jobInfo != null) {
				fileHeaderSize  = jobInfo.getFileHeaderLogSize();
				fileTrailerSize = jobInfo.getFileTrailerLogSize();
			}

			if (fileHeaderSize == 0 && fileTrailerSize == 0) return;

			fin = new FileInputStream(f);
			long fileSize = f.length();

			//DB값, 파일사이즈, 4000Byte(로그저장 varchar 최대값) 중 최소값 설정
			fileHeaderSize  = Math.min(Math.min(fileHeaderSize , fileSize), 4000L);
			fileTrailerSize = Math.min(Math.min(fileTrailerSize, fileSize), 4000L);

			byte[] bufHeader  = new byte[(int)fileHeaderSize ];
			byte[] bufTrailer = new byte[(int)fileTrailerSize];
			int readSize = 0;

			//파일 헤더 값 READ
			if (fileHeaderSize > 0) {
				readSize = fin.read(bufHeader, 0, bufHeader.length);
			}

			//파일 트레일러 값 READ
			if (fileTrailerSize > 0 && readSize >= 0 && readSize <= fileSize) {
				int overlapSize = 0;  //헤더와 트레일러의 겹치는 Byte 사이즈
				long skipSize = (fileSize - readSize) - fileTrailerSize;

				if (skipSize > 0) {         //헤더와 트레일러가 겹치지 않음 -> 트레일러까지 위치 이동
					fin.skip(skipSize);

				} else if (skipSize < 0) {  //헤더와 트레일러가 겹침 -> 오버랩핑되는 헤더의 뒷부분을 트레일러의 앞부분으로 카피
					overlapSize = Math.abs((int)skipSize);
					System.arraycopy(bufHeader, readSize - overlapSize, bufTrailer, 0, overlapSize);
				}
				if (readSize < fileSize) {
					readSize = fin.read(bufTrailer, overlapSize, bufTrailer.length - overlapSize);
				}
			}

			batchDoc.getBatchMsg().setFileHeader(new String(bufHeader));
			batchDoc.getBatchMsg().setFileTrailer(new String(bufTrailer));

		} catch (Exception ex) {
			logger.error( "★★★★★ 파일내용 헤더, 트레일러 DB로그 설정시 오류 발생 !! ★★★★★", ex);
		} finally {
			try { if (fin != null) fin.close(); } catch (Exception e) {}
		}
	}
	
}
