package com.eactive.eai.common.logger;


import java.util.Properties;

import com.eactive.eai.adapter.ElinkAdapter;
import com.eactive.eai.adapter.ElinkAdapterFactory;
import com.eactive.eai.common.dao.DAOFactory;
import com.eactive.eai.common.message.EAIMessage;
import com.eactive.eai.common.message.EAIMessageKeys;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.util.ApplicationContextProvider;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.MessageUtil;
import org.apache.commons.lang.StringUtils;


/** 
 * 1. 기능 : EAI에서 처리되는 모든 On-Line 거래를 데이터베이스에 로깅하기 위한 운영관리 Logger Sender
 * 2. 처리 개요 : 
 *     - Processor에서 받은 거래로그 정보를 저장
 * 3. 주의사항 
 *
 * @author  : 
 * @version : v 3.0.0
 * @see : 
 * @since   :JDK v1.5.0
 */
public class DBLogTransactionLogger implements TransactionLogger { 
	// 거래 로그 Count     
    private int logCount;
    
    // 에러 로그 Count
    private int errCount;
    
    static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);

    /** 
    * 1. 기능 :  EAI 거래 로그 Count를 반환
    * 2. 처리 개요 : 
    *     - EAI 거래 로그 Count를 반환한다.
    * 3. 주의사항 
    *
    * @return   int 거래 로그 Count
    **/
    public int logCount() {
        return logCount;   
    }
    
    /** 
    * 1. 기능 :  EAI 에러 로그 Count를 반환
    * 2. 처리 개요 : 
    *     - EAI 거래 에러 Count를 반환한다.
    * 3. 주의사항 
    *
    * @return   int 에러 로그 Count
    **/
    public int errCount() {
        return errCount;   
    }
    
    /** 
    * 1. 기능 :  거래 로그 및 에러 로그 초기화
    * 2. 처리 개요 : 
    *     - 거래 및 에러 로그를 초기화 한다.
    * 3. 주의사항 
    *
    **/
    public void resetCount() {
        logCount = 0;
        errCount = 0;
    }
    
    private byte[] callAdapter(String adapterGroupName, Properties prop,  Object message) 
    		throws java.lang.Exception {
        byte[] resBytes;        
        try {

        	ElinkAdapterFactory factory = ElinkAdapterFactory.newInstance();            
            ElinkAdapter adapter = null;
            adapter = factory.getElinkAdapter(com.eactive.eai.adapter.Keys.TYPE_NET2);

            if(prop==null) {
                prop = new Properties();
            }
            if(prop.getProperty("ADAPTER_GROUP_NAME") == null) {            
                prop.setProperty("ADAPTER_GROUP_NAME", adapterGroupName);
            }
            resBytes = (byte[])adapter.callService(adapterGroupName, prop, message, prop);
        } catch(Exception e) {
        	logger.error("callSocketAdapter error",  e);
        	//throw new Exception(ExceptionUtil.getErrorCode(e, SOCK_CONTROL_ERROR));
            throw e;
        }
        return resBytes;
    }
    
    private byte[] getItsmSMSMesage(EAIMessage eaimessage) {
    	byte[] itsmSMSMessage = null;
    	StringBuilder sb = new StringBuilder();
    	try {
    		// make message from EAIMessage
    		sb.append(eaimessage.getEAISvcCd());
	    	itsmSMSMessage = sb.toString().getBytes();
    	}
    	catch(Exception e) {
    		itsmSMSMessage = sb.toString().getBytes();
    	}    	
    	return itsmSMSMessage;
    }
    
    /**
     * 1. 기능 : 로깅 정보를 로그 Queue로 전달
     * 2. 처리 개요 : 
     *    - 로깅 정보를 로그 Queue로 전달
     *    - 실시간 거래 정보 통계를 위해 EAIServiceMonitor로 전달
     * 3. 주의사항
     * 
     * @param   message EAIMessage
     * @param   prop    logging 관련 Properties
     * @exception    EAILogException
     **/
    public void log(EAIMessage message, Properties prop) throws EAILogException {
        ++logCount;
        int svcLogLvl = message.getSvcLogLvl();
        String svcTsmtUsgTp = message.getSvcTsmtUsgTp();
        int logPssSno = message.getLogPssSno();                        
        boolean isLogging = false;
        
        String guidLogPrefix = "DBLogTransactionLogger] GUID[" 
        		+ message.getMapper().getGuid(message.getStandardMessage()) 
        		+ "] UUID[" + message.getSvcOgNo() + "] ";
        
        try {
            // Direct DB Logging
        	String logType = "DB";
        	String setLogType = PropManager.getInstance().getProperty("LOG_TYPE");
        	if(setLogType != null) {
        		logType = setLogType;
        	}
        	
        	if("DB".equals(logType)) {
        		insertLog(message, prop);
        	}
        	else {
        		EAIFileLogger.getInstance().setLog(message, prop);
        	}
            //---------------------------------------------------->
            // ITSM ERROR Log 전송
            // 템플릿만 남겨두고, 나머지는 사이트에 맞게 수정 필요함.
            //---------------------------------------------------->
            boolean itsmEnabled = false;
        	if((itsmEnabled) && !MessageUtil.checkRspErrCd(message.getRspErrCd())) { 
            	if(logger.isDebug()) {
                		logger.debug(guidLogPrefix + " ITSM Error Message Notify! ");
            	}
            	if(( EAIMessageKeys.SYNC_SVC.equals(svcTsmtUsgTp) && logPssSno == 400 ) ||
                 ( EAIMessageKeys.ASYNC_SVC.equals(svcTsmtUsgTp) && (logPssSno == 200 || logPssSno == 400))) { 
            		String itsmErrorAdapterName = "";
        			itsmErrorAdapterName = PropManager.getInstance().getProperty("ITSM_CONFIG","ADAPTER_GROUP_NAME_ERROR");   /* Properties 추가 및 어뎁터 등록 */
        			if (logger.isDebug()) {
	            		logger.debug(guidLogPrefix + " ITSM ERROR Send Message Adapter Name[" + itsmErrorAdapterName + "]");
	            	}
        			
        			if(itsmErrorAdapterName != null && itsmErrorAdapterName.length() > 0) {
	        			byte[] itsmSMSMessage = getItsmSMSMesage(message);  /* ITSM 전송 메시지 포맷 결정 */
	        			Properties itsmProp = new Properties();
	        			callAdapter(itsmErrorAdapterName, itsmProp, itsmSMSMessage);
        			}
            	}
            }
        } catch(Exception e) {
        	if (logger.isError()) logger.error(guidLogPrefix + " ITSM ERROR Send ERROR " + e.getMessage(),e);
            errCount++;
            //throw new EAILogException(ExceptionUtil.getErrorCode(e, "RECEAICLG005"));             
        }            
    }
    
    public static void insertLog(EAIMessage eaiMessage, Properties prop) throws EAILogException {
    	String guidLogPrefix = "DBLogTransactionLogger] GUID["+ eaiMessage.getMapper().getGuid(eaiMessage.getStandardMessage())
    			+"] UUID["+eaiMessage.getSvcOgNo()+"] ";
    	try {
    		if (EAIDBLogControl.isEnable()){
	            try {
	            	EAILogDAO dao = ApplicationContextProvider.getContext().getBean(EAILogDAO.class);
	   	            dao.addEAISvcLog(eaiMessage, prop);
	    		} catch(Exception e) {
		            if (logger.isError()) logger.error(guidLogPrefix +" insertLog DB ERROR. - " + e.getMessage(),e);
		            // DB Connection Error일 경우에만 설정하도록 수정
					String message = e.getMessage();
					// 오류 메시지 추가 - Could not open JPA EntityManager for transaction; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection
					// 오류 메시지 추가 - Could not open JPA EntityManager for transaction; nested exception is org.hibernate.exception.GenericJDBCException: Unable to acquire JDBC Connection
					if( "ConnectionError".equals(message) || StringUtils.contains(message, "JDBCConnectionException")
						|| StringUtils.contains(message, "Unable to acquire JDBC Connection") ) {
						EAIDBLogControl.setEnable(false);
					}
					//file log
					EAIFileLogger.getInstance().setLog(eaiMessage, prop);
					throw e;
				} 
    		}
    		else{
    			//file log
				EAIFileLogger.getInstance().setLog(eaiMessage, prop);
    		}
            
        } catch(Exception e) {
            if (logger.isError()) logger.error(guidLogPrefix + " insertLog ERROR. - " + e.getMessage(), e);
            throw new EAILogException("insertLog ERROR."+ e.getMessage());
        }
    }
}
