package com.eactive.eai.common.exception; 

import com.eactive.eai.common.errorcode.ErrorCodeHandler;
import com.eactive.eai.common.util.Logger;

/** 
* 1. 기능 : Exception 발생 시 메시지를 처리하기 위한 Utility 클래스
* 2. 처리 개요 : Exception 발생 시 메시지를 처리하는 메서드를 정의한다.
* *     - 
* 3. 주의사항 
*
* @author  : 
* @version : v 1.0.0
* @see : 관련 기능을 참조
* @since   : 
*  : 
*/
public class ExceptionHandlerServiceImpl implements ExceptionHandleService {
    /**
     * Default Logger
     */
    private static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
    
    /**
     * 메시지 코드 자릿수
     */
    public static final int CODE_LENGTH = 12;
    /**
     * 메시지 코드 Prefix
     */
    //public static final String  CODE_PREFIX = "RECEAI";
    public static final String  CODE_PREFIX_ERROR = "RECEAI";
    public static final String  CODE_PREFIX_FATAL = "RFCEAI";
    public static final String  MSGCODE_PREFIX_ERROR = "[RECEAI";
    public static final String  MSGCODE_PREFIX_FATAL = "[RFCEAI";
//    public static final String  MSGCODE_PREFIX_NEW = "[에러코드:S9";
    public static final String  MSGCODE_PREFIX_NEW = "[ERRCD:";
    
    /** 
    * 1. 기능 :  Exception 발생 시 약속된 메시지 코드를 반환하기 위한 메서드
    * 2. 처리 개요 : Exception 내 메시지가 메시지 코드 체계인지를 판단해서 메시지 체계이면 Excepiton의 메시지를 반환하고, 
    *       그렇지 않다면 파라미터에 새로 정의한 메시지 코드를 반환한다.
    *     - 
    * 3. 주의사항 
    *
    * @param    cause   발생한 오류
    * @param    code    새로 정의할 메시지 코드
    * @return   메시지 코드
    **/
    public String getErrorCode(Throwable cause, String code) {
        if(cause==null) {
            String cd = "RECEAICEU001";
            if (logger.isWarn()) logger.warn("["+cd+"] "+ErrorCodeHandler.getMessage(cd));
            return code;   
        }
        
        logger.error(code, cause);
        
        String msg = makeExceptionCause(cause);
        
        if( msg!=null && 
            (msg.startsWith(CODE_PREFIX_ERROR) || msg.startsWith(CODE_PREFIX_FATAL)) ) {
            //return msg;
            return "["+msg+"] " + ErrorCodeHandler.getMessage(msg);
        }
        else if( msg!=null 
        		&& (msg.startsWith(MSGCODE_PREFIX_NEW) 
            		|| msg.startsWith(MSGCODE_PREFIX_ERROR) 
            		|| msg.startsWith(MSGCODE_PREFIX_FATAL)) ) {
            return msg;
        } 
        else if(msg != null) {
            return formatErrorCode(code) + ErrorCodeHandler.getMessage(code) + ", " + msg;
        }
        else {
//            cause.printStackTrace();
            return formatErrorCode(code) + ErrorCodeHandler.getMessage(code);
            //return code;
        }

    }
    
    /** 
    * 1. 기능 :  Error 코드 및 텍스트를 정의된 포맷으로 만드는 메서드
    * 2. 처리 개요 : Error 코드 및 텍스트를 정의된 포맷으로 만들어 반환한다.
    *     - 
    * 3. 주의사항 
    *
    * @param    errorCode   에러 코드
    * @param    errorText   에러 텍스트
    * @return   에러코드와 텍스트
    **/
    public String make(String errorCode, String errorText) {
        return formatErrorCode(errorCode) + errorText;   
    }
    
    /** 
    * 1. 기능 :  Error 코드 및 텍스트를 정의된 포맷으로 만드는 메서드
    * 2. 처리 개요 : Error 코드 및 텍스트를 정의된 포맷으로 만들어 반환한다.
    *     - 
    * 3. 주의사항 
    *
    * @param    errorCode   에러 코드
    * @param    causeErrorCode   최초 발생한 오류 코드
    * @param    errorText   에러 텍스트
    * @return   에러코드와 텍스트
    **/
    public String make(String errorCode, String causeErrorCode, String errorText) {
        return formatErrorCode(errorCode) + errorText 
        		+ ", " + causeErrorCode;
    }
    
    /** 
    * 1. 기능 :  Error 코드에 대한  텍스트를 정의된 포맷으로 만드는 메서드
    * 2. 처리 개요 : Error 코드 및 텍스트를 정의된 포맷으로 만들어 반환한다.
    *     - 
    * 3. 주의사항 
    *
    * @param    errorCode   에러 코드
    * @param    args   에러 텍스트에 셋팅할 인수 리스트
    * @return   에러코드와 텍스트
    **/
    public String make(String errorCode, String[] args) {
        String errorText = ErrorCodeHandler.getMessage(errorCode, args);
        return make(errorCode,  errorText);        
    }
    
    /** 
    * 1. 기능 :  Error 코드에 대한  텍스트를 정의된 포맷으로 만드는 메서드
    * 2. 처리 개요 : Error 코드 및 텍스트를 정의된 포맷으로 만들어 반환한다.
    *     - 
    * 3. 주의사항 
    *
    * @param    errorCode   에러 코드
    * @param    causeErrorCode   최초 발생한 오류 코드
    * @param    args   에러 텍스트에 셋팅할 인수 리스트
    * @return   에러코드와 텍스트
    **/
    public String make(String errorCode, String causeErrorCode, String[] args) {
        String errorText = ErrorCodeHandler.getMessage(errorCode, args);
        return make(errorCode,  causeErrorCode, errorText);        
    }
    
    /** 
    * 1. 기능 :  Error 코드에 대한  텍스트를 정의된 포맷으로 만드는 메서드
    * 2. 처리 개요 : Error 코드 및 텍스트를 정의된 포맷으로 만들어 반환한다.
    *     - 
    * 3. 주의사항 
    *
    * @param    cause   발생한 오류
    * @param    errorCode   에러 코드
    * @param    args   에러 텍스트에 셋팅할 인수 리스트
    * @return   에러코드와 텍스트
    **/
    public String make(Throwable cause, String errorCode, String[] args) {
        String errorText = ErrorCodeHandler.getMessage(errorCode,args);
        if(errorText==null) errorText = "메시지 코드 테이블에 등록되지 않은 코드입니다. - "+errorCode;
        
        String msg = makeExceptionCause(cause);
        
        if( msg!=null && (msg.startsWith(CODE_PREFIX_ERROR) || msg.startsWith(CODE_PREFIX_FATAL)) ) {
            return make(errorCode, msg, errorText);
        } 
        else if( msg!=null 
        		&& (msg.startsWith(MSGCODE_PREFIX_NEW) 
            		|| msg.startsWith(MSGCODE_PREFIX_ERROR) 
            		|| msg.startsWith(MSGCODE_PREFIX_FATAL)) ) {
            return make(errorCode, msg, errorText);
        }
        if(msg != null) {
        	return make(errorCode, errorText + ", " + msg);
        }
        else {
            return make(errorCode, errorText);
        }
    }   // Controller 용
    
    
    /** 
    * 1. 기능 :  Error 코드에 대한  텍스트를 정의된 포맷으로 만드는 메서드
    * 2. 처리 개요 : Error 코드 및 텍스트를 정의된 포맷으로 만들어 반환한다.
    *     - 
    * 3. 주의사항 
    *
    * @param    cause   발생한 오류
    * @param    errorCode   에러 코드
    * @return   에러코드와 텍스트
    **/
    public String make(Throwable cause, String errorCode) {
        String errorText = ErrorCodeHandler.getMessage(errorCode);
        if(errorText==null) errorText = "메시지 코드 테이블에 등록되지 않은 코드입니다. - "+errorCode;
        
        String msg = makeExceptionCause(cause);
        
        if( msg!=null && (msg.startsWith(CODE_PREFIX_ERROR) || msg.startsWith(CODE_PREFIX_FATAL)) ) {
            return make(errorCode, msg, errorText);
        } 
        else if( msg!=null 
        		&& (msg.startsWith(MSGCODE_PREFIX_NEW) 
        			|| msg.startsWith(MSGCODE_PREFIX_ERROR) 
        			|| msg.startsWith(MSGCODE_PREFIX_FATAL)) ) {
            return make(errorCode, msg, errorText);
        }
        else {
            return make(errorCode, errorText);
        }
    }   // Controller 용
    
    public String formatErrorCode( String code ) {
    	//TODO S9 을 없앨수 있나?
    	return MSGCODE_PREFIX_NEW +code+ "]";
//    	if(code !=null && code.length() > 6) {
//    		return MSGCODE_PREFIX_NEW + code.substring(6) + "]";
//    	}
//    	else {
//    		return MSGCODE_PREFIX_NEW + code + "]";
//    	}	
    }
    
    public String makeExceptionCause(Throwable cause) {
    	StringBuilder sb = new StringBuilder();
    	
    	if(cause == null) {
    		return "cause is NULL";
    	}
    		
    	sb.append(cause.getMessage());
    	
    	Throwable t = cause.getCause();
        String secondCause = null;
        String rootCause = null;
        
        if(t != null) {
        	secondCause = t.getMessage();
        	t = t.getCause();
        	while(t != null) {
            	if(t.getCause() == null) {
            		rootCause = t.getMessage();
            		break;
            	}
            	else {
            		t = t.getCause();
            	}
            }
        }
        
        if(secondCause != null) {
        	sb.append(", ").append(secondCause);
        }
        if( rootCause != null ) {
        	sb.append(", ").append(rootCause);
        }
        return sb.toString();
    }
} 
