// 
// Decompiled by Procyon v0.6.0
// 

package io.sentry;

import io.sentry.util.ExceptionUtils;
import io.sentry.protocol.FeatureFlags;
import io.sentry.util.EventProcessorUtils;
import java.util.HashMap;
import io.sentry.util.CollectionUtils;
import io.sentry.protocol.App;
import org.jetbrains.annotations.ApiStatus;
import io.sentry.protocol.TransactionNameSource;
import java.util.Iterator;
import java.util.Collection;
import io.sentry.featureflags.FeatureFlagBuffer;
import io.sentry.util.Objects;
import java.util.Collections;
import java.util.WeakHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.ArrayList;
import io.sentry.featureflags.IFeatureFlagBuffer;
import io.sentry.util.Pair;
import io.sentry.protocol.Contexts;
import io.sentry.util.AutoClosableReentrantLock;
import io.sentry.internal.eventprocessor.EventProcessorAndOrder;
import java.util.Map;
import java.util.Queue;
import java.util.List;
import io.sentry.protocol.Request;
import io.sentry.protocol.User;
import java.lang.ref.WeakReference;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.NotNull;
import io.sentry.protocol.SentryId;

public final class Scope implements IScope
{
    @NotNull
    private volatile SentryId lastEventId;
    @Nullable
    private SentryLevel level;
    @Nullable
    private ITransaction transaction;
    @NotNull
    private WeakReference<ISpan> activeSpan;
    @Nullable
    private String transactionName;
    @Nullable
    private User user;
    @Nullable
    private String screen;
    @Nullable
    private Request request;
    @NotNull
    private List<String> fingerprint;
    @NotNull
    private volatile Queue<Breadcrumb> breadcrumbs;
    @NotNull
    private Map<String, String> tags;
    @NotNull
    private Map<String, Object> extra;
    @NotNull
    private List<EventProcessorAndOrder> eventProcessors;
    @NotNull
    private volatile SentryOptions options;
    @Nullable
    private volatile Session session;
    @NotNull
    private final AutoClosableReentrantLock sessionLock;
    @NotNull
    private final AutoClosableReentrantLock transactionLock;
    @NotNull
    private final AutoClosableReentrantLock propagationContextLock;
    @NotNull
    private Contexts contexts;
    @NotNull
    private List<Attachment> attachments;
    @NotNull
    private PropagationContext propagationContext;
    @NotNull
    private SentryId replayId;
    @NotNull
    private ISentryClient client;
    @NotNull
    private final Map<Throwable, Pair<WeakReference<ISpan>, String>> throwableToSpan;
    @NotNull
    private final IFeatureFlagBuffer featureFlags;
    
    public Scope(@NotNull final SentryOptions options) {
        this.activeSpan = new WeakReference<ISpan>(null);
        this.fingerprint = new ArrayList<String>();
        this.tags = new ConcurrentHashMap<String, String>();
        this.extra = new ConcurrentHashMap<String, Object>();
        this.eventProcessors = new CopyOnWriteArrayList<EventProcessorAndOrder>();
        this.sessionLock = new AutoClosableReentrantLock();
        this.transactionLock = new AutoClosableReentrantLock();
        this.propagationContextLock = new AutoClosableReentrantLock();
        this.contexts = new Contexts();
        this.attachments = new CopyOnWriteArrayList<Attachment>();
        this.replayId = SentryId.EMPTY_ID;
        this.client = NoOpSentryClient.getInstance();
        this.throwableToSpan = Collections.synchronizedMap(new WeakHashMap<Throwable, Pair<WeakReference<ISpan>, String>>());
        this.options = Objects.requireNonNull(options, "SentryOptions is required.");
        this.breadcrumbs = createBreadcrumbsList(this.options.getMaxBreadcrumbs());
        this.featureFlags = FeatureFlagBuffer.create(options);
        this.propagationContext = new PropagationContext();
        this.lastEventId = SentryId.EMPTY_ID;
    }
    
    private Scope(@NotNull final Scope scope) {
        this.activeSpan = new WeakReference<ISpan>(null);
        this.fingerprint = new ArrayList<String>();
        this.tags = new ConcurrentHashMap<String, String>();
        this.extra = new ConcurrentHashMap<String, Object>();
        this.eventProcessors = new CopyOnWriteArrayList<EventProcessorAndOrder>();
        this.sessionLock = new AutoClosableReentrantLock();
        this.transactionLock = new AutoClosableReentrantLock();
        this.propagationContextLock = new AutoClosableReentrantLock();
        this.contexts = new Contexts();
        this.attachments = new CopyOnWriteArrayList<Attachment>();
        this.replayId = SentryId.EMPTY_ID;
        this.client = NoOpSentryClient.getInstance();
        this.throwableToSpan = Collections.synchronizedMap(new WeakHashMap<Throwable, Pair<WeakReference<ISpan>, String>>());
        this.transaction = scope.transaction;
        this.transactionName = scope.transactionName;
        this.activeSpan = scope.activeSpan;
        this.session = scope.session;
        this.options = scope.options;
        this.level = scope.level;
        this.client = scope.client;
        this.lastEventId = scope.getLastEventId();
        final User userRef = scope.user;
        this.user = ((userRef != null) ? new User(userRef) : null);
        this.screen = scope.screen;
        this.replayId = scope.replayId;
        final Request requestRef = scope.request;
        this.request = ((requestRef != null) ? new Request(requestRef) : null);
        this.fingerprint = new ArrayList<String>(scope.fingerprint);
        this.eventProcessors = new CopyOnWriteArrayList<EventProcessorAndOrder>(scope.eventProcessors);
        final Breadcrumb[] breadcrumbsRef = scope.breadcrumbs.toArray(new Breadcrumb[0]);
        final Queue<Breadcrumb> breadcrumbsClone = createBreadcrumbsList(scope.options.getMaxBreadcrumbs());
        for (final Breadcrumb item : breadcrumbsRef) {
            final Breadcrumb breadcrumbClone = new Breadcrumb(item);
            breadcrumbsClone.add(breadcrumbClone);
        }
        this.breadcrumbs = breadcrumbsClone;
        final Map<String, String> tagsRef = scope.tags;
        final Map<String, String> tagsClone = new ConcurrentHashMap<String, String>();
        for (final Map.Entry<String, String> item2 : tagsRef.entrySet()) {
            if (item2 != null) {
                tagsClone.put(item2.getKey(), item2.getValue());
            }
        }
        this.tags = tagsClone;
        final Map<String, Object> extraRef = scope.extra;
        final Map<String, Object> extraClone = new ConcurrentHashMap<String, Object>();
        for (final Map.Entry<String, Object> item3 : extraRef.entrySet()) {
            if (item3 != null) {
                extraClone.put(item3.getKey(), item3.getValue());
            }
        }
        this.extra = extraClone;
        this.contexts = new Contexts(scope.contexts);
        this.attachments = new CopyOnWriteArrayList<Attachment>(scope.attachments);
        this.featureFlags = scope.featureFlags.clone();
        this.propagationContext = new PropagationContext(scope.propagationContext);
    }
    
    @Nullable
    @Override
    public SentryLevel getLevel() {
        return this.level;
    }
    
    @Override
    public void setLevel(@Nullable final SentryLevel level) {
        this.level = level;
        for (final IScopeObserver observer : this.options.getScopeObservers()) {
            observer.setLevel(level);
        }
    }
    
    @Nullable
    @Override
    public String getTransactionName() {
        final ITransaction tx = this.transaction;
        return (tx != null) ? tx.getName() : this.transactionName;
    }
    
    @Override
    public void setTransaction(@NotNull final String transaction) {
        if (transaction != null) {
            final ITransaction tx = this.transaction;
            if (tx != null) {
                tx.setName(transaction, TransactionNameSource.CUSTOM);
            }
            this.transactionName = transaction;
            for (final IScopeObserver observer : this.options.getScopeObservers()) {
                observer.setTransaction(transaction);
            }
        }
        else {
            this.options.getLogger().log(SentryLevel.WARNING, "Transaction cannot be null", new Object[0]);
        }
    }
    
    @Nullable
    @Override
    public ISpan getSpan() {
        final ISpan activeSpan = this.activeSpan.get();
        if (activeSpan != null) {
            return activeSpan;
        }
        final ITransaction tx = this.transaction;
        if (tx != null) {
            final ISpan span = tx.getLatestActiveSpan();
            if (span != null) {
                return span;
            }
        }
        return tx;
    }
    
    @Override
    public void setActiveSpan(@Nullable final ISpan span) {
        this.activeSpan = new WeakReference<ISpan>(span);
    }
    
    @Override
    public void setTransaction(@Nullable final ITransaction transaction) {
        try (final ISentryLifecycleToken ignored = this.transactionLock.acquire()) {
            this.transaction = transaction;
            for (final IScopeObserver observer : this.options.getScopeObservers()) {
                if (transaction != null) {
                    observer.setTransaction(transaction.getName());
                    observer.setTrace(transaction.getSpanContext(), this);
                }
                else {
                    observer.setTransaction(null);
                    observer.setTrace(null, this);
                }
            }
        }
    }
    
    @Nullable
    @Override
    public User getUser() {
        return this.user;
    }
    
    @Override
    public void setUser(@Nullable final User user) {
        this.user = user;
        for (final IScopeObserver observer : this.options.getScopeObservers()) {
            observer.setUser(user);
        }
    }
    
    @ApiStatus.Internal
    @Nullable
    @Override
    public String getScreen() {
        return this.screen;
    }
    
    @ApiStatus.Internal
    @Override
    public void setScreen(@Nullable final String screen) {
        this.screen = screen;
        final Contexts contexts = this.getContexts();
        App app = contexts.getApp();
        if (app == null) {
            app = new App();
            contexts.setApp(app);
        }
        if (screen == null) {
            app.setViewNames(null);
        }
        else {
            final List<String> viewNames = new ArrayList<String>(1);
            viewNames.add(screen);
            app.setViewNames(viewNames);
        }
        for (final IScopeObserver observer : this.options.getScopeObservers()) {
            observer.setContexts(contexts);
        }
    }
    
    @NotNull
    @Override
    public SentryId getReplayId() {
        return this.replayId;
    }
    
    @Override
    public void setReplayId(@NotNull final SentryId replayId) {
        this.replayId = replayId;
        for (final IScopeObserver observer : this.options.getScopeObservers()) {
            observer.setReplayId(replayId);
        }
    }
    
    @Nullable
    @Override
    public Request getRequest() {
        return this.request;
    }
    
    @Override
    public void setRequest(@Nullable final Request request) {
        this.request = request;
        for (final IScopeObserver observer : this.options.getScopeObservers()) {
            observer.setRequest(request);
        }
    }
    
    @ApiStatus.Internal
    @NotNull
    @Override
    public List<String> getFingerprint() {
        return this.fingerprint;
    }
    
    @Override
    public void setFingerprint(@NotNull final List<String> fingerprint) {
        if (fingerprint == null) {
            return;
        }
        this.fingerprint = new ArrayList<String>(fingerprint);
        for (final IScopeObserver observer : this.options.getScopeObservers()) {
            observer.setFingerprint(fingerprint);
        }
    }
    
    @ApiStatus.Internal
    @NotNull
    @Override
    public Queue<Breadcrumb> getBreadcrumbs() {
        return this.breadcrumbs;
    }
    
    @Nullable
    private Breadcrumb executeBeforeBreadcrumb(@NotNull final SentryOptions.BeforeBreadcrumbCallback callback, @NotNull Breadcrumb breadcrumb, @NotNull final Hint hint) {
        try {
            breadcrumb = callback.execute(breadcrumb, hint);
        }
        catch (final Throwable e) {
            this.options.getLogger().log(SentryLevel.ERROR, "The BeforeBreadcrumbCallback callback threw an exception. Exception details will be added to the breadcrumb.", e);
            if (e.getMessage() != null) {
                breadcrumb.setData("sentry:message", e.getMessage());
            }
        }
        return breadcrumb;
    }
    
    @Override
    public void addBreadcrumb(@NotNull Breadcrumb breadcrumb, @Nullable Hint hint) {
        if (breadcrumb == null || this.breadcrumbs instanceof DisabledQueue) {
            return;
        }
        if (hint == null) {
            hint = new Hint();
        }
        final SentryOptions.BeforeBreadcrumbCallback callback = this.options.getBeforeBreadcrumb();
        if (callback != null) {
            breadcrumb = this.executeBeforeBreadcrumb(callback, breadcrumb, hint);
        }
        if (breadcrumb != null) {
            this.breadcrumbs.add(breadcrumb);
            for (final IScopeObserver observer : this.options.getScopeObservers()) {
                observer.addBreadcrumb(breadcrumb);
                observer.setBreadcrumbs(this.breadcrumbs);
            }
        }
        else {
            this.options.getLogger().log(SentryLevel.INFO, "Breadcrumb was dropped by beforeBreadcrumb", new Object[0]);
        }
    }
    
    @Override
    public void addBreadcrumb(@NotNull final Breadcrumb breadcrumb) {
        this.addBreadcrumb(breadcrumb, null);
    }
    
    @Override
    public void clearBreadcrumbs() {
        this.breadcrumbs.clear();
        for (final IScopeObserver observer : this.options.getScopeObservers()) {
            observer.setBreadcrumbs(this.breadcrumbs);
        }
    }
    
    @Override
    public void clearTransaction() {
        try (final ISentryLifecycleToken ignored = this.transactionLock.acquire()) {
            this.transaction = null;
        }
        this.transactionName = null;
        for (final IScopeObserver observer : this.options.getScopeObservers()) {
            observer.setTransaction(null);
            observer.setTrace(null, this);
        }
    }
    
    @Nullable
    @Override
    public ITransaction getTransaction() {
        return this.transaction;
    }
    
    @Override
    public void clear() {
        this.level = null;
        this.user = null;
        this.request = null;
        this.screen = null;
        this.fingerprint.clear();
        this.clearBreadcrumbs();
        this.tags.clear();
        this.extra.clear();
        this.eventProcessors.clear();
        this.clearTransaction();
        this.clearAttachments();
    }
    
    @ApiStatus.Internal
    @NotNull
    @Override
    public Map<String, String> getTags() {
        return CollectionUtils.newConcurrentHashMap(this.tags);
    }
    
    @Override
    public void setTag(@Nullable final String key, @Nullable final String value) {
        if (key == null) {
            return;
        }
        if (value == null) {
            this.removeTag(key);
        }
        else {
            this.tags.put(key, value);
            for (final IScopeObserver observer : this.options.getScopeObservers()) {
                observer.setTag(key, value);
                observer.setTags(this.tags);
            }
        }
    }
    
    @Override
    public void removeTag(@Nullable final String key) {
        if (key == null) {
            return;
        }
        this.tags.remove(key);
        for (final IScopeObserver observer : this.options.getScopeObservers()) {
            observer.removeTag(key);
            observer.setTags(this.tags);
        }
    }
    
    @ApiStatus.Internal
    @NotNull
    @Override
    public Map<String, Object> getExtras() {
        return this.extra;
    }
    
    @Override
    public void setExtra(@Nullable final String key, @Nullable final String value) {
        if (key == null) {
            return;
        }
        if (value == null) {
            this.removeExtra(key);
        }
        else {
            this.extra.put(key, value);
            for (final IScopeObserver observer : this.options.getScopeObservers()) {
                observer.setExtra(key, value);
                observer.setExtras(this.extra);
            }
        }
    }
    
    @Override
    public void removeExtra(@Nullable final String key) {
        if (key == null) {
            return;
        }
        this.extra.remove(key);
        for (final IScopeObserver observer : this.options.getScopeObservers()) {
            observer.removeExtra(key);
            observer.setExtras(this.extra);
        }
    }
    
    @NotNull
    @Override
    public Contexts getContexts() {
        return this.contexts;
    }
    
    @Override
    public void setContexts(@Nullable final String key, @Nullable final Object value) {
        if (key == null) {
            return;
        }
        this.contexts.put(key, value);
        for (final IScopeObserver observer : this.options.getScopeObservers()) {
            observer.setContexts(this.contexts);
        }
    }
    
    @Override
    public void setContexts(@Nullable final String key, @Nullable final Boolean value) {
        if (key == null) {
            return;
        }
        if (value == null) {
            this.setContexts(key, (Object)null);
        }
        else {
            final Map<String, Boolean> map = new HashMap<String, Boolean>();
            map.put("value", value);
            this.setContexts(key, map);
        }
    }
    
    @Override
    public void setContexts(@Nullable final String key, @Nullable final String value) {
        if (key == null) {
            return;
        }
        if (value == null) {
            this.setContexts(key, (Object)null);
        }
        else {
            final Map<String, String> map = new HashMap<String, String>();
            map.put("value", value);
            this.setContexts(key, map);
        }
    }
    
    @Override
    public void setContexts(@Nullable final String key, @Nullable final Number value) {
        if (key == null) {
            return;
        }
        if (value == null) {
            this.setContexts(key, (Object)null);
        }
        else {
            final Map<String, Number> map = new HashMap<String, Number>();
            map.put("value", value);
            this.setContexts(key, map);
        }
    }
    
    @Override
    public void setContexts(@Nullable final String key, @Nullable final Collection<?> value) {
        if (key == null) {
            return;
        }
        if (value == null) {
            this.setContexts(key, (Object)null);
        }
        else {
            final Map<String, Collection<?>> map = new HashMap<String, Collection<?>>();
            map.put("value", value);
            this.setContexts(key, map);
        }
    }
    
    @Override
    public void setContexts(@Nullable final String key, @Nullable final Object[] value) {
        if (key == null) {
            return;
        }
        if (value == null) {
            this.setContexts(key, (Object)null);
        }
        else {
            final Map<String, Object[]> map = new HashMap<String, Object[]>();
            map.put("value", value);
            this.setContexts(key, map);
        }
    }
    
    @Override
    public void setContexts(@Nullable final String key, @Nullable final Character value) {
        if (key == null) {
            return;
        }
        if (value == null) {
            this.setContexts(key, (Object)null);
        }
        else {
            final Map<String, Character> map = new HashMap<String, Character>();
            map.put("value", value);
            this.setContexts(key, map);
        }
    }
    
    @Override
    public void removeContexts(@Nullable final String key) {
        if (key == null) {
            return;
        }
        this.contexts.remove(key);
    }
    
    @ApiStatus.Internal
    @NotNull
    @Override
    public List<Attachment> getAttachments() {
        return new CopyOnWriteArrayList<Attachment>(this.attachments);
    }
    
    @Override
    public void addAttachment(@NotNull final Attachment attachment) {
        this.attachments.add(attachment);
    }
    
    @Override
    public void clearAttachments() {
        this.attachments.clear();
    }
    
    @NotNull
    static Queue<Breadcrumb> createBreadcrumbsList(final int maxBreadcrumb) {
        return (Queue<Breadcrumb>)((maxBreadcrumb > 0) ? SynchronizedQueue.synchronizedQueue(new CircularFifoQueue<Object>(maxBreadcrumb)) : new DisabledQueue<Object>());
    }
    
    @ApiStatus.Internal
    @NotNull
    @Override
    public List<EventProcessor> getEventProcessors() {
        return EventProcessorUtils.unwrap(this.eventProcessors);
    }
    
    @ApiStatus.Internal
    @NotNull
    @Override
    public List<EventProcessorAndOrder> getEventProcessorsWithOrder() {
        return this.eventProcessors;
    }
    
    @Override
    public void addEventProcessor(@NotNull final EventProcessor eventProcessor) {
        this.eventProcessors.add(new EventProcessorAndOrder(eventProcessor, eventProcessor.getOrder()));
    }
    
    @ApiStatus.Internal
    @Nullable
    @Override
    public Session withSession(@NotNull final IWithSession sessionCallback) {
        Session cloneSession = null;
        try (final ISentryLifecycleToken ignored = this.sessionLock.acquire()) {
            sessionCallback.accept(this.session);
            if (this.session != null) {
                cloneSession = this.session.clone();
            }
        }
        return cloneSession;
    }
    
    @ApiStatus.Internal
    @Nullable
    @Override
    public SessionPair startSession() {
        SessionPair pair = null;
        try (final ISentryLifecycleToken ignored = this.sessionLock.acquire()) {
            if (this.session != null) {
                this.session.end();
                this.options.getContinuousProfiler().reevaluateSampling();
            }
            final Session previousSession = this.session;
            if (this.options.getRelease() != null) {
                this.session = new Session(this.options.getDistinctId(), this.user, this.options.getEnvironment(), this.options.getRelease());
                final Session previousClone = (previousSession != null) ? previousSession.clone() : null;
                pair = new SessionPair(this.session.clone(), previousClone);
            }
            else {
                this.options.getLogger().log(SentryLevel.WARNING, "Release is not set on SentryOptions. Session could not be started", new Object[0]);
            }
        }
        return pair;
    }
    
    @ApiStatus.Internal
    @Nullable
    @Override
    public Session endSession() {
        Session previousSession = null;
        try (final ISentryLifecycleToken ignored = this.sessionLock.acquire()) {
            if (this.session != null) {
                this.session.end();
                this.options.getContinuousProfiler().reevaluateSampling();
                previousSession = this.session.clone();
                this.session = null;
            }
        }
        return previousSession;
    }
    
    @ApiStatus.Internal
    @Override
    public void withTransaction(@NotNull final IWithTransaction callback) {
        try (final ISentryLifecycleToken ignored = this.transactionLock.acquire()) {
            callback.accept(this.transaction);
        }
    }
    
    @ApiStatus.Internal
    @NotNull
    @Override
    public SentryOptions getOptions() {
        return this.options;
    }
    
    @ApiStatus.Internal
    @Nullable
    @Override
    public Session getSession() {
        return this.session;
    }
    
    @ApiStatus.Internal
    @Override
    public void clearSession() {
        this.session = null;
    }
    
    @ApiStatus.Internal
    @Override
    public void setPropagationContext(@NotNull final PropagationContext propagationContext) {
        this.propagationContext = propagationContext;
        final SpanContext spanContext = propagationContext.toSpanContext();
        for (final IScopeObserver observer : this.options.getScopeObservers()) {
            observer.setTrace(spanContext, this);
        }
    }
    
    @ApiStatus.Internal
    @NotNull
    @Override
    public PropagationContext getPropagationContext() {
        return this.propagationContext;
    }
    
    @ApiStatus.Internal
    @NotNull
    @Override
    public PropagationContext withPropagationContext(@NotNull final IWithPropagationContext callback) {
        try (final ISentryLifecycleToken ignored = this.propagationContextLock.acquire()) {
            callback.accept(this.propagationContext);
            return new PropagationContext(this.propagationContext);
        }
    }
    
    @NotNull
    @Override
    public IScope clone() {
        return new Scope(this);
    }
    
    @Override
    public void setLastEventId(@NotNull final SentryId lastEventId) {
        this.lastEventId = lastEventId;
    }
    
    @NotNull
    @Override
    public SentryId getLastEventId() {
        return this.lastEventId;
    }
    
    @Override
    public void bindClient(@NotNull final ISentryClient client) {
        this.client = client;
    }
    
    @NotNull
    @Override
    public ISentryClient getClient() {
        return this.client;
    }
    
    @Override
    public void addFeatureFlag(@Nullable final String flag, @Nullable final Boolean result) {
        this.featureFlags.add(flag, result);
    }
    
    @Nullable
    @Override
    public FeatureFlags getFeatureFlags() {
        return this.featureFlags.getFeatureFlags();
    }
    
    @NotNull
    @Override
    public IFeatureFlagBuffer getFeatureFlagBuffer() {
        return this.featureFlags;
    }
    
    @ApiStatus.Internal
    @Override
    public void assignTraceContext(@NotNull final SentryEvent event) {
        if (this.options.isTracingEnabled() && event.getThrowable() != null) {
            final Pair<WeakReference<ISpan>, String> pair = this.throwableToSpan.get(ExceptionUtils.findRootCause(event.getThrowable()));
            if (pair != null) {
                final WeakReference<ISpan> spanWeakRef = pair.getFirst();
                if (event.getContexts().getTrace() == null && spanWeakRef != null) {
                    final ISpan span = spanWeakRef.get();
                    if (span != null) {
                        event.getContexts().setTrace(span.getSpanContext());
                    }
                }
                final String transactionName = pair.getSecond();
                if (event.getTransaction() == null && transactionName != null) {
                    event.setTransaction(transactionName);
                }
            }
        }
    }
    
    @ApiStatus.Internal
    @Override
    public void setSpanContext(@NotNull final Throwable throwable, @NotNull final ISpan span, @NotNull final String transactionName) {
        Objects.requireNonNull(throwable, "throwable is required");
        Objects.requireNonNull(span, "span is required");
        Objects.requireNonNull(transactionName, "transactionName is required");
        final Throwable rootCause = ExceptionUtils.findRootCause(throwable);
        if (!this.throwableToSpan.containsKey(rootCause)) {
            this.throwableToSpan.put(rootCause, new Pair<WeakReference<ISpan>, String>(new WeakReference<ISpan>(span), transactionName));
        }
    }
    
    @ApiStatus.Internal
    @Override
    public void replaceOptions(@NotNull final SentryOptions options) {
        this.options = options;
        final Queue<Breadcrumb> oldBreadcrumbs = this.breadcrumbs;
        this.breadcrumbs = createBreadcrumbsList(options.getMaxBreadcrumbs());
        for (final Breadcrumb breadcrumb : oldBreadcrumbs) {
            this.addBreadcrumb(breadcrumb);
        }
    }
    
    static final class SessionPair
    {
        @Nullable
        private final Session previous;
        @NotNull
        private final Session current;
        
        public SessionPair(@NotNull final Session current, @Nullable final Session previous) {
            this.current = current;
            this.previous = previous;
        }
        
        @Nullable
        public Session getPrevious() {
            return this.previous;
        }
        
        @NotNull
        public Session getCurrent() {
            return this.current;
        }
    }
    
    interface IWithSession
    {
        void accept(@Nullable final Session p0);
    }
    
    @ApiStatus.Internal
    public interface IWithTransaction
    {
        void accept(@Nullable final ITransaction p0);
    }
    
    @ApiStatus.Internal
    public interface IWithPropagationContext
    {
        void accept(@NotNull final PropagationContext p0);
    }
}
