package com.eactive.eai.common.routing;

import java.util.Properties;

import com.eactive.eai.common.context.ElinkTransactionContext;
import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.message.EAIMessage;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.server.Keys;
import com.eactive.eai.common.session.SessionManager;
import com.eactive.eai.common.util.JMSSender;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.env.ElinkConfig;
import com.ext.eai.common.stdmessage.STDMessageKeys;

/** 
 * 1. 기능 : Inbound Layer에서 FlowControl로 라우팅하는 기능을 제공
 * 2. 처리 개요 : 
 *      - Inbound Layer에서 정의한 pProperties를 통해 전달한 값을 기반으로
 *        FlowControl로 JMS Queue/JMS Topic/DirectCall 방식으로 EAIMessage를 전달한다. 
 * 3. 주의사항 
 *
 * @author  : 
 * @version : v 1.0.0
 * @see : 
 * @since   : 
 *  : 
 */
public class FlowRouter 
{
    static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
    
    public static final String FRROUTER_ERROR_INVALID   = "RECEAICFR000"; // Routing Info 오류
    public static final String FRROUTER_ERROR_JPD       = "RECEAICFR001"; // 호출 오류
    public static final String FRROUTER_ERROR_QUEUE     = "RECEAICFR002"; // FC Async Queue 메시지 송신 오류
    public static final String FRROUTER_ERROR_TOPIC     = "RECEAICFR003"; // SA 패턴의 응답메시지 전송 오류
    
    private static String  instPostfix = "";
    
    static {
    	String serverName = System.getProperty(Keys.SERVER_KEY);
    	if(serverName != null && serverName.length() > 2) {
    		instPostfix = "_" + EAIServerManager.getInstance().getInstId(); 
    	}
    }
    
    /** 
     * 1. 기능 : Inbound Layer에서 FlowControl로 라우팅하는 기능을 제공
 	 * 2. 처리 개요 : 
 	 *      - Inbound Layer에서 정의한 Properties를 통해 전달한 값을 기반으로
 	 *        FlowControl로 JMS Queue/JMS Topic/JPDProxy 방식으로 EAIMessage를 전달한다. 
     * 3. 주의사항 
     *
     * @param eaiMessage Inbound에서 생성한 EAI표준메시지
     * @param prop 라우팅을 위한 환경값
     * @return EAIMessage FlowControl로부터 처리된 결과가 리턴됨
     * @exception
     **/
    public static EAIMessage process(EAIMessage eaiMessage, Properties prop) throws Exception {
        RoutingVO routingVO = RoutingManager.getInstance().getRoutingVO(eaiMessage.getFlwCntlRtnNm());
        EAIMessage rtnMsg = null;
        
        String route_type = prop.getProperty(RouteKeys.ROUTING_TYPE);
        
//        String guidLogPrefix = "FlowRouter] GUID["+eaiMessage.getKbMsg().getKBHeader().getGuIdNo()+"] UUID["+eaiMessage.getSvcOgNo()+"] ";
        String guidLogPrefix = "FlowRouter] GUID["+eaiMessage.getMapper().getGuid(eaiMessage.getStandardMessage())+"] UUID["+eaiMessage.getSvcOgNo()+"] ";
        
        if(RouteKeys.ROUT_CALL.equals(route_type)) {
            String serviceURI = routingVO.getSyncRoutingPath();
            boolean isLocal = true;
            try {
                rtnMsg = ElinkESBProcessProxy.callElinkESBProcess(serviceURI, eaiMessage, isLocal, prop);
            } catch(Exception e) {
            	if (logger.isError()) logger.error(guidLogPrefix + " process.JPD Error. JPD Name ["+serviceURI+"]- " + e.getMessage(), e);
                //throw new Exception(FRROUTER_ERROR_JPD);
                throw new Exception(ExceptionUtil.getErrorCode(e,FRROUTER_ERROR_JPD));
            }
        }
        else if(RouteKeys.ROUT_QUEUE.equals(route_type)) {
            // send Queue
            PropManager propManager = PropManager.getInstance();
            String queueConFactory = propManager.getProperty(RouteKeys.GROUP_NAME, RouteKeys.ROUTING_QUEUE_CONNECTION_FACTORY);
            
            //--------------------------------------------------------------------------
            // 요청거래와 응답거래의 QUEUE를 분리한다  : 2008.10.29
            //--------------------------------------------------------------------------
//            String telgmDmndDstcd = eaiMessage.getKbMsg().getKBHeader().getTelgmDmndDstcd();
//            String telgmDmndDstcd = eaiMessage.getExtMsg().getSendRecv();
            String telgmDmndDstcd = eaiMessage.getMapper().getSendRecvDivision(eaiMessage.getStandardMessage()); // S|R
            String routeQueueName = "";
            
            routeQueueName = routingVO.getAsynRoutingPath();
            
            // 새로 설정한 Queue로 RoutingPath가 정의된 경우
            // 룰 설정이 안된 경우 - 20081111
            if(routeQueueName == null || routeQueueName.trim().length() == 0) {
        		routeQueueName = "FlowRouterQueue";
        	}
            else if(routeQueueName.startsWith("com.elink.eai.common")) {
	            if( STDMessageKeys.SEND_RECV_CD_SEND.equals(telgmDmndDstcd)) {
	            	routeQueueName = propManager.getProperty(RouteKeys.GROUP_NAME, RouteKeys.ROUTING_QUEUE);
	            }
	            else {
	            	routeQueueName = propManager.getProperty(RouteKeys.GROUP_NAME, RouteKeys.ROUTING_RESQUEUE);
	            }
            }
            else {
            	// 2009.12.22
            	// 다른 인스턴스로 송신하는 부분을 막는다.
            	// TODO : 적용여부 확인 필요
//            	routeQueueName = routeQueueName + instPostfix;
            	// Local Queue 방식으로 수정함
            	if (logger.isDebug()) {
            		logger.debug(guidLogPrefix + "RoutingPath Async Queue Name - " + routeQueueName);
            	}
            }
            
            if (logger.isDebug()) {
            	logger.debug(guidLogPrefix + " telgmDmndDstcd[" + telgmDmndDstcd + "] = Async Queue Name - " + routeQueueName);
            }
            
            try {
            	//--------------------------------------------------------
            	// 2009.03.30 - Queue 분리관련 추가 로직
            	// EAI 업무그룹코드와 EAI 서비스코드, 표준의 대외기관코드 를 설정
            	//--------------------------------------------------------
            	prop.setProperty("EAIBWKCLS",  eaiMessage.getBwkCls().trim());
            	prop.setProperty("EAISVCCD",   eaiMessage.getEAISvcCd().trim());
//            	prop.setProperty("OSIDINSTCD", eaiMessage.getKbMsg().getKBCommon().getOsidInstiCd().trim());
//            	prop.setProperty("OSIDINSTCD", eaiMessage.getExtMsg().getInstitutionCode().trim());
            	prop.setProperty("OSIDINSTCD", eaiMessage.getMapper().getInstCode(eaiMessage.getStandardMessage()).trim());
            	//--------------------------------------------------------
            }
            catch(Exception ex) {
            	if (logger.isWarn()) logger.debug(guidLogPrefix + "JMS Property  set Error - " + ex.getMessage());
            }
            
            try {
            	// [ElinkTransactionContext] 비동기 송신 전 컨텍스트 복사
            	eaiMessage.setTransactionContextTransfer(ElinkTransactionContext.getAll());
            	JMSSender.sendToQueue(eaiMessage, queueConFactory, routeQueueName, prop);
            } catch(Exception e) {
            	if (logger.isError()) logger.error(guidLogPrefix +" process.Queue Error. Queue Name[" + routeQueueName + "]- " + e.getMessage(), e);
                //throw new Exception(FRROUTER_ERROR_QUEUE);
                throw new Exception(ExceptionUtil.getErrorCode(e,FRROUTER_ERROR_QUEUE));
            }
        }
        else if(RouteKeys.ROUT_TOPIC.equals(route_type)) {
            // send Topic
            String traceKey = prop.getProperty(RouteKeys.TRACE_KEY);

            PropManager propManager = PropManager.getInstance();
            String topicConFactory = propManager.getProperty(RouteKeys.GROUP_NAME, RouteKeys.ROUTING_TOPIC_CONNECTION_FACTORY);
            String routeTopicName = propManager.getProperty(RouteKeys.GROUP_NAME, RouteKeys.ROUTING_TOPIC);
            String sTTL = propManager.getProperty(RouteKeys.GROUP_NAME, RouteKeys.ROUTING_TOPIC_TTL);
            
            long ttl = 60000; // Default Set 60secs
            try {
            	if(sTTL != null && sTTL.length() > 0) {
            		ttl = Long.parseLong(sTTL);
            	}
            }
            catch(Exception e) {
            	if (logger.isDebug()) logger.debug(guidLogPrefix + " TTL Not Set - " 
            			+ RouteKeys.ROUTING_TOPIC_TTL + ":"+ e.getMessage());
            }
            
            try {
            	// [ElinkTransactionContext] 비동기 송신 전 컨텍스트 복사
            	eaiMessage.setTransactionContextTransfer(ElinkTransactionContext.getAll());
            	if (ElinkConfig.isUseCacheTopic()) {
            		SessionManager.getInstance().putTopic(traceKey, eaiMessage);
            	}
            	else {
            		JMSSender.sendToTopic(eaiMessage, topicConFactory, routeTopicName, null, traceKey, ttl);
            	}
            } catch(Exception e) {
            	if (logger.isError()) logger.error(guidLogPrefix + " process.Topic Error. Topic Name ["+routeTopicName+"]- " + e.getMessage(), e);
                //throw new Exception(FRROUTER_ERROR_TOPIC);
                throw new Exception(ExceptionUtil.getErrorCode(e,FRROUTER_ERROR_TOPIC));
            }
        }
        else {
            if (logger.isError()) logger.error(guidLogPrefix + " Invalid ROUTING INFO TYPE[" + route_type + "]");
            throw new Exception( FRROUTER_ERROR_INVALID );
        }
        
        return rtnMsg;
    }
} 
