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

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.Properties;

import com.eactive.eai.batch.common.FileUtil;
import com.eactive.eai.batch.common.LogUtil;
import com.eactive.eai.batch.common.StringUtil;
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.batch.rule.dirInfo.BatchJobInfoVO;
import com.eactive.eai.batch.rule.dirInfo.DirInfoManager;
import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.util.DatetimeUtil;

public class SEND_KSDBT_0210 extends DefaultTelegram implements TelegramService
{

    private int     SEQUENCE_NO;
    private int     SEND_LENGTH;       //실제 송신할 전문의 총길이

    private Properties telegramInfo;
    private File file;
    private BufferedOutputStream bos;
    private String strFullPath;

    /**
     * 생성자
     */
    public SEND_KSDBT_0210() {
        //DATA응답 전문
    }

    /**
     * 전문조립
     */
    public boolean doExecute() {
        try {

            boolean result = calculateSendLength();
            if (!result) return false;

            //SEQUENCE_NO = this.batchDoc.getEAIBatchMessage().getBody().getSeqNum();
            
            //송신전문의 총 Byte 수
            compileField(0, String.valueOf(SEND_LENGTH), this.al_FieldProps[0]);
            //TR CODE
            compileField(1, telegramInfo.getProperty(TelegramKeys.TRANSACTION_CODE), this.al_FieldProps[1]);
            //기관 ID
            compileField(2, telegramInfo.getProperty(TelegramKeys.BANK_CODE), this.al_FieldProps[2]);
            //전문종별코드
            compileField(3, this.getFldTelegramType(), this.al_FieldProps[3]);
            //통신망관리정보
            //001-업무개시, 002-재개시, 040-종료, 301-회선시험
            compileField(4, this.getFldOpCode(), this.al_FieldProps[4]);
            //데이터전문코드
           	compileField(5, batchDoc.getBatchMsg().getHeader().getBizCode(), this.al_FieldProps[5]);
            //응답코드
            compileField(6, this.getResolveResponseCode(), this.al_FieldProps[6]);
            //전문전송일시
            compileField(7, TelegramKeys.getYYYYMMddHHmmss(), this.al_FieldProps[7]);
          	//전문일련번호
          	compileField(8, ""+ batchDoc.getBatchMsg().getBody().getSeqNum(), this.al_FieldProps[8]);
            //데이터 건수
            compileField(9, "00", this.al_FieldProps[9]);
            //<<전문 완성
            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;
        }
    }



    public boolean doPostExecute() {
        try {
            if (!super.doPostExecute()) return false;
            //DB로그에 남길 전문 헤더 설정
            ByteArrayOutputStream baout = new ByteArrayOutputStream();
            for (int i=0; i<10; i++) { //KSD전문의 헤더는 DATA건수까지 임.
                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("");

            if ( this.getFldOpCode().equals("999") ){
                batchDoc.getBatchMsg().getBody().setSeqNum(0);
                batchDoc.getBatchMsg().getBody().setCurFileSize(-1);
            }
            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;
        }
    }


    public boolean doPreExecute() {
        try {
            if (!super.doPreExecute()) return false;
            telegramInfo = getTelegramInfo();
            String jobCode = this.batchDoc.getBatchMsg().getHeader().getJobCode();
            BatchJobInfoVO bjvo = DirInfoManager.getInstance().getFileInfo( jobCode );
            if ( bjvo != null ){
                batchDoc.getBatchMsg().getHeader().setRecLen((int)bjvo.getFileRecSize());
            }
            checkPrevRecvFile();
            processPrevData();
            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 int getSendLength()
    {
        try {
            return 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;
        }
    }

    /**
     * int getCalculatedLength(int idx)
     * --------------------------------------------------------------------------------------
     * 전달된 인덱스 idx는 비정형 필드여야 한다. 즉 필드의 길이값이 FILE_NO_LENGTH("XX") 이어야 한다.
     * 해당 비정형 필드에 대해 실질적인 전문길이를 동적으로 계산해 낸다.
     * RECV : 수신 길이 계산
     */
    public int getCalculatedLength(int idx) {

    	if (idx >= this.getFieldCount()) {
            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)) {
            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;
        }
        return 0;
    }
    public int getInformalFieldSendData(int idx, byte[] data) {
    	int fldLen = getCalculatedLength(idx);
        try {
            if (idx >= this.getFieldCount() ) {
                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 < fldLen) {
                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;
            }
            return fldLen;
        } 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;
        }
    }


    private boolean calculateSendLength () {
        try {
        	for (int i=0; i< this.al_Field.size()-1; i++) {
                byte[] aField = (byte[]) this.al_Field.get(i);
                SEND_LENGTH += aField.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 void checkPrevRecvFile(){
		if ( !createFile() ){
			// 이전 수신 파일 없음!! SKIP!!!
			SEQUENCE_NO = 0;
			return;
		}
		BufferedInputStream bis = null;
		try {
			bis = new BufferedInputStream( new FileInputStream(file));
			byte[] fileLine = null;
			byte[] lastLine = null;
			while (( fileLine = FileUtil.readLine(bis)) != null ){
				lastLine = fileLine; 
			}
			//logger.debug("lastLine-->" +  new String(lastLine));
			byte[] byte_seq   = new byte[8];
			System.arraycopy(lastLine, 0, byte_seq, 0, 8);
			SEQUENCE_NO  = Integer.parseInt( new String(byte_seq));
			
			//일련번호 에러와 함께 최종 받은 SEQNUM 재전송
			batchDoc.getBatchMsg().getBody().setSeqNum(SEQUENCE_NO);
				
		} catch (FileNotFoundException fne) {
			return;
		} catch (Exception e) {
			logger.error( e.getMessage(), e);
			return;
		}finally{
			try {
				if ( bis != null ) {
					bis.close();
				}
			} catch (Exception e) {}
		}

    }
    
    private void processPrevData(){
        String prevTelegramHeader = batchDoc.getBatchMsg().getTelegramHeader();
        String recvOpCode = prevTelegramHeader.substring(22,25);
        
        
        // 1. 받은 시퀀스 체크
        int recvSeq = 0;
        try {
            recvSeq = Integer.parseInt(prevTelegramHeader.substring(51,59));
		} catch (Exception e) {
            String[] msgArgs = new String[2];
            msgArgs[0] = "" + batchDoc.getBatchMsg().getBody().getSeqNum();
            msgArgs[1] = prevTelegramHeader.substring(51,59);
            String errCode = "BECEAIFJI045";
            String errMsg = ExceptionUtil.getErrorCode ( errCode, msgArgs);
            this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
			this.setResolveResponseCode("99");
			return;
		}
		
		if ( recvOpCode.equals("000")){
//			if ( SEQUENCE_NO + 1 != recvSeq ){
//	            String[] msgArgs = new String[2];
//	            msgArgs[0] = "" + SEQUENCE_NO;
//	            msgArgs[1] = "" + recvSeq;
//	            String errCode = "BECEAIFJI045";
//	            String errMsg = ExceptionUtil.getErrorCode ( errCode, msgArgs);
//	            this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
//	            this.setResolveResponseCode("99");
//	            return;
//			}
		}else if ( recvOpCode.equals("999")){
			if ( batchDoc.getBatchMsg().getBody().getSeqNum() != recvSeq ){
	            String[] msgArgs = new String[2];
	            msgArgs[0] = "" + batchDoc.getBatchMsg().getBody().getSeqNum();
	            msgArgs[1] = "" + recvSeq;
	            String errCode = "BECEAIFJI045";
	            String errMsg = ExceptionUtil.getErrorCode ( errCode, msgArgs);
	            this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
	            this.setResolveResponseCode("99");
	            return;
			}
		}
		
		// 2. 건수 체크
        @SuppressWarnings("unused")
		int recCount = 0;
        try {
        	recCount = Integer.parseInt(prevTelegramHeader.substring(59,61));
		} catch (Exception e) {
            String[] msgArgs = new String[1];
            msgArgs[0] = prevTelegramHeader.substring(59,61);
            String errCode = "BECEAIFJI046";
            String errMsg = ExceptionUtil.getErrorCode ( errCode, msgArgs);
            this.batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
			this.setResolveResponseCode("9A");
			return;
		}

		try {
			if ( !createFile() ){
				logger.error( "수신 파일 생성 오류" );
	            this.setResolveResponseCode("09");
	            return ;
			}
			if ( recvOpCode.equals("000")){
				bos = new BufferedOutputStream (new FileOutputStream(file, true));   //bytes will be written to the end of the file rather than the beginning
				
				long lnCurSize = batchDoc.getBatchMsg().getBody().getCurFileSize();
				if ( lnCurSize < 1 ) {
					LogUtil.setLogFileStart(batchDoc);
				}
				
                // 레코드 크기
                int recSize = batchDoc.getBatchMsg().getHeader().getRecLen();
		        String prevTelegramBody = batchDoc.getBatchMsg().getTelegramBody();
				byte [] fileData = new byte[recSize];
				byte [] byteCnt = new byte[2];
				System.arraycopy(prevTelegramHeader.getBytes(), 59, byteCnt, 0, 2);
				int recCnt = 0;
				try {
					recCnt = Integer.parseInt(new String(byteCnt));
				} catch (Exception e) {}
				
				for (int inx = 0; inx < recCnt; inx++) {
					System.arraycopy(prevTelegramBody.getBytes(), ( inx * (recSize + 8)) + 8, fileData, 0, recSize);
					bos.write(fileData);
					bos.write('\n');
					if ( lnCurSize < 1 ) {
						batchDoc.getBatchMsg().setFileHeader(new String(fileData));
					}
					if ( inx == recCnt -1 ){
						batchDoc.getBatchMsg().setFileTrailer(new String(fileData));
					}
		            lnCurSize += recSize;
		            batchDoc.getBatchMsg().getBody().setCurFileSize(lnCurSize);
		            try {
			            batchDoc.getBatchMsg().getHeader().setTotRecCnt(lnCurSize/recSize);
					} catch (Exception e) {
			            batchDoc.getBatchMsg().getHeader().setTotRecCnt(1);
					}
				}
				bos.close();
				SEQUENCE_NO = recvSeq + recCnt -1;
				batchDoc.getBatchMsg().getBody().setSeqNum( SEQUENCE_NO );

								
			}else if (recvOpCode.equals("999")){
				
				String strArchFileName = StringUtil.realToArchDir(this.strFullPath);
				File rcvArchFile  = new File( strArchFileName );
//				if ( rcvArchFile.exists() ) {
//					String strHHMMSS = CalendarUtil.getCurrentTimeNoDash();
//					strArchFileName = strArchFileName + "_" + strHHMMSS;
//					rcvArchFile = new File( strArchFileName );
//					batchDoc.getBatchMsg().getHeader().setRenamedFileName(batchDoc.getBatchMsg().getHeader().getFileName() + "_" + CalendarUtil.getCurrentTimeNoDash());
//				}else{
//					batchDoc.getBatchMsg().getHeader().setRenamedFileName(batchDoc.getBatchMsg().getHeader().getFileName());
//				}
				batchDoc.getBatchMsg().getHeader().setRenamedFileName(batchDoc.getBatchMsg().getHeader().getFileName());

				if ( !file.exists() ){
					file.createNewFile();
				}
				//File 종료시간 설정
				batchDoc.getBatchMsg().getBody().setPhaseEndTime(DatetimeUtil.getCurrentTimeMillis());
				//DB로그에 남길 파일 헤더,트레일러 내용 설정
				batchDoc.getBatchMsg().getHeader().setFileSize(batchDoc.getBatchMsg().getBody().getCurFileSize());
                // 레코드 크기
                int recSize = batchDoc.getBatchMsg().getHeader().getRecLen();
                if ( recSize <= 0 ){
    				batchDoc.getBatchMsg().getHeader().setTotRecCnt(1);
                }else{
                	int recCnt = (int)batchDoc.getBatchMsg().getBody().getCurFileSize() / recSize;
    				batchDoc.getBatchMsg().getHeader().setTotRecCnt(recCnt);
                }


				if ( file.length()==0 ){
					LogUtil.setLogFileStart(batchDoc);
				}

				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}]
		            this.setResolveResponseCode("09");
		            return ;
				}
				//수신 Root 디렉토리에 동일 파일명의 0 byte 의 Dummy 파일 생성
				logger.info("{} >>>>> 수신 파일과 동일 파일명의 0 Byte 파일을 Root 디렉토리에 생성......(업무 서버에 자동 송신하도록 수신 File Event 발생)", logHeader);
				File rcvRootFile = new File( StringUtil.realToRootDir(strFullPath) );

				if (!rcvRootFile.createNewFile()) {
					String errMsg = ExceptionUtil.getErrorCode("BECEAIFJI031", new String[] {rcvRootFile.getAbsolutePath()});
					batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);	//수신 Root 디렉토리에 0 Byte 파일을 생성할 수 없습니다. [Path: {1}]
		            this.setResolveResponseCode("09");
		            return ;
				}

				LogUtil.setLogFileEnd(batchDoc);

			}else{ // 발생가능성은 없으나 혹시나 하여..
				bos.close();
			}
		} 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);
            this.setResolveResponseCode("09");
            return ;
		}
		//에러 상황이 해제되면 에러가 아닌 정상 거래로 처리
		this.batchDoc.getBatchMsg().getBody().setErrorMsg("");
		this.setResolveResponseCode("00");
		
    }

    private boolean createFile () {
        try {
        	
			String fileName =  batchDoc.getBatchMsg().getHeader().getFileName();
            strFullPath = batchDoc.getBatchMsg().getHeader().getFilePath();
            if (strFullPath.charAt(strFullPath.length()-1) != File.separatorChar) {
                strFullPath = strFullPath + File.separator;
            }
            strFullPath = strFullPath + fileName;
            file = new File(strFullPath);
        } 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;
    }

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

