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

package io.sentry.util;

import java.util.List;
import java.util.Iterator;
import io.sentry.DateUtils;
import java.util.HashMap;
import java.util.ArrayList;
import io.sentry.SentryLevel;
import java.util.Calendar;
import java.util.Currency;
import java.util.UUID;
import java.net.InetAddress;
import java.net.URI;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.Locale;
import java.util.Arrays;
import java.util.Collection;
import io.sentry.JsonSerializable;
import java.util.TimeZone;
import java.util.Date;
import org.jetbrains.annotations.Nullable;
import io.sentry.ILogger;
import java.io.IOException;
import java.util.ArrayDeque;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
import org.jetbrains.annotations.ApiStatus;
import io.sentry.ObjectWriter;

@ApiStatus.Internal
public final class MapObjectWriter implements ObjectWriter
{
    @NotNull
    final Map<String, Object> root;
    @NotNull
    final ArrayDeque<Object> stack;
    
    public MapObjectWriter(@NotNull final Map<String, Object> root) {
        this.root = root;
        (this.stack = new ArrayDeque<Object>()).addLast(root);
    }
    
    @Override
    public MapObjectWriter name(@NotNull final String name) throws IOException {
        this.stack.add(name);
        return this;
    }
    
    @Override
    public MapObjectWriter value(@NotNull final ILogger logger, @Nullable final Object object) throws IOException {
        if (object == null) {
            this.nullValue();
        }
        else if (object instanceof Character) {
            this.value(Character.toString((char)object));
        }
        else if (object instanceof String) {
            this.value((String)object);
        }
        else if (object instanceof Boolean) {
            this.value((boolean)object);
        }
        else if (object instanceof Number) {
            this.value((Number)object);
        }
        else if (object instanceof Date) {
            this.serializeDate(logger, (Date)object);
        }
        else if (object instanceof TimeZone) {
            this.serializeTimeZone(logger, (TimeZone)object);
        }
        else if (object instanceof JsonSerializable) {
            ((JsonSerializable)object).serialize(this, logger);
        }
        else if (object instanceof Collection) {
            this.serializeCollection(logger, (Collection<?>)object);
        }
        else if (object.getClass().isArray()) {
            this.serializeCollection(logger, Arrays.asList((Object[])object));
        }
        else if (object instanceof Map) {
            this.serializeMap(logger, (Map<?, ?>)object);
        }
        else if (object instanceof Locale) {
            this.value(object.toString());
        }
        else if (object instanceof AtomicIntegerArray) {
            this.serializeCollection(logger, JsonSerializationUtils.atomicIntegerArrayToList((AtomicIntegerArray)object));
        }
        else if (object instanceof AtomicBoolean) {
            this.value(((AtomicBoolean)object).get());
        }
        else if (object instanceof URI) {
            this.value(object.toString());
        }
        else if (object instanceof InetAddress) {
            this.value(object.toString());
        }
        else if (object instanceof UUID) {
            this.value(object.toString());
        }
        else if (object instanceof Currency) {
            this.value(object.toString());
        }
        else if (object instanceof Calendar) {
            this.serializeMap(logger, JsonSerializationUtils.calendarToMap((Calendar)object));
        }
        else if (object.getClass().isEnum()) {
            this.value(object.toString());
        }
        else {
            logger.log(SentryLevel.WARNING, "Failed serializing unknown object.", object);
        }
        return this;
    }
    
    @Override
    public void setLenient(final boolean lenient) {
    }
    
    @Override
    public void setIndent(@Nullable final String indent) {
    }
    
    @Nullable
    @Override
    public String getIndent() {
        return null;
    }
    
    @Override
    public MapObjectWriter beginArray() throws IOException {
        this.stack.add(new ArrayList());
        return this;
    }
    
    @Override
    public MapObjectWriter endArray() throws IOException {
        this.endObject();
        return this;
    }
    
    @Override
    public MapObjectWriter beginObject() throws IOException {
        this.stack.addLast(new HashMap());
        return this;
    }
    
    @Override
    public MapObjectWriter endObject() throws IOException {
        final Object value = this.stack.removeLast();
        this.postValue(value);
        return this;
    }
    
    @Override
    public MapObjectWriter value(@Nullable final String value) throws IOException {
        this.postValue(value);
        return this;
    }
    
    @Override
    public ObjectWriter jsonValue(@Nullable final String value) throws IOException {
        return this;
    }
    
    @Override
    public MapObjectWriter nullValue() throws IOException {
        this.postValue(null);
        return this;
    }
    
    @Override
    public MapObjectWriter value(final boolean value) throws IOException {
        this.postValue(value);
        return this;
    }
    
    @Override
    public MapObjectWriter value(@Nullable final Boolean value) throws IOException {
        this.postValue(value);
        return this;
    }
    
    @Override
    public MapObjectWriter value(final double value) throws IOException {
        this.postValue(value);
        return this;
    }
    
    @Override
    public MapObjectWriter value(final long value) throws IOException {
        this.postValue(value);
        return this;
    }
    
    @Override
    public MapObjectWriter value(@Nullable final Number value) throws IOException {
        this.postValue(value);
        return this;
    }
    
    private void serializeDate(@NotNull final ILogger logger, @NotNull final Date date) throws IOException {
        try {
            this.value(DateUtils.getTimestamp(date));
        }
        catch (final Exception e) {
            logger.log(SentryLevel.ERROR, "Error when serializing Date", e);
            this.nullValue();
        }
    }
    
    private void serializeTimeZone(@NotNull final ILogger logger, @NotNull final TimeZone timeZone) throws IOException {
        try {
            this.value(timeZone.getID());
        }
        catch (final Exception e) {
            logger.log(SentryLevel.ERROR, "Error when serializing TimeZone", e);
            this.nullValue();
        }
    }
    
    private void serializeCollection(@NotNull final ILogger logger, @NotNull final Collection<?> collection) throws IOException {
        this.beginArray();
        for (final Object object : collection) {
            this.value(logger, object);
        }
        this.endArray();
    }
    
    private void serializeMap(@NotNull final ILogger logger, @NotNull final Map<?, ?> map) throws IOException {
        this.beginObject();
        for (final Object key : map.keySet()) {
            if (key instanceof String) {
                this.name((String)key);
                this.value(logger, (Object)map.get(key));
            }
        }
        this.endObject();
    }
    
    private void postValue(@Nullable final Object value) {
        final Object topStackElement = this.stack.peekLast();
        if (topStackElement instanceof List) {
            ((List)topStackElement).add(value);
        }
        else {
            if (!(topStackElement instanceof String)) {
                throw new IllegalStateException("Invalid stack state, expected array or string on top");
            }
            final String key = this.stack.removeLast();
            this.peekObject().put(key, value);
        }
    }
    
    @NotNull
    private Map<String, Object> peekObject() {
        final Object item = this.stack.peekLast();
        if (item == null) {
            throw new IllegalStateException("Stack is empty.");
        }
        if (item instanceof Map) {
            return (Map)item;
        }
        throw new IllegalStateException("Stack element is not a Map.");
    }
}
