package com.eactive.eai.agent.web;

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.eactive.eai.adapter.socket.outbound.OutboundSocketClient;
import com.eactive.eai.batch.common.CalendarUtil;
import com.eactive.eai.batch.common.CommonKeys;
import com.eactive.eai.batch.common.LogUtil;
import com.eactive.eai.batch.doc.BatchDoc;
import com.eactive.eai.batch.message.EAIBatchMsgManager;
import com.eactive.eai.batch.osd.OutsideLinkVO;
import com.eactive.eai.batch.osd.OutsideManager;
import com.eactive.eai.batch.osd.OutsideVO;
import com.eactive.eai.batch.rule.ruleinfo.RuleInfoManager;
import com.eactive.eai.batch.rule.ruleinfo.RuleInfoVO;
import com.eactive.eai.batch.running.BatchRunningJobManager;
import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.UUIDGenerator;
import com.eactive.eai.inbound.ResponseHandler;

/**
 * 회선상태 체크 Agent
 */
public class CheckLine  extends HttpServlet
{
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	public static final int ERROR_NO_ERROR             = 0;
    //BatchRunningJobManager 에서 UUID에 해당하는 소켓인스탄스를 찾을 수 없다.
    public static final int ERROR_NO_SOCKET            = 1;
    public static final int ERROR_NO_PROCDATA          = 2;
    public static final int ERROR_NO_NEXTSTAGE         = 3;
    public static final int ERROR_TELEGRAM_COMPILE     = 4;
    public static final int ERROR_RECV_PRE_LENGTH      = 5;
    public static final int ERROR_RECV_ERROR           = 6;
    public static final int ERROR_TIMEOUT_OVER         = 7;
    public static final int ERROR_RECV_SHORT_LENGTH    = 8;
    public static final int ERROR_LENGTH_PARSE         = 9;
    public static final int ERROR_UNEXPECTED_TELEGRAM  = 10;
    public static final int ERROR_NO_CLASS_DEFINITION  = 11;
    public static final int ERROR_NO_TELEGRAM_ID       = 12;
    public static final int ERROR_WRITE_ERROR          = 13;
    public static final int ERROR_SEND_VALIDATION      = 14;
    public static final int ERROR_RECV_VALIDATION      = 15;
    public static final int ERROR_POST_EXECUTION       = 16;
    public static final int ERROR_EXECUTION            = 17;
    public static final int ERROR_ERR_TELEGRAM_META    = 18;
    public static final int ERROR_INFORMAL_ACTION      = 19;
    public static final int ERROR_READ_FILE            = 20;
    // 플로우 컴포넌트에서 송수신 중 비정형필드에 대한 처리데이터 길이를 구할 수 없다.
    public static final int ERROR_INFORMAL_FIELD_LENGTH= 21;
    // 소켓연결 중 소켓 포트정보가 없다.
    public static final int ERROR_NO_SOCKET_PORT        = 22;
    // Outbound 소켓연결 중 연결 실패
    public static final int ERROR_FAIL_TO_CONNECT       = 23;

    Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
    String errorMsg = "";
    private final String ruleID = "CH001";

   /**
    * 1. 기능 :  요청으로 전달된 Command 실행
    * 2. 처리 개요 : 요청으로 전달된 Command 실행하고 실행된 결과를 ObjectOutStream을 통해 전송
    * 3. 주의사항
    *
    * @param    request     HttpServletRequest
    * @param    response    HttpServletResponse
    * @return
    * @exception
    **/
    public void service(HttpServletRequest request, HttpServletResponse response) {
        try {
            logger.info("[CheckLine] Servlet starting .......");
            String strProcessCodeCode = request.getParameter("processCode");
            String strOrganCode       = request.getParameter("organCode");
            String strBizCode         = request.getParameter("bizCode");
            String strIP              = request.getParameter("organIP");
            String strPort            = request.getParameter("organPort");
            int    nPort = -1;
            try {
                nPort = Integer.parseInt(strPort);
            } catch (Exception ex) {
                nPort = -1;
            }
            response.setContentType("text/html;charset=euc-kr");

            if (strOrganCode==null||strOrganCode.length()==0||
                strIP==null||strIP.length()==0||nPort==-1) {
                logger.info("[CheckLine] ▷▷▷ URL format error !!!! ");
                response.getWriter().println("[ERROR] URL FORMAT ERROR<BR>");
                response.getWriter().println("-->URL PATTERN<BR>");
                response.getWriter().println("<BR>");
                response.getWriter().println("http://" + request.getServerName()+":"+request.getServerPort()+  request.getContextPath() + "/CheckLine?organCode=IL03&bizCode=0000300&organIP=172.17.61.71&organPort=41021 &nbsp&nbsp▷▷▷회선체크 URL 형식<BR>" );
            } else {
                //BatchMsgDoc 생성
                BatchDoc batchMsgDoc = EAIBatchMsgManager.createBatchMsgWithUUID(true);  //true:초기화함
        
                //BatchMsgDoc Layer, SubLayer, StartTime 설정
                EAIBatchMsgManager.updateBatchMsgWithStageTime(batchMsgDoc, CommonKeys.LAYER_FLOW_CONTROLLER, CommonKeys.SUB_LAYER_FLOW_CONTROLLER);
                
                batchMsgDoc = setBatchMessage(batchMsgDoc, strProcessCodeCode, strOrganCode, strBizCode, strIP, strPort) ;
                if (batchMsgDoc == null) {
                    logger.info("[CheckLine] : BatchMsg is NULL!! >>" + this.errorMsg);
                    response.getWriter().println("[ERROR] "  + this.errorMsg);
                    return;
                }

                // OutboundSocketHandle처럼 소켓을 만들어서 BatchRunningJobManager 등록 해준다.
                Socket socket=null;

                try {
                    socket=new Socket(strIP, nPort);
                } catch (UnknownHostException e) {
                    String errMsg = ExceptionUtil.getErrorCode(e, "BECEAIASC001", new String[] {strIP, Integer.toString(nPort)});
                    throw new Exception(errMsg);	//Socket 연결 에러 (IP: %1, Port: %2), 서버를 찾을 수 없습니다.
                }	catch(IOException e){
                    StringBuffer sb = new StringBuffer();
                    sb.append("[ERROR] IP[" + strIP +"]");
                    sb.append("PORT[" + strPort + "] socket connection error");
                    sb.append("[" + e.getLocalizedMessage() + "]");
                    response.getWriter().println(sb.toString());
//                    String errMsg = 
                    	ExceptionUtil.getErrorCode(e, "BECEAIASC002", new String[] {strIP, Integer.toString(nPort)});

                    logger.error( e.getMessage(), e);
                    return;
                }

                String strUUID = batchMsgDoc.getBatchMsg().getHeader().getUUID();
                OutboundSocketClient socketClient = new OutboundSocketClient(socket);
                BatchRunningJobManager.getInstance().addRunningJobInfo(strUUID, socketClient, batchMsgDoc);

                logger.info("[CheckLine]  : FlowController JPD call & start ");
                String startTime = CalendarUtil.getCurrentTimeNoDash();
                batchMsgDoc.getBatchMsg().getBody().setPhaseStartTime(startTime);
                batchMsgDoc.getBatchMsg().getBody().setPhaseEndTime(startTime);
                LogUtil.setStartLog(batchMsgDoc);
                ResponseHandler handler = new ResponseHandler();
                batchMsgDoc = handler.execute(batchMsgDoc);
                logger.info("[CheckLine]  : FlowController JPD call & end ");

                // BatchRunningJobManager 에서 제거한다.
                BatchRunningJobManager.getInstance().removeRunningJobInfo(strUUID);
                try {
                    socket.close();
                } catch (UnknownHostException e) {
                    String errMsg = ExceptionUtil.getErrorCode(e, "BECEAIASC001", new String[] {strIP, Integer.toString(nPort)});
                    throw new Exception(errMsg);	//Socket 연결 에러 (IP: %1, Port: %2), 서버를 찾을 수 없습니다.
                }	catch(IOException e){
                    String errMsg = ExceptionUtil.getErrorCode(e, "BECEAIASC002", new String[] {strIP, Integer.toString(nPort)});
                    throw new Exception(errMsg);	//Socket 연결 에러 (IP: %1, Port: %2), I/O Exception이 발생했습니다.
                }

                // 결과를 확인한다.
                int nErrorCode = batchMsgDoc.getBatchMsg().getBody().getErrorCode();
                if (nErrorCode == ERROR_NO_ERROR) {
                    // 성공 ...
                    String strResponseCode = batchMsgDoc.getBatchMsg().getBody().getLastResCode();
                    if (strResponseCode.equalsIgnoreCase("000")) {
                        StringBuffer sb = new StringBuffer();
                        sb.append("[SUCCESS] IP[" + strIP +"]");
                        sb.append("PORT[" + strPort + "] connection test ok!!!");
                        response.getWriter().println(sb.toString());
                    } else {
                        StringBuffer sb = new StringBuffer();
                        sb.append("[ERROR] IP[" + strIP +"]");
                        sb.append("PORT[" + strPort + "] Receive Error response Code");
                        sb.append("[" + strResponseCode + "]");
                        response.getWriter().println(sb.toString());
                    }
                } else {
                    // 실패 ...
                    StringBuffer sb = new StringBuffer();
                    sb.append("[ERROR]");
                    sb.append("ERROR CODE [" + nErrorCode + "]" + this.getErrorMsg(nErrorCode));
                    response.getWriter().println(sb.toString());
                }
            }
        } catch (Exception ex) {
        	logger.error( ex.getMessage(), ex);
            response.setStatus(500);
            try {
                response.getWriter().println(ex.getMessage());
                throw ex;
            } catch (Exception e) {
                // IGNORE
            }
        }
    }

    public BatchDoc setBatchMessage(BatchDoc batchMsgDoc, String strBatchCode, String strOsdCode, String strBizCode, String strTargetIP, String strTargetPort)
    {
        //----------------------------------------------------------------------------------------
    	ArrayList<OutsideVO> osd_array = OutsideManager.getInstance().getOutsideInfo(strBatchCode);
        if (osd_array == null) {
            this.errorMsg = "Not found outside institution information list of Batch Job Code["+strBatchCode+"]";
            logger.debug(this.errorMsg);
            return null;
        }
        int i = 0;
        for (i=0; i<osd_array.size(); i++) {
            OutsideVO vo = (OutsideVO) osd_array.get(i);
            if (vo.getOsdCode().equalsIgnoreCase(strOsdCode)) {
                break;
            }
        }
        if (i ==  osd_array.size()) {
            this.errorMsg = "Not found outside institution information by 대외기관코드["+strOsdCode+"] 배치업무코드["+strBatchCode+"]";
            logger.debug(this.errorMsg);
            return null;
        }
        OutsideVO ovo = (OutsideVO) osd_array.get(i);

        ArrayList<OutsideLinkVO> link_Array = OutsideManager.getInstance().getOutsideLinkInfo(strOsdCode);
        if (link_Array == null) {
            this.errorMsg = "Not found outside link list(TSEAIBJ05) of institution code in OutsideManager ["+strOsdCode+"]";
            logger.debug(this.errorMsg);
            return null;
        }
        int idx = 0;
        OutsideLinkVO linkVO = null;
        for (idx = 0; idx< link_Array.size(); idx++) {
            linkVO = (OutsideLinkVO) link_Array.get(idx);
            if (linkVO.getLinkIP().equalsIgnoreCase(strTargetIP) && linkVO.getLinkPort().trim().equalsIgnoreCase(strTargetPort)) {
                break;
            }
        }
        if (idx == link_Array.size()) {
            this.errorMsg = "Not found outside link information by mapping IP["+strTargetIP+"] Port["+strTargetPort+"]";
            logger.debug(this.errorMsg);
            return null;
        }
        String uuid = UUIDGenerator.getUUID();
        batchMsgDoc.getBatchMsg().getHeader().setUUID(uuid);
        batchMsgDoc.getBatchMsg().getHeader().setProcessCode(ovo.getBatchCode());
		batchMsgDoc.getBatchMsg().getHeader().setProcessName(ovo.getBatchName());
        batchMsgDoc.getBatchMsg().getHeader().setProcessType(CommonKeys.PROCESS_REQUEST_SEND);
        batchMsgDoc.getBatchMsg().getHeader().setInstitutionCode(ovo.getOsdCode());
        batchMsgDoc.getBatchMsg().getHeader().setInstitutionName(ovo.getOsdName());
        batchMsgDoc.getBatchMsg().getHeader().setScheduleCode("");
        batchMsgDoc.getBatchMsg().getHeader().setScheduleSTime("");
        batchMsgDoc.getBatchMsg().getHeader().setScheduleETime("");
        batchMsgDoc.getBatchMsg().getHeader().setFilePath("");
        batchMsgDoc.getBatchMsg().getHeader().setFileName("");
        batchMsgDoc.getBatchMsg().getHeader().setRenamedFileName("");
        batchMsgDoc.getBatchMsg().getHeader().setJobCode("");
        batchMsgDoc.getBatchMsg().getHeader().setBizCode(strBizCode);
        batchMsgDoc.getBatchMsg().getHeader().setFlowCode(this.ruleID);
        batchMsgDoc.getBatchMsg().getHeader().setRuleCode(this.ruleID);
        // RULE 정보 조회
        RuleInfoVO vo = RuleInfoManager.getInstance().getRuleInfo(this.ruleID);
        batchMsgDoc.getBatchMsg().getHeader().setRuleDesc(vo.getDesc());
    	batchMsgDoc.getBatchMsg().getHeader().setLayerCode(CommonKeys.LAYER_FLOW_CONTROLLER);
        batchMsgDoc.getBatchMsg().getHeader().setTRXID("");
        batchMsgDoc.getBatchMsg().getHeader().setRequestResponse("");
        batchMsgDoc.getBatchMsg().getHeader().setSendRecv("");
        batchMsgDoc.getBatchMsg().getHeader().setUserName("");
//        batchMsgDoc.getBatchMsg().getHeader().setProtocol("TCP/IP");
        batchMsgDoc.getBatchMsg().getHeader().setUserID(linkVO.getUserID());         // 실제 링크가 할당되면 알수 있다.
        batchMsgDoc.getBatchMsg().getHeader().setUserPassword(linkVO.getPwd());   // 실제 링크가 할당되면 알수 있다.
        batchMsgDoc.getBatchMsg().getHeader().setBlockSize(ovo.getBlkSize());
        batchMsgDoc.getBatchMsg().getHeader().setSequenceSize(ovo.getSequenceSize());
        batchMsgDoc.getBatchMsg().getHeader().setRemoteIP(linkVO.getLinkIP());       // 실제 링크가 할당되면 알수 있다.
        batchMsgDoc.getBatchMsg().getHeader().setPort(linkVO.getLinkPort());           // 실제 링크가 할당되면 알수 있다.
        batchMsgDoc.getBatchMsg().getHeader().setBatchStartTime(CalendarUtil.getCurrentTimeNoDash());

        batchMsgDoc.getBatchMsg().getBody().setSubUUID(uuid);
    	batchMsgDoc.getBatchMsg().getBody().setSubLayerCode(CommonKeys.SUB_LAYER_FLOW_PHASE_CK);
        batchMsgDoc.getBatchMsg().getBody().setWLIServerName(System.getProperty("weblogic.Name"));

        batchMsgDoc.getBatchMsg().getBody().setActionTag("");
        batchMsgDoc.getBatchMsg().getBody().setRecallTag("");

        batchMsgDoc.getBatchMsg().getBody().setBlockNum(0);          // 현 운영 블럭넘버
        batchMsgDoc.getBatchMsg().getBody().setSeqNum(0);            // 현 운영 시퀀스 넘버

        batchMsgDoc.getBatchMsg().getBody().setLastPhaseCode("");
        batchMsgDoc.getBatchMsg().getBody().setNextPhaseCode("");
        batchMsgDoc.getBatchMsg().getBody().setLastPhaseStartTime("");
        batchMsgDoc.getBatchMsg().getBody().setLastPhaseEndTime("");
        batchMsgDoc.getBatchMsg().getBody().setPhaseStartTime("");
        batchMsgDoc.getBatchMsg().getBody().setPhaseEndTime("");
        batchMsgDoc.getBatchMsg().getBody().setLastPhaseType("");
        batchMsgDoc.getBatchMsg().getBody().setPhaseType("");
        batchMsgDoc.getBatchMsg().getBody().setNextPhaseType("");
        batchMsgDoc.getBatchMsg().getBody().setNodeCount(0);
        batchMsgDoc.getBatchMsg().getBody().setPortNo("");
        batchMsgDoc.getBatchMsg().getBody().setSndMsgCode("");
        batchMsgDoc.getBatchMsg().getBody().setRcvMsgCode("");
        batchMsgDoc.getBatchMsg().getBody().setTimeoutInterval("");
        batchMsgDoc.getBatchMsg().getBody().setRetryCount(0);

		batchMsgDoc.getBatchMsg().getPhaseinfo().setRuleCode          ("");
		batchMsgDoc.getBatchMsg().getPhaseinfo().setPhaseCode         ("");
		batchMsgDoc.getBatchMsg().getPhaseinfo().setPhaseType         ("");
		batchMsgDoc.getBatchMsg().getPhaseinfo().setFlowClassName     ("");
		batchMsgDoc.getBatchMsg().getPhaseinfo().setLengthTelegramID  ("");
		batchMsgDoc.getBatchMsg().getPhaseinfo().setLengthClassName   ("");
		batchMsgDoc.getBatchMsg().getPhaseinfo().setLengthMsgCode     ("");
		batchMsgDoc.getBatchMsg().getPhaseinfo().setLengthFieldIndex  (-1);
		batchMsgDoc.getBatchMsg().getPhaseinfo().setPhaseSeq          ("");
		batchMsgDoc.getBatchMsg().getPhaseinfo().setPhaseTelegramID   ("");
		batchMsgDoc.getBatchMsg().getPhaseinfo().setPhaseClassName    ("");
		batchMsgDoc.getBatchMsg().getPhaseinfo().setPhaseMsgCode      ("");
		batchMsgDoc.getBatchMsg().getPhaseinfo().setTelegramTypeValue ("");
		batchMsgDoc.getBatchMsg().getPhaseinfo().setBizCodeValue      ("");
		batchMsgDoc.getBatchMsg().getPhaseinfo().setControlCodeValue  ("");
		batchMsgDoc.getBatchMsg().getPhaseinfo().setResponseCodeValue ("");

        //스케쥴러 Processing 단계 시작시간 설정
        batchMsgDoc.getBatchMsg().getBody().setPhaseStartTime(CalendarUtil.getCurrentTimeNoDash());
        return batchMsgDoc;
    }

    public String getErrorMsg(int nErrorCode) {
        switch (nErrorCode) {
            case ERROR_NO_ERROR:
                return "NO_ERROR";
            case ERROR_NO_SOCKET  :
                return "NO SOCKET";
            case ERROR_NO_PROCDATA :
                return "NO PROCDATA";
            case ERROR_NO_NEXTSTAGE        :
                return "NO NEXT STAGE";
            case ERROR_TELEGRAM_COMPILE    :
                return "TELEGRAM COMPILE";
            case ERROR_RECV_PRE_LENGTH     :
                return "RECV PRE LENGTH";
            case ERROR_RECV_ERROR          :
                return "RECV ERROR";
            case ERROR_TIMEOUT_OVER        :
                return "TIMEOUT OVER";
            case ERROR_RECV_SHORT_LENGTH   :
                return "RECV SHORT LENGTH";
            case ERROR_LENGTH_PARSE        :
                return "LENGTH PARSE ERROR";
            case ERROR_UNEXPECTED_TELEGRAM :
                return "UNEXPECTED TEELGRAM";
            case ERROR_NO_CLASS_DEFINITION :
                return "NO CLASS DEFINITION";
            case ERROR_NO_TELEGRAM_ID      :
                return "NO TELEGRAM ID";
            case ERROR_WRITE_ERROR         :
                return "WRITE ERROR";
            case ERROR_SEND_VALIDATION     :
                return "SEND VALIDATION ERROR";
            case ERROR_RECV_VALIDATION     :
                return "RECV VALIDATION ERROR";
            case ERROR_POST_EXECUTION      :
                return "doPostExecution ERROR";
            case ERROR_EXECUTION           :
                return "doExecute ERROR";
            case ERROR_ERR_TELEGRAM_META :
                return "ERROR TELEGRAM META DATA";
            case ERROR_INFORMAL_ACTION  :
                return "ERROR IN INFORMAL FIELD ACTION";
            case ERROR_READ_FILE  :
                return "READ FILE ERROR";
            case ERROR_INFORMAL_FIELD_LENGTH : // 플로우 컴포넌트에서 송수신 중 비정형필드에 대한 처리데이터 길이를 구할 수 없다.
                return "ERROR IN INFORMAL FIELD LENGTH";
            case ERROR_NO_SOCKET_PORT  : // 소켓연결 중 소켓 포트정보가 없다.
                return "SOCKET PORT ERROR";
            case ERROR_FAIL_TO_CONNECT  : // Outbound 소켓연결 중 연결 실패
                return "SOCKET CONNECT ERROR";
            default:
                return "UNKNOWN ERROR CODE["+nErrorCode+"]";
        }
    }
}
