package net.kencochrane.raven.event.interfaces;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.Set;

/**
 * Class associating a Sentry exception to its {@link StackTraceInterface}.
 */
public final class SentryException {
    private static final Logger logger = LoggerFactory.getLogger(SentryException.class);
    /**
     * Name used when the class' package is the default one.
     */
    private static final String DEFAULT_PACKAGE_NAME = "(default)";
    private final String exceptionMessage;
    private final String exceptionClassName;
    private final String exceptionPackageName;
    private final StackTraceInterface stackTraceInterface;

    /**
     * Creates a Sentry exception based on a Java Throwable.
     * <p>
     * The {@code childExceptionStackTrace} parameter is used to define the common frames with the child exception
     * (Exception caused by {@code throwable}).
     * </p>
     *
     * @param throwable                Java exception to send to Sentry.
     * @param childExceptionStackTrace StackTrace of the exception caused by {@code throwable}.
     */
    public SentryException(Throwable throwable, StackTraceElement[] childExceptionStackTrace) {
        this.exceptionMessage = throwable.getMessage();
        this.exceptionClassName = throwable.getClass().getSimpleName();
        Package exceptionPackage = throwable.getClass().getPackage();
        this.exceptionPackageName = exceptionPackage != null ? exceptionPackage.getName() : null;
        this.stackTraceInterface = new StackTraceInterface(throwable.getStackTrace(), childExceptionStackTrace);
    }

    /**
     * Creates a new instance from the given exceptions data.
     *
     * @param exceptionMessage     the message of the exception
     * @param exceptionClassName   the exception's class name
     * @param exceptionPackageName the exception's package name
     * @param stackTraceInterface  the stack trace interface holding the stack trace information of the exception
     */
    public SentryException(String exceptionMessage,
                           String exceptionClassName,
                           String exceptionPackageName,
                           StackTraceInterface stackTraceInterface) {
        this.exceptionMessage = exceptionMessage;
        this.exceptionClassName = exceptionClassName;
        this.exceptionPackageName = exceptionPackageName;
        this.stackTraceInterface = stackTraceInterface;
    }

    /**
     * Transforms a {@link Throwable} into a Queue of {@link SentryException}.
     * <p>
     * Exceptions are stored in the queue from the most recent one to the oldest one.
     * </p>
     *
     * @param throwable throwable to transform in a queue of exceptions.
     * @return a queue of exception with StackTrace.
     */
    public static Deque<SentryException> extractExceptionQueue(Throwable throwable) {
        Deque<SentryException> exceptions = new ArrayDeque<SentryException>();
        Set<Throwable> circularityDetector = new HashSet<Throwable>();
        StackTraceElement[] childExceptionStackTrace = new StackTraceElement[0];

        //Stack the exceptions to send them in the reverse order
        while (throwable != null) {
            if (!circularityDetector.add(throwable)) {
                //TODO: Send a more helpful log message here.
                logger.warn("Exiting a circular exception!");
                break;
            }

            exceptions.add(new SentryException(throwable, childExceptionStackTrace));
            childExceptionStackTrace = throwable.getStackTrace();
            throwable = throwable.getCause();
        }

        return exceptions;
    }

    public String getExceptionMessage() {
        return exceptionMessage;
    }

    public String getExceptionClassName() {
        return exceptionClassName;
    }

    /**
     * Gets the exception package name.
     * <p>
     * If there is no package, the value will be {@link #DEFAULT_PACKAGE_NAME}.
     * </p>
     *
     * @return the exception package name or {@link #DEFAULT_PACKAGE_NAME} if it isn't defined.
     */
    public String getExceptionPackageName() {
        return exceptionPackageName != null ? exceptionPackageName : DEFAULT_PACKAGE_NAME;
    }

    public StackTraceInterface getStackTraceInterface() {
        return stackTraceInterface;
    }
}

@@ -46,66 +46,8 @@
 s;%0A%0A
-import org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;%0A%0A
 impo
@@ -269,97 +269,8 @@
 n %7B%0A
-    private static final Logger logger = LoggerFactory.getLogger(SentryException.class);%0A
     
@@ -3158,29 +3158,12 @@
 null
-) %7B%0A            if (!
+ && 
 circ
@@ -3200,170 +3200,8 @@
 ) %7B%0A
-                //TODO: Send a more helpful log message here.%0A                logger.warn(%22Exiting a circular exception!%22);%0A                break;%0A            %7D%0A%0A
     

Remove logs for circular exceptions