package com.hotent.base.util;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.springframework.core.NestedExceptionUtils;

/**
 * 错误信息处理类
 * 
 * @company 广州宏天软件股份有限公司
 * @author heyifan
 * @email heyf@jee-soft.cn
 * @date 2018年4月11日
 */
public class ExceptionUtil {

	/**
	 * 从异常中获取异常信息
	 * <p>
	 * 如果异常信息以XML格式存放在&lt;CommonResult>...&lt;/CommonResult>中时，会从中间提取精确的异常信息内容。
	 * </p>
	 * @param e
	 * @return
	 */
	public static String getExceptionMessage(Throwable e) {
        return getMessage(e);
	}
	
	/**
	 * 从根异常中获取异常信息
	 * <p>
	 * 如果异常信息以XML格式存放在&lt;CommonResult>...&lt;/CommonResult>中时，会从中间提取精确的异常信息内容。
	 * </p>
	 * @param e
	 * @return
	 */
	public static String getRootCauseMessage(Throwable e) {
		Throwable root = ExceptionUtils.getRootCause(e);
        root = (root == null ? e : root);
		return getExceptionMessage(e);
	}
	
	/**
	 * 从异常中获取异常信息
	 * <p>
	 * 如果异常信息以XML格式存放在&lt;CommonResult>...&lt;/CommonResult>中时，会从中间提取精确的异常信息内容。
	 * </p>
	 * @param th
	 * @return
	 */
	public static String getMessage(Throwable th) {
        if (th == null) {
            return "";
        }
        String msg = extractMessageFromXML(th.getMessage());
        return StringUtils.defaultString(msg);
    }
	
	/**
	 * 从XML格式的错误信息中提取精确的错误信息内容
	 * @param message
	 * @return
	 */
	public static String extractMessageFromXML(String message) {
		if(StringUtil.isEmpty(message)) {
			return StringUtils.defaultString(message);
		}
		try {
			Pattern regex = Pattern.compile("^.*?<CommonResult>.*?<message>(.*?)</message>.*?</CommonResult>.*?$");
			Matcher regexMatcher = regex.matcher(message);
			if (regexMatcher.matches()) {
				return regexMatcher.group(1);
			}
		} catch (PatternSyntaxException ex) {}
		return message;
	}
	
	/**
     * <p>Introspects the <code>Throwable</code> to obtain the root cause.</p>
     *
     * <p>This method walks through the exception chain to the last element,
     * "root" of the tree, using {@link #getCause(Throwable)}, and
     * returns that exception.</p>
     *
     * <p>From version 2.2, this method handles recursive cause structures
     * that might otherwise cause infinite loops. If the throwable parameter
     * has a cause of itself, then null will be returned. If the throwable
     * parameter cause chain loops, the last element in the chain before the
     * loop is returned.</p>
     *
     * @param throwable  the throwable to get the root cause for, may be null
     * @return the root cause of the <code>Throwable</code>,
     *  <code>null</code> if none found or null throwable input
     */
	public static Throwable getRootCause(Throwable throwable) {
        return ExceptionUtils.getRootCause(throwable);
    }

	/**
	 * 返回根异常 如果跟异常为空 返回当前异常
	 * @param throwable
	 * @return
	 */
	public static Throwable getRootCauseOrSelf(Throwable throwable) {
		Throwable rootCause = NestedExceptionUtils.getRootCause(throwable);
		if(rootCause==null){
			return throwable;
		}
		return rootCause;
	}
	
	/**
     * <p>A way to get the entire nested stack-trace of an throwable.</p>
     *
     * <p>The result of this method is highly dependent on the JDK version
     * and whether the exceptions override printStackTrace or not.</p>
     *
     * @param throwable  the <code>Throwable</code> to be examined
     * @return the nested stack trace, with the root cause first
     * @since 2.0
     */
	public static String getFullStackTrace(Throwable throwable) {
        return ExceptionUtils.getFullStackTrace(throwable);
    }
}
