package com.eactive.eai.batch.job.jobModule.Component;

import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;

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

import com.eactive.eai.batch.doc.BatchDoc;
import com.eactive.eai.batch.rule.phaseinfo.PhaseInfoVO;
import com.eactive.eai.batch.running.BatchRunningJobManager;
import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.util.Logger;

public class JobComponent  implements JobComponentService
{

    public BatchDoc batchDoc;

    // FileLoger
    protected Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);

    public String       logHeader;
    public String       logNodeCount;

    // 소켓을 구한다.
    public BatchRunningJobManager bs_man   = BatchRunningJobManager.getInstance();
    public Socket     socket ;
    public String     strUUID      = "";
    public String     strRuleCode  = "";
    public String     strPhaseCode = "";

    public PhaseInfoVO nextPhaseInfoVO = null;

    public JobComponent() {
    }

    public BatchDoc getEAIBatchMessage()
    {
        return batchDoc;
    }

    public void setEAIBatchMessage(BatchDoc batchDoc) throws Exception
    {
        this.batchDoc     = batchDoc;
        this.strUUID      = batchDoc.getBatchMsg().getHeader().getUUID();
        this.strRuleCode  = batchDoc.getBatchMsg().getHeader().getRuleCode();
        this.strPhaseCode = batchDoc.getBatchMsg().getPhaseinfo().getPhaseCode();

        logger = batchDoc.getLogger();
        // 노드카운트를 1 증가시킨다.
        int nNodeCount = batchDoc.getBatchMsg().getBody().getNodeCount();
        batchDoc.getBatchMsg().getBody().setNodeCount(nNodeCount+1);

        logHeader = "["+ batchDoc.getBatchMsg().getHeader().getUUID() +" / "+
                         batchDoc.getBatchMsg().getHeader().getProcessCode() +" / "+
                         batchDoc.getBatchMsg().getHeader().getInstitutionName() +" / "+
                         batchDoc.getBatchMsg().getHeader().getProcessType() +" / "+
                         batchDoc.getBatchMsg().getHeader().getFileName() +" / "+
                         batchDoc.getBatchMsg().getHeader().getRuleCode() +" / "+
                         batchDoc.getBatchMsg().getPhaseinfo().getPhaseCode() +" / "+
                         batchDoc.getBatchMsg().getPhaseinfo().getPhaseType() +"] ";
        logNodeCount = "[NodeCnt-"+ batchDoc.getBatchMsg().getBody().getNodeCount() +" / "+
                                    this.getClass().getName().substring(this.getClass().getName().lastIndexOf(".")+1) +"] ";
    }

    public BatchDoc execute() throws Exception {
        return batchDoc;
    }

    protected void setPreviousTelegramComponent(TelegramService telegramComp) {
        HashMap<String, Object> map = JobProcessData.getInstance().getBatchStageData(strUUID);
        map.remove(JobProcessData.PROCDATA_PRE_TELEGRAM);
        map.put(JobProcessData.PROCDATA_PRE_TELEGRAM, telegramComp);
    }

    public void doErrorAction(TelegramService telegramComp, String errCode) throws Exception
    {
        doErrorAction(null, telegramComp, errCode, null);
    }

    public void doErrorAction(Exception cause, TelegramService telegramComp, String errCode) throws Exception
    {
        doErrorAction(cause, telegramComp, errCode, null);
    }

    public void doErrorAction(TelegramService telegramComp, String errCode, String[] args) throws Exception
    {
        doErrorAction(null, telegramComp, errCode, args);
    }

    public void doErrorAction(Exception cause, TelegramService telegramComp, String errCode, String[] args) throws Exception
    {
        //telegramComp 가 null 이 아니면 다음 수행할 Telegram Component 가 현재 데이터를 참조할 수 있도록
        //현재 Telegram Component를 JobProcessData (PROCDATA_PRE_TELEGRAM) 에 저장해둔다.
        if (telegramComp != null) {
            this.setPreviousTelegramComponent(telegramComp);
        }

        //1. 에러메시지 설정
        String errMsg = ExceptionUtil.getErrorCode(cause, batchDoc, errCode, args);
        batchDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
        logger.error(logHeader+" [" + errMsg+"]");

        String phaseType = batchDoc.getBatchMsg().getPhaseinfo().getPhaseType();
        //=================================================================================================
        // 송신 시 오류가 발생한 경우
        if (phaseType.equals("SEND")) {
            //다음단계를 에러종료 단계로 설정
            batchDoc.getBatchMsg().getBody().setNextPhaseCode(FlowController.PHASECODE_ERROR_END);
            return;
        }

        //=================================================================================================
        //수신 시 오류가 발생한 경우

        //정상수신인데 기대했던 전문종별코드가 아닌경우
        if (errCode.equals(ErrorKeys.ERROR_UNEXPECTED_TELEGRAM_IGNORE)) {
            //다음단계를 바꾸지 않고 그대로 둔다. (정상수신된 부적합한 전문종별코드의 전문을 무시한다.)
            return;
        }

        //다음 단계정보 조회
        String  strUUID     = batchDoc.getBatchMsg().getHeader().getUUID();
        HashMap<String, Object> currdata_hm = JobProcessData.getInstance().getBatchStageData(strUUID);
        if (currdata_hm == null) {
        	logger.error("{} ★★★★★ NO NEXT STAGE INFO ★★★★★", logHeader);
            batchDoc.getBatchMsg().getBody().setNextPhaseCode(FlowController.PHASECODE_ERROR_END);
            return;
        }
        @SuppressWarnings("unchecked")
        ArrayList<PhaseInfoVO> al_curr_poss_next_stage = (ArrayList<PhaseInfoVO>) currdata_hm.get(JobProcessData.PROCDATA_NEXTSTAGE);
        if (al_curr_poss_next_stage == null || al_curr_poss_next_stage.size() == 0) {
        	logger.error("{} ★★★★★ NO NEXT STAGE ★★★★★", logHeader);
            batchDoc.getBatchMsg().getBody().setNextPhaseCode(FlowController.PHASECODE_ERROR_END);
            return;
        }

        //#######################################################################
        //TIMEOUT 오류인 경우
        //#######################################################################
        if (errMsg.indexOf(ErrorKeys.ERROR_TIMEOUT_OVER) > 0) {
            //다음단계 목록에서 TIMEOUT 단계를 찾아 설정한다.
            for (int i=0; i<al_curr_poss_next_stage.size(); i++) {
                PhaseInfoVO vo = al_curr_poss_next_stage.get(i);
                if (vo.getConditionTxt().trim().equalsIgnoreCase(TelegramKeys.TIMEOUT)) {
                    logger.info("{} [TIMEOUT] Next Stage ==> [" + vo.getNextPhaseCode() + "]", logHeader);
                    logger.info("{} ===============================================================", logHeader);
                    batchDoc.getBatchMsg().getBody().setNextPhaseCode(vo.getNextPhaseCode());
                    return;
                }
            }
            logger.info("{} [TIMEOUT] NOT Assigned [TIMEOUT] Condition Next Stage ...  ", logHeader);
            logger.info("{} ===============================================================", logHeader);
            batchDoc.getBatchMsg().getBody().setNextPhaseCode(FlowController.PHASECODE_ERROR_END);

        //#######################################################################
        //응답송신, 응답수신 시 오류이고 Socket 이 연결된 경우
        //(오류전문을 송신한다. 응답코드는 오류가 발생한 지점에서 설정된다.)
//        } else if ((batchDoc.getBatchMsg().getHeader().getProcessType().equals(CommonKeys.PROCESS_RESPONSE_SEND) ||
//                    batchDoc.getBatchMsg().getHeader().getProcessType().equals(CommonKeys.PROCESS_RESPONSE_RECEIVE)) &&
//                    BatchRunningJobManager.getInstance().isSocketClosed(strUUID) == false) {
//            //다음단계 목록에서 가장 첫번째 단계를 설정한다. (SEND 단계)
//            PhaseInfoVO vo = (PhaseInfoVO) al_curr_poss_next_stage.get(0);
//            batchDoc.getBatchMsg().getBody().setNextPhaseCode(vo.getNextPhaseCode());
//            logger.info("{} [응답송수신 수신전문 오류] => 에러전문 송신 Next Phase : ["+vo.getNextPhaseCode()+"]", logHeader);
//
        } else {
            batchDoc.getBatchMsg().getBody().setNextPhaseCode(FlowController.PHASECODE_ERROR_END);
        }
    }
}