package cn.palmte.work;

import org.springframework.core.NestedExceptionUtils;
import org.springframework.core.NestedRuntimeException;

/**
 * 没有堆栈的异常, 降低性能消耗
 *
 * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
 * @since 2.0 2022/12/30 15:25
 */
public class NoStackTraceRuntimeException extends RuntimeException {
  private static final long serialVersionUID = 1L;

  public NoStackTraceRuntimeException() {
    super();
  }

  public NoStackTraceRuntimeException(Throwable cause) {
    super(cause);
  }

  public NoStackTraceRuntimeException(String msg) {
    super(msg);
  }

  public NoStackTraceRuntimeException(/*@Nullable*/ String msg, /*@Nullable */Throwable cause) {
    super(msg, cause);
  }

  @Override
  public final synchronized Throwable fillInStackTrace() {
    return this;
  }

  /**
   * Retrieve the innermost cause of this exception, if any.
   *
   * @return the innermost exception, or {@code null} if none
   */
//  @Nullable
  public Throwable getRootCause() {
    return NestedExceptionUtils.getRootCause(this);
  }

  /**
   * Retrieve the most specific cause of this exception, that is,
   * either the innermost cause (root cause) or this exception itself.
   * <p>Differs from {@link #getRootCause()} in that it falls back
   * to the present exception if there is no root cause.
   *
   * @return the most specific cause (never {@code null})
   */
  public Throwable getMostSpecificCause() {
    Throwable rootCause = getRootCause();
    return (rootCause != null ? rootCause : this);
  }

  /**
   * Check whether this exception contains an exception of the given type:
   * either it is of the given class itself or it contains a nested cause
   * of the given type.
   *
   * @param exType the exception type to look for
   * @return whether there is a nested exception of the specified type
   */
  public boolean contains(Class<?> exType) {
    if (exType == null) {
      return false;
    }
    if (exType.isInstance(this)) {
      return true;
    }
    Throwable cause = getCause();
    if (cause == this) {
      return false;
    }
    if (cause instanceof NestedRuntimeException) {
      return ((NestedRuntimeException) cause).contains(exType);
    }
    else {
      while (cause != null) {
        if (exType.isInstance(cause)) {
          return true;
        }
        if (cause.getCause() == cause) {
          break;
        }
        cause = cause.getCause();
      }
      return false;
    }
  }

}

