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

package io.sentry;

import java.util.Iterator;
import java.io.IOException;
import java.util.List;
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 io.sentry.util.JsonSerializationUtils;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.Locale;
import java.util.Map;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.TimeZone;
import java.util.Date;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.ApiStatus;

@ApiStatus.Internal
public final class JsonObjectSerializer
{
    public static final String OBJECT_PLACEHOLDER = "[OBJECT]";
    public final JsonReflectionObjectSerializer jsonReflectionObjectSerializer;
    
    public JsonObjectSerializer(final int maxDepth) {
        this.jsonReflectionObjectSerializer = new JsonReflectionObjectSerializer(maxDepth);
    }
    
    public void serialize(@NotNull final ObjectWriter writer, @NotNull final ILogger logger, @Nullable final Object object) throws IOException {
        if (object == null) {
            writer.nullValue();
        }
        else if (object instanceof Character) {
            writer.value(Character.toString((char)object));
        }
        else if (object instanceof String) {
            writer.value((String)object);
        }
        else if (object instanceof Boolean) {
            writer.value((boolean)object);
        }
        else if (object instanceof Number) {
            writer.value((Number)object);
        }
        else if (object instanceof Date) {
            this.serializeDate(writer, logger, (Date)object);
        }
        else if (object instanceof TimeZone) {
            this.serializeTimeZone(writer, logger, (TimeZone)object);
        }
        else if (object instanceof JsonSerializable) {
            ((JsonSerializable)object).serialize(writer, logger);
        }
        else if (object instanceof Collection) {
            this.serializeCollection(writer, logger, (Collection<?>)object);
        }
        else if (object instanceof boolean[]) {
            final List<Boolean> bools = new ArrayList<Boolean>(((boolean[])object).length);
            for (final boolean b : (boolean[])object) {
                bools.add(b);
            }
            this.serializeCollection(writer, logger, bools);
        }
        else if (object instanceof byte[]) {
            final List<Byte> bytes = new ArrayList<Byte>(((byte[])object).length);
            for (final byte b2 : (byte[])object) {
                bytes.add(b2);
            }
            this.serializeCollection(writer, logger, bytes);
        }
        else if (object instanceof short[]) {
            final List<Short> shorts = new ArrayList<Short>(((short[])object).length);
            for (final short s : (short[])object) {
                shorts.add(s);
            }
            this.serializeCollection(writer, logger, shorts);
        }
        else if (object instanceof char[]) {
            final List<Character> chars = new ArrayList<Character>(((char[])object).length);
            for (final char s2 : (char[])object) {
                chars.add(s2);
            }
            this.serializeCollection(writer, logger, chars);
        }
        else if (object instanceof int[]) {
            final List<Integer> ints = new ArrayList<Integer>(((int[])object).length);
            for (final int i : (int[])object) {
                ints.add(i);
            }
            this.serializeCollection(writer, logger, ints);
        }
        else if (object instanceof long[]) {
            final List<Long> longs = new ArrayList<Long>(((long[])object).length);
            for (final long l : (long[])object) {
                longs.add(l);
            }
            this.serializeCollection(writer, logger, longs);
        }
        else if (object instanceof float[]) {
            final List<Float> floats = new ArrayList<Float>(((float[])object).length);
            for (final float f : (float[])object) {
                floats.add(f);
            }
            this.serializeCollection(writer, logger, floats);
        }
        else if (object instanceof double[]) {
            final List<Double> doubles = new ArrayList<Double>(((double[])object).length);
            for (final double d : (double[])object) {
                doubles.add(d);
            }
            this.serializeCollection(writer, logger, doubles);
        }
        else if (object.getClass().isArray()) {
            this.serializeCollection(writer, logger, Arrays.asList((Object[])object));
        }
        else if (object instanceof Map) {
            this.serializeMap(writer, logger, (Map<?, ?>)object);
        }
        else if (object instanceof Locale) {
            writer.value(object.toString());
        }
        else if (object instanceof AtomicIntegerArray) {
            this.serializeCollection(writer, logger, JsonSerializationUtils.atomicIntegerArrayToList((AtomicIntegerArray)object));
        }
        else if (object instanceof AtomicBoolean) {
            writer.value(((AtomicBoolean)object).get());
        }
        else if (object instanceof URI) {
            writer.value(object.toString());
        }
        else if (object instanceof InetAddress) {
            writer.value(object.toString());
        }
        else if (object instanceof UUID) {
            writer.value(object.toString());
        }
        else if (object instanceof Currency) {
            writer.value(object.toString());
        }
        else if (object instanceof Calendar) {
            this.serializeMap(writer, logger, JsonSerializationUtils.calendarToMap((Calendar)object));
        }
        else if (object.getClass().isEnum()) {
            writer.value(object.toString());
        }
        else {
            try {
                final Object serializableObject = this.jsonReflectionObjectSerializer.serialize(object, logger);
                this.serialize(writer, logger, serializableObject);
            }
            catch (final Exception exception) {
                logger.log(SentryLevel.ERROR, "Failed serializing unknown object.", exception);
                writer.value("[OBJECT]");
            }
        }
    }
    
    private void serializeDate(@NotNull final ObjectWriter writer, @NotNull final ILogger logger, @NotNull final Date date) throws IOException {
        try {
            writer.value(DateUtils.getTimestamp(date));
        }
        catch (final Exception e) {
            logger.log(SentryLevel.ERROR, "Error when serializing Date", e);
            writer.nullValue();
        }
    }
    
    private void serializeTimeZone(@NotNull final ObjectWriter writer, @NotNull final ILogger logger, @NotNull final TimeZone timeZone) throws IOException {
        try {
            writer.value(timeZone.getID());
        }
        catch (final Exception e) {
            logger.log(SentryLevel.ERROR, "Error when serializing TimeZone", e);
            writer.nullValue();
        }
    }
    
    private void serializeCollection(@NotNull final ObjectWriter writer, @NotNull final ILogger logger, @NotNull final Collection<?> collection) throws IOException {
        writer.beginArray();
        for (final Object object : collection) {
            this.serialize(writer, logger, object);
        }
        writer.endArray();
    }
    
    private void serializeMap(@NotNull final ObjectWriter writer, @NotNull final ILogger logger, @NotNull final Map<?, ?> map) throws IOException {
        writer.beginObject();
        for (final Object key : map.keySet()) {
            if (key instanceof String) {
                writer.name((String)key);
                this.serialize(writer, logger, map.get(key));
            }
        }
        writer.endObject();
    }
}
