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

package io.sentry;

import io.sentry.vendor.gson.stream.JsonToken;
import java.io.IOException;
import io.sentry.util.Objects;
import org.jetbrains.annotations.ApiStatus;
import io.sentry.util.HttpUtils;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import io.sentry.util.UrlUtils;
import java.util.Iterator;
import java.util.Locale;
import io.sentry.util.CollectionUtils;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
import org.jetbrains.annotations.NotNull;
import java.util.Date;
import org.jetbrains.annotations.Nullable;

public final class Breadcrumb implements JsonUnknown, JsonSerializable, Comparable<Breadcrumb>
{
    @Nullable
    private final Long timestampMs;
    @Nullable
    private Date timestamp;
    @NotNull
    private final Long nanos;
    @Nullable
    private String message;
    @Nullable
    private String type;
    @NotNull
    private Map<String, Object> data;
    @Nullable
    private String category;
    @Nullable
    private String origin;
    @Nullable
    private SentryLevel level;
    @Nullable
    private Map<String, Object> unknown;
    
    public Breadcrumb(@NotNull final Date timestamp) {
        this.data = new ConcurrentHashMap<String, Object>();
        this.nanos = System.nanoTime();
        this.timestamp = timestamp;
        this.timestampMs = null;
    }
    
    public Breadcrumb(final long timestamp) {
        this.data = new ConcurrentHashMap<String, Object>();
        this.nanos = System.nanoTime();
        this.timestampMs = timestamp;
        this.timestamp = null;
    }
    
    Breadcrumb(@NotNull final Breadcrumb breadcrumb) {
        this.data = new ConcurrentHashMap<String, Object>();
        this.nanos = System.nanoTime();
        this.timestamp = breadcrumb.timestamp;
        this.timestampMs = breadcrumb.timestampMs;
        this.message = breadcrumb.message;
        this.type = breadcrumb.type;
        this.category = breadcrumb.category;
        this.origin = breadcrumb.origin;
        final Map<String, Object> dataClone = CollectionUtils.newConcurrentHashMap(breadcrumb.data);
        if (dataClone != null) {
            this.data = dataClone;
        }
        this.unknown = CollectionUtils.newConcurrentHashMap(breadcrumb.unknown);
        this.level = breadcrumb.level;
    }
    
    public static Breadcrumb fromMap(@NotNull final Map<String, Object> map, @NotNull final SentryOptions options) {
        Date timestamp = DateUtils.getCurrentDateTime();
        String message = null;
        String type = null;
        final Map<String, Object> data = new ConcurrentHashMap<String, Object>();
        String category = null;
        String origin = null;
        SentryLevel level = null;
        Map<String, Object> unknown = null;
        for (final Map.Entry<String, Object> entry : map.entrySet()) {
            final Object value = entry.getValue();
            final String s = entry.getKey();
            switch (s) {
                case "timestamp": {
                    if (value instanceof String) {
                        final Date deserializedDate = ObjectReader.dateOrNull((String)value, options.getLogger());
                        if (deserializedDate == null) {
                            continue;
                        }
                        timestamp = deserializedDate;
                        continue;
                    }
                    continue;
                }
                case "message": {
                    message = ((value instanceof String) ? ((String)value) : null);
                    continue;
                }
                case "type": {
                    type = ((value instanceof String) ? ((String)value) : null);
                    continue;
                }
                case "data": {
                    final Map<Object, Object> untypedData = (value instanceof Map) ? ((Map)value) : null;
                    if (untypedData != null) {
                        for (final Map.Entry<Object, Object> dataEntry : untypedData.entrySet()) {
                            if (dataEntry.getKey() instanceof String && dataEntry.getValue() != null) {
                                data.put(dataEntry.getKey(), dataEntry.getValue());
                            }
                            else {
                                options.getLogger().log(SentryLevel.WARNING, "Invalid key or null value in data map.", new Object[0]);
                            }
                        }
                        continue;
                    }
                    continue;
                }
                case "category": {
                    category = ((value instanceof String) ? ((String)value) : null);
                    continue;
                }
                case "origin": {
                    origin = ((value instanceof String) ? ((String)value) : null);
                    continue;
                }
                case "level": {
                    final String levelString = (value instanceof String) ? ((String)value) : null;
                    if (levelString != null) {
                        try {
                            level = SentryLevel.valueOf(levelString.toUpperCase(Locale.ROOT));
                        }
                        catch (final Exception ex) {}
                        continue;
                    }
                    continue;
                }
                default: {
                    if (unknown == null) {
                        unknown = new ConcurrentHashMap<String, Object>();
                    }
                    unknown.put(entry.getKey(), entry.getValue());
                    continue;
                }
            }
        }
        final Breadcrumb breadcrumb = new Breadcrumb(timestamp);
        breadcrumb.message = message;
        breadcrumb.type = type;
        breadcrumb.data = data;
        breadcrumb.category = category;
        breadcrumb.origin = origin;
        breadcrumb.level = level;
        breadcrumb.setUnknown(unknown);
        return breadcrumb;
    }
    
    @NotNull
    public static Breadcrumb http(@NotNull final String url, @NotNull final String method) {
        final Breadcrumb breadcrumb = new Breadcrumb();
        final UrlUtils.UrlDetails urlDetails = UrlUtils.parse(url);
        breadcrumb.setType("http");
        breadcrumb.setCategory("http");
        if (urlDetails.getUrl() != null) {
            breadcrumb.setData("url", urlDetails.getUrl());
        }
        breadcrumb.setData("method", method.toUpperCase(Locale.ROOT));
        if (urlDetails.getQuery() != null) {
            breadcrumb.setData("http.query", urlDetails.getQuery());
        }
        if (urlDetails.getFragment() != null) {
            breadcrumb.setData("http.fragment", urlDetails.getFragment());
        }
        return breadcrumb;
    }
    
    @NotNull
    public static Breadcrumb http(@NotNull final String url, @NotNull final String method, @Nullable final Integer code) {
        final Breadcrumb breadcrumb = http(url, method);
        if (code != null) {
            breadcrumb.setData("status_code", code);
            breadcrumb.setLevel(levelFromHttpStatusCode(code));
        }
        return breadcrumb;
    }
    
    @NotNull
    public static Breadcrumb graphqlOperation(@Nullable final String operationName, @Nullable final String operationType, @Nullable final String operationId) {
        final Breadcrumb breadcrumb = new Breadcrumb();
        breadcrumb.setType("graphql");
        if (operationName != null) {
            breadcrumb.setData("operation_name", operationName);
        }
        if (operationType != null) {
            breadcrumb.setData("operation_type", operationType);
            breadcrumb.setCategory(operationType);
        }
        else {
            breadcrumb.setCategory("graphql.operation");
        }
        if (operationId != null) {
            breadcrumb.setData("operation_id", operationId);
        }
        return breadcrumb;
    }
    
    @NotNull
    public static Breadcrumb graphqlDataFetcher(@Nullable final String path, @Nullable final String field, @Nullable final String type, @Nullable final String objectType) {
        final Breadcrumb breadcrumb = new Breadcrumb();
        breadcrumb.setType("graphql");
        breadcrumb.setCategory("graphql.fetcher");
        if (path != null) {
            breadcrumb.setData("path", path);
        }
        if (field != null) {
            breadcrumb.setData("field", field);
        }
        if (type != null) {
            breadcrumb.setData("type", type);
        }
        if (objectType != null) {
            breadcrumb.setData("object_type", objectType);
        }
        return breadcrumb;
    }
    
    @NotNull
    public static Breadcrumb graphqlDataLoader(@NotNull final Iterable<?> keys, @Nullable final Class<?> keyType, @Nullable final Class<?> valueType, @Nullable final String name) {
        final Breadcrumb breadcrumb = new Breadcrumb();
        breadcrumb.setType("graphql");
        breadcrumb.setCategory("graphql.data_loader");
        final List<String> serializedKeys = new ArrayList<String>();
        for (final Object key : keys) {
            serializedKeys.add(key.toString());
        }
        breadcrumb.setData("keys", serializedKeys);
        if (keyType != null) {
            breadcrumb.setData("key_type", keyType.getName());
        }
        if (valueType != null) {
            breadcrumb.setData("value_type", valueType.getName());
        }
        if (name != null) {
            breadcrumb.setData("name", name);
        }
        return breadcrumb;
    }
    
    @NotNull
    public static Breadcrumb navigation(@NotNull final String from, @NotNull final String to) {
        final Breadcrumb breadcrumb = new Breadcrumb();
        breadcrumb.setCategory("navigation");
        breadcrumb.setType("navigation");
        breadcrumb.setData("from", from);
        breadcrumb.setData("to", to);
        return breadcrumb;
    }
    
    @NotNull
    public static Breadcrumb transaction(@NotNull final String message) {
        final Breadcrumb breadcrumb = new Breadcrumb();
        breadcrumb.setType("default");
        breadcrumb.setCategory("sentry.transaction");
        breadcrumb.setMessage(message);
        return breadcrumb;
    }
    
    @NotNull
    public static Breadcrumb debug(@NotNull final String message) {
        final Breadcrumb breadcrumb = new Breadcrumb();
        breadcrumb.setType("debug");
        breadcrumb.setMessage(message);
        breadcrumb.setLevel(SentryLevel.DEBUG);
        return breadcrumb;
    }
    
    @NotNull
    public static Breadcrumb error(@NotNull final String message) {
        final Breadcrumb breadcrumb = new Breadcrumb();
        breadcrumb.setType("error");
        breadcrumb.setMessage(message);
        breadcrumb.setLevel(SentryLevel.ERROR);
        return breadcrumb;
    }
    
    @NotNull
    public static Breadcrumb info(@NotNull final String message) {
        final Breadcrumb breadcrumb = new Breadcrumb();
        breadcrumb.setType("info");
        breadcrumb.setMessage(message);
        breadcrumb.setLevel(SentryLevel.INFO);
        return breadcrumb;
    }
    
    @NotNull
    public static Breadcrumb query(@NotNull final String message) {
        final Breadcrumb breadcrumb = new Breadcrumb();
        breadcrumb.setType("query");
        breadcrumb.setMessage(message);
        return breadcrumb;
    }
    
    @NotNull
    public static Breadcrumb ui(@NotNull final String category, @NotNull final String message) {
        final Breadcrumb breadcrumb = new Breadcrumb();
        breadcrumb.setType("default");
        breadcrumb.setCategory("ui." + category);
        breadcrumb.setMessage(message);
        return breadcrumb;
    }
    
    @NotNull
    public static Breadcrumb user(@NotNull final String category, @NotNull final String message) {
        final Breadcrumb breadcrumb = new Breadcrumb();
        breadcrumb.setType("user");
        breadcrumb.setCategory(category);
        breadcrumb.setMessage(message);
        return breadcrumb;
    }
    
    @NotNull
    public static Breadcrumb userInteraction(@NotNull final String subCategory, @Nullable final String viewId, @Nullable final String viewClass) {
        return userInteraction(subCategory, viewId, viewClass, Collections.emptyMap());
    }
    
    @NotNull
    public static Breadcrumb userInteraction(@NotNull final String subCategory, @Nullable final String viewId, @Nullable final String viewClass, @Nullable final String viewTag, @NotNull final Map<String, Object> additionalData) {
        final Breadcrumb breadcrumb = new Breadcrumb();
        breadcrumb.setType("user");
        breadcrumb.setCategory("ui." + subCategory);
        if (viewId != null) {
            breadcrumb.setData("view.id", viewId);
        }
        if (viewClass != null) {
            breadcrumb.setData("view.class", viewClass);
        }
        if (viewTag != null) {
            breadcrumb.setData("view.tag", viewTag);
        }
        for (final Map.Entry<String, Object> entry : additionalData.entrySet()) {
            breadcrumb.getData().put(entry.getKey(), entry.getValue());
        }
        breadcrumb.setLevel(SentryLevel.INFO);
        return breadcrumb;
    }
    
    @NotNull
    public static Breadcrumb userInteraction(@NotNull final String subCategory, @Nullable final String viewId, @Nullable final String viewClass, @NotNull final Map<String, Object> additionalData) {
        return userInteraction(subCategory, viewId, viewClass, null, additionalData);
    }
    
    @Nullable
    private static SentryLevel levelFromHttpStatusCode(@NotNull final Integer code) {
        if (HttpUtils.isHttpClientError(code)) {
            return SentryLevel.WARNING;
        }
        if (HttpUtils.isHttpServerError(code)) {
            return SentryLevel.ERROR;
        }
        return null;
    }
    
    public Breadcrumb() {
        this(System.currentTimeMillis());
    }
    
    public Breadcrumb(@Nullable final String message) {
        this();
        this.message = message;
    }
    
    @NotNull
    public Date getTimestamp() {
        if (this.timestamp != null) {
            return (Date)this.timestamp.clone();
        }
        if (this.timestampMs != null) {
            return this.timestamp = DateUtils.getDateTime(this.timestampMs);
        }
        throw new IllegalStateException("No timestamp set for breadcrumb");
    }
    
    @Nullable
    public String getMessage() {
        return this.message;
    }
    
    public void setMessage(@Nullable final String message) {
        this.message = message;
    }
    
    @Nullable
    public String getType() {
        return this.type;
    }
    
    public void setType(@Nullable final String type) {
        this.type = type;
    }
    
    @ApiStatus.Internal
    @NotNull
    public Map<String, Object> getData() {
        return this.data;
    }
    
    @Nullable
    public Object getData(@Nullable final String key) {
        if (key == null) {
            return null;
        }
        return this.data.get(key);
    }
    
    public void setData(@Nullable final String key, @Nullable final Object value) {
        if (key == null) {
            return;
        }
        if (value == null) {
            this.removeData(key);
        }
        else {
            this.data.put(key, value);
        }
    }
    
    public void removeData(@Nullable final String key) {
        if (key == null) {
            return;
        }
        this.data.remove(key);
    }
    
    @Nullable
    public String getCategory() {
        return this.category;
    }
    
    public void setCategory(@Nullable final String category) {
        this.category = category;
    }
    
    @Nullable
    public String getOrigin() {
        return this.origin;
    }
    
    public void setOrigin(@Nullable final String origin) {
        this.origin = origin;
    }
    
    @Nullable
    public SentryLevel getLevel() {
        return this.level;
    }
    
    public void setLevel(@Nullable final SentryLevel level) {
        this.level = level;
    }
    
    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || this.getClass() != o.getClass()) {
            return false;
        }
        final Breadcrumb that = (Breadcrumb)o;
        if ("http".equals(this.type)) {
            return httpBreadcrumbEquals(this, that);
        }
        return breadcrumbEquals(this, that);
    }
    
    @Override
    public int hashCode() {
        if ("http".equals(this.type)) {
            return httpBreadcrumbHashCode(this);
        }
        return breadcrumbHashCode(this);
    }
    
    private static boolean breadcrumbEquals(@NotNull final Breadcrumb a, @NotNull final Breadcrumb b) {
        return a.getTimestamp().getTime() == b.getTimestamp().getTime() && Objects.equals(a.message, b.message) && Objects.equals(a.type, b.type) && Objects.equals(a.category, b.category) && Objects.equals(a.origin, b.origin) && a.level == b.level;
    }
    
    private static boolean httpBreadcrumbEquals(@NotNull final Breadcrumb a, @NotNull final Breadcrumb b) {
        return breadcrumbEquals(a, b) && Objects.equals(a.getData("status_code"), b.getData("status_code")) && Objects.equals(a.getData("url"), b.getData("url")) && Objects.equals(a.getData("method"), b.getData("method")) && Objects.equals(a.getData("http.fragment"), b.getData("http.fragment")) && Objects.equals(a.getData("http.query"), b.getData("http.query"));
    }
    
    private static int breadcrumbHashCode(@NotNull final Breadcrumb breadcrumb) {
        return Objects.hash(breadcrumb.getTimestamp().getTime(), breadcrumb.message, breadcrumb.type, breadcrumb.category, breadcrumb.origin, breadcrumb.level);
    }
    
    private static int httpBreadcrumbHashCode(@NotNull final Breadcrumb breadcrumb) {
        return Objects.hash(breadcrumb.getTimestamp().getTime(), breadcrumb.message, breadcrumb.type, breadcrumb.category, breadcrumb.origin, breadcrumb.level, breadcrumb.getData("status_code"), breadcrumb.getData("url"), breadcrumb.getData("method"), breadcrumb.getData("http.fragment"), breadcrumb.getData("http.query"));
    }
    
    @Nullable
    @Override
    public Map<String, Object> getUnknown() {
        return this.unknown;
    }
    
    @Override
    public void setUnknown(@Nullable final Map<String, Object> unknown) {
        this.unknown = unknown;
    }
    
    @Override
    public int compareTo(@NotNull final Breadcrumb o) {
        return this.nanos.compareTo(o.nanos);
    }
    
    @Override
    public void serialize(@NotNull final ObjectWriter writer, @NotNull final ILogger logger) throws IOException {
        writer.beginObject();
        writer.name("timestamp").value(logger, this.getTimestamp());
        if (this.message != null) {
            writer.name("message").value(this.message);
        }
        if (this.type != null) {
            writer.name("type").value(this.type);
        }
        writer.name("data").value(logger, this.data);
        if (this.category != null) {
            writer.name("category").value(this.category);
        }
        if (this.origin != null) {
            writer.name("origin").value(this.origin);
        }
        if (this.level != null) {
            writer.name("level").value(logger, this.level);
        }
        if (this.unknown != null) {
            for (final String key : this.unknown.keySet()) {
                final Object value = this.unknown.get(key);
                writer.name(key);
                writer.value(logger, value);
            }
        }
        writer.endObject();
    }
    
    public static final class JsonKeys
    {
        public static final String TIMESTAMP = "timestamp";
        public static final String MESSAGE = "message";
        public static final String TYPE = "type";
        public static final String DATA = "data";
        public static final String CATEGORY = "category";
        public static final String ORIGIN = "origin";
        public static final String LEVEL = "level";
    }
    
    public static final class Deserializer implements JsonDeserializer<Breadcrumb>
    {
        @NotNull
        @Override
        public Breadcrumb deserialize(@NotNull final ObjectReader reader, @NotNull final ILogger logger) throws Exception {
            reader.beginObject();
            Date timestamp = DateUtils.getCurrentDateTime();
            String message = null;
            String type = null;
            Map<String, Object> data = new ConcurrentHashMap<String, Object>();
            String category = null;
            String origin = null;
            SentryLevel level = null;
            Map<String, Object> unknown = null;
            while (reader.peek() == JsonToken.NAME) {
                final String nextName2;
                final String nextName = nextName2 = reader.nextName();
                switch (nextName2) {
                    case "timestamp": {
                        final Date deserializedDate = reader.nextDateOrNull(logger);
                        if (deserializedDate != null) {
                            timestamp = deserializedDate;
                            continue;
                        }
                        continue;
                    }
                    case "message": {
                        message = reader.nextStringOrNull();
                        continue;
                    }
                    case "type": {
                        type = reader.nextStringOrNull();
                        continue;
                    }
                    case "data": {
                        final Map<String, Object> deserializedData = CollectionUtils.newConcurrentHashMap((Map<String, Object>)reader.nextObjectOrNull());
                        if (deserializedData != null) {
                            data = deserializedData;
                            continue;
                        }
                        continue;
                    }
                    case "category": {
                        category = reader.nextStringOrNull();
                        continue;
                    }
                    case "origin": {
                        origin = reader.nextStringOrNull();
                        continue;
                    }
                    case "level": {
                        try {
                            level = new SentryLevel.Deserializer().deserialize(reader, logger);
                        }
                        catch (final Exception exception) {
                            logger.log(SentryLevel.ERROR, exception, "Error when deserializing SentryLevel", new Object[0]);
                        }
                        continue;
                    }
                    default: {
                        if (unknown == null) {
                            unknown = new ConcurrentHashMap<String, Object>();
                        }
                        reader.nextUnknown(logger, unknown, nextName);
                        continue;
                    }
                }
            }
            final Breadcrumb breadcrumb = new Breadcrumb(timestamp);
            breadcrumb.message = message;
            breadcrumb.type = type;
            breadcrumb.data = data;
            breadcrumb.category = category;
            breadcrumb.origin = origin;
            breadcrumb.level = level;
            breadcrumb.setUnknown(unknown);
            reader.endObject();
            return breadcrumb;
        }
    }
}
