package com.eactive.eai.batch.job.jobItem.fiusc;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Properties;

import com.eactive.eai.batch.job.jobConstant.TelegramKeys;
import com.eactive.eai.batch.job.jobItem.DefaultTelegram;
import com.eactive.eai.batch.job.jobItem.TelegramService;
import com.eactive.eai.common.exception.ExceptionUtil;

public class SEND_FIUSC_0302 extends DefaultTelegram implements TelegramService {

    private int SEND_LENGTH;            //길이 필드를 제외한 전문의 총길이
    private int REAL_SEND_LENGTH;       //실제 송신할 전문의 총길이( SEND_LENGTH + 길이필드 길이)
    private int HASH_LENGTH;         	//전자서명 HASH data byte수
    private String HASH_LENGTH_INFO;    //전자서명 HASH data byte수 (4byte String)

    private Properties telegramInfo;
    
    private String fileHeaderInfo;  	//송신파일 헤더정보(106byte)
    private byte[] fileTrailerInfo;  	//송신파일 암호화데이터 전자서명정보(100byte~가변)
    
    /**
     * 생성자
     */
    public SEND_FIUSC_0302() {
        //파일 시작 요구
    }

    /**
     * 전문조립
     */
    public boolean doExecute() {
        try {
            boolean result = calculateSendLength();
            if (!result) return false;

            int i = -1;

            //전문송신  전체 Byte 수
            compileField(++i, ""+REAL_SEND_LENGTH, this.al_FieldProps[i]);
            
            //Transaction Code
            compileField(++i, telegramInfo.getProperty(TelegramKeys.TRANSACTION_CODE), this.al_FieldProps[i]);

            //시스템명칭 (FIU)
            compileField(++i, telegramInfo.getProperty(TelegramKeys.BIZ_GBN), this.al_FieldProps[i]);
            
            //기관코드(6)
            compileField(++i, telegramInfo.getProperty(TelegramKeys.BANK_CODE), this.al_FieldProps[i]);
            
            //사용자ID(20)
            byte[] userId = new byte[20];
            Arrays.fill(userId, (byte)' ');
            
            // checked file에서 가져온 사용자 ID
            String checkedFileUserId = fileHeaderInfo.substring(SEND_FIUSC_HEAD.USER_ID.getStrPos(),SEND_FIUSC_HEAD.USER_ID.getEndPos());
            System.arraycopy(checkedFileUserId.getBytes(), 0, userId, 0, Math.min(checkedFileUserId.getBytes().length, 20));

            al_Field.set(++i, userId);
            
            //전문종별코드
            compileField(++i, this.getFldTelegramType()+ this.getFldOpCode() + "0", this.al_FieldProps[i]);
            
            //송수신 FLAG : 전문 발생 기관을 구분하여 아래의 값을 SET한다.
            compileField(++i, getFldTrClass(), this.al_FieldProps[i]);

            //기관구분
            compileField(++i, telegramInfo.getProperty(TelegramKeys.TRA_FLAG_BANK), this.al_FieldProps[i]);

            //계속여부 
            compileField(++i, "Y", this.al_FieldProps[i]);
            
            //응답코드
            compileField(++i, getSendResponseCode(), this.al_FieldProps[i]);
            // 여기 까지 공통부
            
            //문서종류코드(6)
            compileField(++i, fileHeaderInfo.substring(SEND_FIUSC_HEAD.DOC_CODE.getStrPos(),SEND_FIUSC_HEAD.DOC_CODE.getEndPos()), this.al_FieldProps[i]);

            //보고메시지유형코드(2)
            compileField(++i, fileHeaderInfo.substring(SEND_FIUSC_HEAD.MSG_GBN_CD.getStrPos(),SEND_FIUSC_HEAD.MSG_GBN_CD.getEndPos()), this.al_FieldProps[i]);
            
            //문서번호(17)
            compileField(++i, fileHeaderInfo.substring(SEND_FIUSC_HEAD.DOC_NO.getStrPos(),SEND_FIUSC_HEAD.DOC_NO.getEndPos()), this.al_FieldProps[i]);
            
            //보고일자(8)
            compileField(++i, fileHeaderInfo.substring(SEND_FIUSC_HEAD.DOC_DATETIME.getStrPos(),SEND_FIUSC_HEAD.DOC_DATETIME.getEndPos()), this.al_FieldProps[i]);

            //종전문서번호(17)
            compileField(++i, fileHeaderInfo.substring(SEND_FIUSC_HEAD.PRE_DOC_NO.getStrPos(),SEND_FIUSC_HEAD.PRE_DOC_NO.getEndPos()), this.al_FieldProps[i]);
            
            //보고파일명(40)
            compileField(++i, batchDoc.getBatchMsg().getHeader().getFileName(), this.al_FieldProps[i]);

            //거래순번(15)
            compileField(++i, fileHeaderInfo.substring(SEND_FIUSC_HEAD.TGRA_SEQ.getStrPos(),SEND_FIUSC_HEAD.TGRA_SEQ.getEndPos()), this.al_FieldProps[i]);
            
            //기본보고문서번호(17)
            compileField(++i, fileHeaderInfo.substring(SEND_FIUSC_HEAD.DEF_DOC_NO.getStrPos(),SEND_FIUSC_HEAD.DEF_DOC_NO.getEndPos()), this.al_FieldProps[i]);
            
            //중계기관코드(6)
            compileField(++i, telegramInfo.getProperty(TelegramKeys.FIUSC_EAI_CD), this.al_FieldProps[i]);
            
            //레코드 길이(4)
            if (telegramInfo.getProperty(TelegramKeys.TRANSACTION_CODE).startsWith("D")) {
            	compileField(++i, "0001", this.al_FieldProps[i]);
            } else {
            	compileField(++i, HASH_LENGTH_INFO, this.al_FieldProps[i]);  // Local 테스트용 (응답수신에서 전자서명(가변) 길이값으로 사용됨
            }

            //압축사용여부(1)
            String renamedFileName = batchDoc.getBatchMsg().getHeader().getRenamedFileName();
            String compGb = "0";
            if ( ( renamedFileName.indexOf(".ZIP_") > -1 ) || ( renamedFileName.indexOf(".zip_")) > -1 ){
            	compGb = "2";
            }
            if ( renamedFileName.indexOf(".Z_") > -1 ){
            	compGb = "1";
            }
            compileField(++i, compGb, this.al_FieldProps[i]);

            //파일 전체 크기(10)
            compileField(++i, ""+ calculateFileSize(), this.al_FieldProps[i]);
            
            //전자서명데이터(가변)
//            compileField(++i, fileTrailerInfo, this.al_FieldProps[i]);  // 가변데이터는 공통(SEND1)에서 별도처리

            //<< 전문 완성
            
            return true;
        } catch (Exception e) {
            String[] msgArgs = new String[1];
            msgArgs[0] = this.batchDoc.getBatchMsg().getHeader().getProcessCode();
            String errCode = "BECEAIFJI001";
            String errMsg = ExceptionUtil.getErrorCode (e, errCode, msgArgs);
            this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
            logger.error(e.getMessage(),e);
            return false;
        }
    }

    private long calculateFileSize () {

        long length = 0L;
        String fileDir = batchDoc.getBatchMsg().getHeader().getFilePath();
        String fileNm  = batchDoc.getBatchMsg().getHeader().getRenamedFileName();

        if (fileDir.charAt(fileDir.length()-1) != File.separatorChar) {
            fileDir = fileDir + this.getSeparator();
        }

        String fileName = fileDir + fileNm;
    	try {

            File file = new File(fileName);
            if (!file.exists()) // 파일이 없으면 리턴 False
            {
                String[] msgArgs = new String[2];
                msgArgs[0] = this.batchDoc.getBatchMsg().getHeader().getProcessCode();
                msgArgs[1] = fileName;
                String errCode = "BECEAIFJI022";
                String errMsg = ExceptionUtil.getErrorCode (errCode, msgArgs);
                this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
                throw new Exception(" the File["+fileName+"] does not exist!!!");
            }
            length = file.length();
            
            //EMS 송수신파일관리 헤더 및 트레일러 크기만큼 송신파일에서 파싱하여 설정
//        	super.setFileHeaderAndTrailer(file); 
            
        } catch (Exception e) {
            String[] msgArgs = new String[1];
            msgArgs[0] = this.batchDoc.getBatchMsg().getHeader().getProcessCode();
            String errCode = "BECEAIFJI028";
            String errMsg = ExceptionUtil.getErrorCode (e, errCode, msgArgs);
            this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
            logger.error(e.getMessage(),e);
        }
        if (length < 0) {
            return 0;
        }
        this.batchDoc.getBatchMsg().getHeader().setFileSize(length);
        return length;

    }
    
    /**
     * 실제 송신할 전문의 총길이를 리턴해준다.
     */
    public int getSendLength()
    {
        try {
            return REAL_SEND_LENGTH;  //실 DATA BYTE수
        } catch (Exception e) {
            String[] msgArgs = new String[1];
            msgArgs[0] = this.batchDoc.getBatchMsg().getHeader().getProcessCode();
            String errCode = "BECEAIFJI013";
            String errMsg = ExceptionUtil.getErrorCode (e, errCode, msgArgs);
            this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
            logger.error(e.getMessage(),e);
            return -1;
        }
    }

    /**
     * 비정형 필드에 대한 송신 길이를 계산해서 리턴해준다.
     * 필드(idx)가 비정형 필드(XX)인지 점검하고 , 해당 필드에 대한 예상 길이를 계산하여 리턴하도록 한다
     * 비정현 필드를 가지고 있는 개별 Telegram Class 에서 오버라이드 필요.
     */
    public int getCalculatedLength(int idx) {
        try {
            if (idx >= this.getFieldCount() ) {
                logger.debug("{} getCalculatedLength> parameter is bigger than field count", logHeader);
                String[] msgArgs = new String[2];
                msgArgs[0] = this.batchDoc.getBatchMsg().getHeader().getProcessCode();
                msgArgs[1] = ""+idx;
                String errCode = "BECEAIFJI011";
                String errMsg = ExceptionUtil.getErrorCode (errCode, msgArgs);
                this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
                return -1;
            }
            if (this.getFieldLength(idx).equalsIgnoreCase(TelegramService.FIELD_NO_LENGTH)) {
               return HASH_LENGTH;
            } else {
                String[] msgArgs = new String[2];
                msgArgs[0] = this.batchDoc.getBatchMsg().getHeader().getProcessCode();
                msgArgs[1] = ""+idx;
                String errCode = "BECEAIFJI012";
                String errMsg = ExceptionUtil.getErrorCode (errCode, msgArgs);
                this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
                logger.debug("{} getCalculatedLength> parameter is not FIELD_NO_LENGTH", logHeader);
                return -1;
            }
        }catch (Exception e) {
            String[] msgArgs = new String[1];
            msgArgs[0] = this.batchDoc.getBatchMsg().getHeader().getProcessCode();
            String errCode = "BECEAIFJI005";
            String errMsg = ExceptionUtil.getErrorCode (e, errCode, msgArgs);
            this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
            logger.error(e.getMessage(),e);
            return -1;
        }
    }
    
    public int getInformalFieldSendData(int idx, byte[] data) {
        try {
            if (idx >= this.getFieldCount() ) {
                logger.debug("{}  getInformalFieldSendData> " +idx+ " is bigger than field count", logHeader);
                String[] msgArgs = new String[2];
                msgArgs[0] = this.batchDoc.getBatchMsg().getHeader().getProcessCode();
                msgArgs[1] = ""+idx;
                String errCode = "BECEAIFJI011";
                String errMsg = ExceptionUtil.getErrorCode (errCode, msgArgs);
                this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
                return -1;
            }
            if (data.length < HASH_LENGTH) {
                logger.debug("{}  getInformalFieldSendData> InformalFieldSendData size is bigger than buffer size", logHeader);
                String[] msgArgs = new String[2];
                msgArgs[0] = this.batchDoc.getBatchMsg().getHeader().getProcessCode();
                msgArgs[1] = ""+idx;
                String errCode = "BECEAIFJI014";
                String errMsg = ExceptionUtil.getErrorCode (errCode, msgArgs);
                this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
                return -1;
            }
            
            //data = fileData;
            ByteArrayInputStream bin = new ByteArrayInputStream(fileTrailerInfo);
            bin.read(data, 0, HASH_LENGTH);
            
            return HASH_LENGTH;
            
        } catch (Exception ex) {
            String[] msgArgs = new String[1];
            msgArgs[0] = this.batchDoc.getBatchMsg().getHeader().getProcessCode();
            String errCode = "BECEAIFJI006";
            String errMsg = ExceptionUtil.getErrorCode (ex, errCode, msgArgs);
            this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
            logger.error(ex.getMessage(),ex);
            return -1;
        }
    }
    
    public boolean doPreExecute() {
    	
        try {
            if (!super.doPreExecute()) return false;

            //BATCH작업구분코드 (processCode)에 따른 프로퍼티 정보 가져오기
            telegramInfo = getTelegramInfo();
            
            //송신파일 0~100byte 파싱하여 document FileHeader에 설정
            //송신파일 100byte~전자서명Hash 길이 파싱하여 document FileTailer에 설정
            if (this.batchDoc.getBatchMsg().getHeader().getRuleCode().equals("FIU01")) {
            	HashMap<String,Object> fileInfoMap = getFileInfo();
            	fileHeaderInfo = fileInfoMap.get("fileHeaderInfo").toString();  //송신파일 헤더정보(100byte)
            	fileTrailerInfo = (byte[])fileInfoMap.get("fileTrailerInfo");  //송신파일 암호화데이터 전자서명정보(100byte~가변)
            	HASH_LENGTH_INFO = fileHeaderInfo.substring(SEND_FIUSC_HEAD.HASH_SIZE.getStrPos(),SEND_FIUSC_HEAD.HASH_SIZE.getEndPos());
            	HASH_LENGTH = Integer.valueOf(HASH_LENGTH_INFO);

            	this.batchDoc.getBatchMsg().setFileHeader(fileHeaderInfo);
            	this.batchDoc.getBatchMsg().setFileTrailer(new String(fileTrailerInfo));
            }
            
            return true;
        } catch (Exception ex) {
            String[] msgArgs = new String[1];
            msgArgs[0] = this.batchDoc.getBatchMsg().getHeader().getProcessCode();
            String errCode = "BECEAIFJI003";
            String errMsg = ExceptionUtil.getErrorCode (ex, errCode, msgArgs);
            this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
            logger.error(ex.getMessage(),ex);
            return false;
        }

    }

    public boolean doPostExecute() {
        if (!super.doPostExecute()) return false;

        try {
			//DB로그에 남길 전문 헤더 설정
            ByteArrayOutputStream baout = new ByteArrayOutputStream();
            for (int i=0; i<10; i++) {
                baout.write((byte[])this.al_Field.get(i));
            }
            batchDoc.getBatchMsg().setTelegramHeader(new String(baout.toByteArray()));

            //DB로그에 남길 전문 바디 설정
            baout = new ByteArrayOutputStream();
            for (int i=10; i< al_Field.size(); i++) {
                baout.write((byte[])this.al_Field.get(i));
            }
            batchDoc.getBatchMsg().setTelegramBody(new String(baout.toByteArray()));

            return true;

        } catch(Exception ex) {
            String[] msgArgs = new String[1];
            msgArgs[0] = this.batchDoc.getBatchMsg().getHeader().getProcessCode();
            String errCode = "BECEAIFJI002";
            String errMsg = ExceptionUtil.getErrorCode (ex, errCode, msgArgs);
            this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
            logger.error(ex.getMessage(),ex);
            return false;
        }
    }

    private boolean calculateSendLength() {
        try {
            for (int i=1; i< this.al_Field.size()-1; i++) {
        		byte[] aField = (byte[]) this.al_Field.get(i);
        		SEND_LENGTH += aField.length;
            }
            SEND_LENGTH += HASH_LENGTH;
            REAL_SEND_LENGTH = SEND_LENGTH + ((byte[]) this.al_Field.get(0)).length;
        } catch (Exception e) {
            String[] msgArgs = new String[1];
            msgArgs[0] = this.batchDoc.getBatchMsg().getHeader().getProcessCode();
            String errCode = "BECEAIFJI025";
            String errMsg = ExceptionUtil.getErrorCode (e, errCode, msgArgs);
            this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
            logger.error(e.getMessage(),e);
            return false;
        }
        return true;
    }

    private HashMap<String,Object> getFileInfo() {

        String fileDir = batchDoc.getBatchMsg().getHeader().getFilePath();
        String fileNm  = batchDoc.getBatchMsg().getHeader().getRenamedFileName();

        if (fileDir.charAt(fileDir.length()-1) != File.separatorChar) {
            fileDir = fileDir + this.getSeparator();
        }

        HashMap<String,Object> fileInfo = new HashMap<String,Object>();
        
        String fileName = fileDir + fileNm;
        String orgFileName = fileName + ".org";
        
    	try {

            File file = new File(fileName);
            if (!file.exists()) // 파일이 없으면 리턴 False
            {
                String[] msgArgs = new String[2];
                msgArgs[0] = this.batchDoc.getBatchMsg().getHeader().getProcessCode();
                msgArgs[1] = fileName;
                String errCode = "BECEAIFJI022";
                String errMsg = ExceptionUtil.getErrorCode (errCode, msgArgs);
                this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
                throw new Exception(" the File["+fileName+"] does not exist!!!");
            }
            
            //InputStream ios = null;// 20250910 npe
            InputStream ioss = null;
            FileOutputStream fos  = null;
            
            File orgFile = new File(orgFileName); // 20250825 // 원본 파일 
            try {
            	// 전송파일에서 .chk 파일에서 헤더정보 추출
            	String headerInfo = batchDoc.getBatchMsg().getHeader().getHdrInfoName();
            	headerInfo = headerInfo.substring(38);
            	fileInfo.put("fileHeaderInfo", headerInfo);
            	
            	// 재전송을 위해 원본파일(전송정보(100byte)길이 + 전자서명길이(가변) + 데이터(가변)) Copy
            	byte[] copyBuffer = new byte[1024];
            	ioss = new FileInputStream(file);
            	
            	//File orgFile = new File(orgFileName);// 20250825
            	
            	if (!orgFile.exists()) {// 20250825 ogr 파일이 있으면 새로 만들지 않는다 - 재전송을 위해
	            	fos = new FileOutputStream(orgFile);
	            	
	            	int copyLength;
	            	while ((copyLength = ioss.read(copyBuffer)) > 0) {
	            		fos.write(copyBuffer, 0, copyLength);
	            	}
            	}
            } finally {
            	try {
            		//if (ios != null) ios.close();
            		if (ioss != null) ioss.close();
            		if (fos != null) fos.close();
            	} catch (IOException ioe) {
            		logger.debug(ioe.getMessage(),ioe);
            	}
            }

            //암호화데이터 전자서명 Hash값 길이(4byte)
            String fileHeaderInfo = fileInfo.get("fileHeaderInfo").toString();
            int encHashLength = Integer.valueOf(fileHeaderInfo.substring(SEND_FIUSC_HEAD.HASH_SIZE.getStrPos(),SEND_FIUSC_HEAD.HASH_SIZE.getEndPos()));

            File sourceFile = orgFile.exists() ? orgFile : file; // 읽기용 // 20250825
            File targetFile = new File(fileName);  // 20250825
            
        	RandomAccessFile randomFile = null;
        	try {
        		//randomFile = new RandomAccessFile(fileName,"r");
        		randomFile = new RandomAccessFile(sourceFile,"r");// 20250825 - 재전송을 위해 원본파일로 생성한다.
        		
        		// 전송파일에서 암호화데이터 전자서명 Hash값을 헤더정보의 길이값만큼 파싱하여 전자서명정보 추출
        		byte[] hashBytes = new byte[encHashLength];
        		randomFile.readFully(hashBytes);
        		
        		fileInfo.put("fileTrailerInfo", hashBytes);
        		
        		// 전자서명길이(가변) byte 제외하고 데이터만 전송파일에 다시 저장
        		randomFile.seek(encHashLength);
        		byte[] dataBytes = new byte[(int)randomFile.length()-(encHashLength)];
        		randomFile.readFully(dataBytes);
        		
        		//fos = new FileOutputStream(file);
        		fos = new FileOutputStream(targetFile);// 20250825 - 재전송을 위해 
        		fos.write(dataBytes);
        		
        	} finally {
        		try {
        			if (randomFile != null) randomFile.close();
        			if (fos != null) fos.close();        			
        		} catch (IOException ioe) {
        			logger.debug(ioe.getMessage(),ioe);
        		}
        	}
            
        } catch (Exception e) {
            String[] msgArgs = new String[1];
            msgArgs[0] = this.batchDoc.getBatchMsg().getHeader().getProcessCode();
            String errCode = "BECEAIFJI028";
            String errMsg = ExceptionUtil.getErrorCode (e, errCode, msgArgs);
            this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
            logger.error(e.getMessage(),e);
        }

    	return fileInfo;
    }
    
    //---------------- 특정 필드값을 구하는 부분
    // 전문종별코드 필드값 리턴
    public String getTelegramType()
    {
    	String telegramNo = super.getFieldValueString(5);
    	if ( telegramNo.length() < 8 ) return "";
		return telegramNo.substring(0,3) + telegramNo.substring(6,7);
    }

    //응답코드 필드값 리턴
    public String getResCode()
    {
		return super.getFieldValueString(9);
    }

}
