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

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;

import com.eactive.eai.batch.job.jobConstant.TelegramKeys;
import com.eactive.eai.batch.job.jobHandle.JobProcessData;
import com.eactive.eai.batch.job.jobItem.DefaultTelegram;
import com.eactive.eai.batch.job.jobItem.TelegramService;

import com.eactive.eai.batch.common.FileUtil;
import com.eactive.eai.batch.common.StringUtil;
import com.eactive.eai.batch.osd.OutsideManager;
import com.eactive.eai.batch.osd.OutsideVO;
import com.eactive.eai.batch.rule.dirInfo.BatchJobInfoVO;
import com.eactive.eai.batch.rule.dirInfo.DirInfoManager;
import com.eactive.eai.common.exception.ExceptionUtil;

public class RECV_DEBIT_0320 extends DefaultTelegram implements TelegramService {
    private int INFORMALFIELD_INDEX = 11;
    private ByteArrayOutputStream bout;
    private File file;
    private FileOutputStream fout;
    private String strFullPath = "";

    /**
     * 생성자
     */
    public RECV_DEBIT_0320() {
        //DATA 수신
        bout = new ByteArrayOutputStream();
    }

    /**
     * 전문 해체하기
     */
    public boolean doExecute() {
        if (!super.doExecute()) return false;

        try {
            String fName    = new String ((byte[]) al_Field.get(4));
            //파일명으로 부터 거래 구분 코드 추출
            int bizCodeStartIndex = 0;
            int bizCodeEndIndex   = 0;
            String processCode = batchDoc.getBatchMsg().getHeader().getProcessCode();
            String institutionCode = batchDoc.getBatchMsg().getHeader().getInstitutionCode();
            ArrayList<OutsideVO> organList = OutsideManager.getInstance().getOutsideInfo(processCode);
            for (int i=0; organList!=null && i<organList.size(); i++) {
                OutsideVO organInfo = organList.get(i);
                if ( institutionCode.equals(organInfo.getOsdCode()) ) {
                    bizCodeStartIndex = organInfo.getBizCdStartIdx();
                    bizCodeEndIndex   = organInfo.getBizCdEndIdx();
                    break;
                }
            }
            if (bizCodeStartIndex <= 0 || bizCodeStartIndex >= fName.length()) bizCodeStartIndex = 0;
            if (bizCodeEndIndex   <= 0 || bizCodeEndIndex   >  fName.length()) bizCodeEndIndex = fName.length();
            String bizCode = fName.substring(bizCodeStartIndex, bizCodeEndIndex);
            batchDoc.getBatchMsg().getHeader().setBizCode(bizCode);

            BatchJobInfoVO bJobInfo = DirInfoManager.getInstance().getFileInfoByDstcd(processCode, bizCode);

            String pattern = null;
            if ( bJobInfo!= null ){
                pattern = bJobInfo.getSndrcvFileName();
                batchDoc.getBatchMsg().getHeader().setRecLen((int)bJobInfo.getFileRecSize());
            }
            String recvFileName = FileUtil.getRecvFileName(fName, pattern, batchDoc);
            batchDoc.getBatchMsg().getHeader().setFileName(recvFileName);
            
            String _block_no  = new String ((byte[]) al_Field.get(8));
            String _seq_no    = new String ((byte[]) al_Field.get(9));
            int recv_block_no = Integer.parseInt(_block_no);
            int recv_seq_no   = Integer.parseInt(_seq_no);

            int block_no = batchDoc.getBatchMsg().getBody().getBlockNum();

           //중간 블럭 데이터 손실되었거나, 지금까지 수신한 블럭의 크기가 현재 받은 블럭의 크기보다 크면 Error
             if (( recv_block_no != 9999 ) && ((recv_block_no - block_no) > 1 || (recv_block_no - block_no) < 0 )) {
                logger.debug("{}  doExecute >> recived block_no is bigger than current block_no", logHeader);
                this.setConditionTxt(TelegramKeys.ERROR);

                String[] msgArgs = new String[3];
                msgArgs[0] = this.batchDoc.getBatchMsg().getHeader().getProcessCode();
                msgArgs[1] = _block_no;
                msgArgs[2] = ""+block_no;
                String errCode = "BECEAIFJI024";
                String errMsg = ExceptionUtil.getErrorCode (errCode, msgArgs);
                this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);

                return false;

            }

            batchDoc.getBatchMsg().getBody().setBlockNum(recv_block_no);
            batchDoc.getBatchMsg().getBody().setSeqNum(recv_seq_no);
            if ( recv_block_no == 0 || recv_block_no == 9999) {
                if (!createFile(recv_block_no == 0)) {
                    return false;
                }
                if (recv_block_no == 9999) {
                    this.setConditionTxt(TelegramKeys.EOF);
                }
            }

        } 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;
        }

        return true;
    }

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

            String _block_no  = new String ((byte[]) al_Field.get(8));
            String _seq_no    = new String ((byte[]) al_Field.get(9));
            int recv_block_no = Integer.parseInt(_block_no);
            int recv_seq_no   = Integer.parseInt(_seq_no);

            JobProcessData job = JobProcessData.getInstance();
            String uuid = this.batchDoc.getBatchMsg().getHeader().getUUID();
            HashMap<String, Object> hm = job.getBatchStageData(uuid);

            byte[] newLine = new byte[1];
            newLine[0] = '\n';
            
            int recLen = batchDoc.getBatchMsg().getHeader().getRecLen();
            if (recLen < 10 ){
            	recLen = bout.toByteArray().length;
            }
            byte[] recvData = new byte[recLen];
            for (int inx = 0; inx < recvData.length; inx++) {
				recvData[inx] = ' ';
			}

            if ( recv_block_no == 0 ){  // 받은 데이터가 헤더 이면
            	System.arraycopy(bout.toByteArray(), 0, recvData, 0, Math.min(recLen, bout.toByteArray().length));
                fout.write( recvData );
                fout.write(newLine);
                fout.close();
//                logger.debug("VAN TEST HEADER\n" + CommonLib.getDumpMessage(bout.toByteArray()));
                batchDoc.getBatchMsg().setFileHeader(new String(bout.toByteArray()));
                try {
                    String procCode = batchDoc.getBatchMsg().getHeader().getProcessCode();
                    String bizCode = batchDoc.getBatchMsg().getHeader().getBizCode();
                    BatchJobInfoVO info = DirInfoManager.getInstance().getFileInfoByDstcd(procCode, bizCode);
                    batchDoc.getBatchMsg().getHeader().setRecLen((int)info.getFileRecSize());
                } catch (Exception e) { // 에러가 나도 아무것도 안함
                    // do nothing
                }

//                batchDoc.getBatchMsg().getHeader().setFileSize( Integer.parseInt(new String(bout.toByteArray()).substring(23,30)) * batchDoc.getBatchMsg().getHeader().getRecLen());
//            	int recCnt = (int)batchDoc.getBatchMsg().getHeader().getFileSize()/batchDoc.getBatchMsg().getHeader().getRecLen();
//            	batchDoc.getBatchMsg().getHeader().setTotRecCnt(recCnt);

            } else if ( recv_block_no == 9999 ) {  // 받은 데이터가 트레일러 이면
            	System.arraycopy(bout.toByteArray(), 0, recvData, 0, Math.min(recLen, bout.toByteArray().length));
                fout.write( recvData );
                fout.write(newLine);
                fout.close();
                batchDoc.getBatchMsg().setFileTrailer(new String(bout.toByteArray()));
//                logger.debug("VAN TEST TRAILER\n" + CommonLib.getDumpMessage(bout.toByteArray()));
                
                if ( !moveFile())
                    return false;
                
            } else if (recv_block_no > 0){
                // 강제 결번 세팅
//            } else if ((recv_block_no > 0) && ( recv_seq_no%30 != 5 )  ){
                @SuppressWarnings("unchecked")
                HashMap<Integer, byte[]> block_data = (HashMap<Integer, byte[]>) hm.get(JobProcessData.PROCDATA_BLOCKDATA);
                if (block_data == null) {
                    block_data = new HashMap<Integer, byte[]>();
                }
                block_data.put( new Integer(recv_seq_no-1) ,  bout.toByteArray());

                hm.put(JobProcessData.PROCDATA_BLOCKDATA, block_data);

            }

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

            //DB로그에 남길 전문 바디 설정
            baout = new ByteArrayOutputStream();
            for (int i=7; 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;
        } 

    }

    /**
     * 전문 Validation
     */
    public boolean doValidation()
    {
        if (!super.doValidation()) return false;

        return true;
    }

    /**
     * int getCalculatedLength(int idx)
     * --------------------------------------------------------------------------------------
     * 전달된 인덱스 idx는 비정형 필드여야 한다. 즉 필드의 길이값이 FILE_NO_LENGTH("XX") 이어야 한다.
     * 해당 비정형 필드에 대해 실질적인 전문길이를 동적으로 계산해 낸다.
     * SEND : 송신 길이 계산
     * RECV : 수신 길이 계산
     */
    public int getCalculatedLength(int idx) {
        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)) {
            try {
                String byte_size = new String ((byte[]) al_Field.get(0));
                logger.info("{} the sum of definite field length [" + byte_size + "]", logHeader);
                int preLen = 0;
                for (int inx = 1; inx < idx; inx++) {
                    byte[] aField = (byte[]) this.al_Field.get(inx);
                    preLen += aField.length;
                }
                return Integer.parseInt(byte_size) - preLen;
            } 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;
            }

        } 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);

            return -1;
        }
    }

    public boolean doInformalField(int idx, byte[] data, int length)
    {
        try {
            if (idx == INFORMALFIELD_INDEX) {
                bout.write(data, 0, length);
                al_Field.set(idx, bout.toByteArray());
            } else {
                logger.debug("{} doInformalField >> index of informal action error : " + idx, logHeader);

                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);

                return false;
            }
        } catch (Exception ex) {
            String[] msgArgs = new String[1];
            msgArgs[0] = this.batchDoc.getBatchMsg().getHeader().getProcessCode();
            String errCode = "BECEAIFJI004";
            String errMsg = ExceptionUtil.getErrorCode (ex, errCode, msgArgs);
            this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
            logger.error( ex.getMessage(), ex);
            return false;
        }
        return true;
    }
    private boolean createFile ( boolean init) {
        try {
            strFullPath = batchDoc.getBatchMsg().getHeader().getFilePath();
            if (strFullPath.charAt(strFullPath.length()-1) != File.separatorChar) {
                strFullPath = strFullPath + File.separator;
            }
            strFullPath = strFullPath + batchDoc.getBatchMsg().getHeader().getFileName();
            logger.info("{}  getCalculatedLength >> File full-path [" + strFullPath + "]", logHeader);
            file = new File(strFullPath);
            fout = new FileOutputStream(file, !init);   //bytes will be written to the end of the file rather than the beginning
        } 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 false;
        }
        return true;
    }
    
    private boolean moveFile() throws Exception{
        
        File rcvArchFile  = new File( StringUtil.realToArchDir(this.strFullPath) );
        File rcvErrorFile = new File( StringUtil.realToErrorDir(this.strFullPath) );

        //응답코드가 000 (성공) 이 아니면 Error 디렉토리로 옮기고 리턴
        if ( !super.getResolveResponseCode().equals(TelegramKeys.KFB_RET_CODE_SUCCESS) ) {
            // 수신 파일을 수신 Real 디렉토리 -> 수신 Error 디렉토리로 이동 (파일명 변경 안함)
            logger.info("{} >>>>> 수신 파일을 수신 Real 디렉토리 -> 수신 Error 디렉토리로 이동.....", logHeader);
            boolean isSuccessMoveFile = file.renameTo(rcvErrorFile);
            if (!isSuccessMoveFile) {
                String errMsg = ExceptionUtil.getErrorCode("BECEAIFJI042", new String[] {file.getAbsolutePath(), rcvArchFile.getAbsolutePath()});
                if (!batchDoc.getBatchMsg().getBody().getErrorMsg().equals("")) {
                    errMsg += "\n caused by..." + batchDoc.getBatchMsg().getBody().getErrorMsg();
                }
                batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);    //수신 파일을 수신 Real 디렉토리에서 수신 Error 디렉로 이동시 오류가 발생하였습니다. [Real Path: {1}] [Error Path: {2}]
            }
            return false;
        }

        //3. 수신 파일을 수신 Real 디렉토리 -> 수신 Arch 디렉토리로 이동 (파일명 변경 안함)
        logger.info("{} >>>>> 수신 파일을 수신 Real 디렉토리 -> 수신 Arch 디렉토리로 이동.....", logHeader);
        boolean isSuccessMoveFile = file.renameTo(rcvArchFile);
        if (!isSuccessMoveFile) {
            String errMsg = ExceptionUtil.getErrorCode("BECEAIFJI030", new String[] {file.getAbsolutePath(), rcvArchFile.getAbsolutePath()});
            batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);    //수신 파일을 수신 Real 디렉토리에서 수신 Arch 디렉로 이동시 오류가 발생하였습니다. [Real Path: {1}] [Arch Path: {2}]
            return false;
        }

        //4-1. 수신 Root 디렉토리에 동일 파일명의 0 byte 의 Dummy 파일 생성
        logger.info("{} >>>>> 수신 파일과 동일 파일명의 0 Byte 파일을 Root 디렉토리에 생성......(호스트에  자동 송신하도록 수신 File Event 발생)", logHeader);
        try {
            File rcvRootFile = new File( StringUtil.realToRootDir(this.strFullPath) );
            rcvRootFile.createNewFile();
        } catch (Exception ex) {
            String errMsg = ExceptionUtil.getErrorCode(ex, "BECEAIFJI031", new String[] { StringUtil.realToRootDir(this.strFullPath) });
            batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);    //수신 Root 디렉토리에 0 Byte 파일을 생성할 수 없습니다. [Path: {1}]
            return false;
        }

        return true;
    }

    //---------------- 특정 필드값을 구하는 부분
    // 전문종별코드 필드값 리턴
    public String getTelegramType()
    {
        return super.getFieldValueString(3);
    }
    // 거래구분코드 필드값 리턴
    public String getTrClass()
    {
        return super.getFieldValueString(7);
    }
    //응답코드 필드값 리턴
    public String getResCode()
    {
        return super.getFieldValueString(6);
    }
}