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

package com.hypixel.hytale.codec;

import com.hypixel.hytale.codec.schema.config.StringSchema;
import com.hypixel.hytale.codec.schema.config.Schema;
import com.hypixel.hytale.codec.schema.SchemaContext;
import com.hypixel.hytale.codec.exception.CodecException;
import java.util.Arrays;
import org.bson.BsonBinary;
import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;
import java.io.IOException;
import javax.annotation.Nonnull;
import com.hypixel.hytale.codec.util.RawJsonReader;
import javax.annotation.Nullable;
import org.bson.BsonValue;
import java.util.UUID;
import com.hypixel.hytale.codec.codecs.UUIDBinaryCodec;
import java.util.logging.Level;
import java.time.Duration;
import java.time.Instant;
import java.nio.file.Path;
import com.hypixel.hytale.codec.function.FunctionCodec;
import com.hypixel.hytale.codec.codecs.array.ArrayCodec;
import com.hypixel.hytale.codec.codecs.array.LongArrayCodec;
import com.hypixel.hytale.codec.codecs.array.IntArrayCodec;
import com.hypixel.hytale.codec.codecs.array.FloatArrayCodec;
import com.hypixel.hytale.codec.codecs.array.DoubleArrayCodec;
import java.util.regex.Pattern;
import com.hypixel.hytale.codec.codecs.simple.LongCodec;
import com.hypixel.hytale.codec.codecs.simple.IntegerCodec;
import com.hypixel.hytale.codec.codecs.simple.ShortCodec;
import com.hypixel.hytale.codec.codecs.simple.ByteCodec;
import com.hypixel.hytale.codec.codecs.simple.FloatCodec;
import com.hypixel.hytale.codec.codecs.simple.DoubleCodec;
import com.hypixel.hytale.codec.codecs.simple.BooleanCodec;
import com.hypixel.hytale.codec.codecs.simple.StringCodec;
import com.hypixel.hytale.codec.codecs.BsonDocumentCodec;
import com.hypixel.hytale.codec.schema.SchemaConvertable;

public interface Codec<T> extends RawJsonCodec<T>, SchemaConvertable<T>
{
    @Deprecated
    public static final BsonDocumentCodec BSON_DOCUMENT = new BsonDocumentCodec();
    public static final StringCodec STRING = new StringCodec();
    public static final BooleanCodec BOOLEAN = new BooleanCodec();
    public static final DoubleCodec DOUBLE = new DoubleCodec();
    public static final FloatCodec FLOAT = new FloatCodec();
    public static final ByteCodec BYTE = new ByteCodec();
    public static final ShortCodec SHORT = new ShortCodec();
    public static final IntegerCodec INTEGER = new IntegerCodec();
    public static final LongCodec LONG = new LongCodec();
    public static final Pattern BASE64_PATTERN = Pattern.compile("^[0-9a-zA-Z+/]+$");
    @Deprecated
    public static final Codec<byte[]> BYTE_ARRAY = new Codec<byte[]>() {
        @Override
        public byte[] decode(@Nonnull final BsonValue bsonValue, final ExtraInfo extraInfo) {
            return bsonValue.asBinary().getData();
        }
        
        @Nonnull
        @Override
        public BsonValue encode(@Nonnull final byte[] bytes, final ExtraInfo extraInfo) {
            return new BsonBinary(bytes);
        }
        
        @Nullable
        @Override
        public byte[] decodeJson(final RawJsonReader reader, final ExtraInfo extraInfo) throws IOException {
            reader.expect('[');
            reader.consumeWhiteSpace();
            if (reader.tryConsume(']')) {
                return new byte[0];
            }
            int i = 0;
            byte[] arr = new byte[10];
            while (true) {
                if (i == arr.length) {
                    arr = Arrays.copyOf(arr, i + 1 + (i >> 1));
                }
                extraInfo.pushIntKey(i, reader);
                try {
                    arr[i] = reader.readByteValue();
                    ++i;
                }
                catch (final Exception e) {
                    throw new CodecException("Failed to decode", reader, extraInfo, e);
                }
                finally {
                    extraInfo.popKey();
                }
                reader.consumeWhiteSpace();
                if (reader.tryConsumeOrExpect(']', ',')) {
                    break;
                }
                reader.consumeWhiteSpace();
            }
            if (arr.length == i) {
                return arr;
            }
            return Arrays.copyOf(arr, i);
        }
        
        @Nonnull
        @Override
        public Schema toSchema(@Nonnull final SchemaContext context) {
            final StringSchema base64 = new StringSchema();
            base64.setPattern(Codec$1.BASE64_PATTERN);
            base64.setTitle("Binary");
            return base64;
        }
    };
    public static final DoubleArrayCodec DOUBLE_ARRAY = new DoubleArrayCodec();
    public static final FloatArrayCodec FLOAT_ARRAY = new FloatArrayCodec();
    public static final IntArrayCodec INT_ARRAY = new IntArrayCodec();
    public static final LongArrayCodec LONG_ARRAY = new LongArrayCodec();
    public static final ArrayCodec<String> STRING_ARRAY = new ArrayCodec<String>(Codec.STRING, String[]::new);
    public static final FunctionCodec<String, Path> PATH = new FunctionCodec<String, Path>((Codec<String>)Codec.STRING, x$0 -> Paths.get(x$0, new String[0]), Path::toString);
    public static final FunctionCodec<String, Instant> INSTANT = new FunctionCodec<String, Instant>(Codec.STRING, Instant::parse, Instant::toString);
    public static final FunctionCodec<String, Duration> DURATION = new FunctionCodec<String, Duration>(Codec.STRING, Duration::parse, Duration::toString);
    public static final FunctionCodec<Double, Duration> DURATION_SECONDS = new FunctionCodec<Double, Duration>((Codec<Double>)Codec.DOUBLE, v -> Duration.ofNanos((long)(v * TimeUnit.SECONDS.toNanos(1L))), v -> (v == null) ? null : Double.valueOf(v.toNanos() / (double)TimeUnit.SECONDS.toNanos(1L)));
    public static final FunctionCodec<String, Level> LOG_LEVEL = new FunctionCodec<String, Level>(Codec.STRING, Level::parse, Level::toString);
    public static final UUIDBinaryCodec UUID_BINARY = new UUIDBinaryCodec();
    public static final FunctionCodec<String, UUID> UUID_STRING = new FunctionCodec<String, UUID>(Codec.STRING, UUID::fromString, UUID::toString);
    
    @Nullable
    @Deprecated
    default T decode(final BsonValue bsonValue) {
        return this.decode(bsonValue, EmptyExtraInfo.EMPTY);
    }
    
    @Nullable
    T decode(final BsonValue p0, final ExtraInfo p1);
    
    @Deprecated
    default BsonValue encode(final T t) {
        return this.encode(t, EmptyExtraInfo.EMPTY);
    }
    
    BsonValue encode(final T p0, final ExtraInfo p1);
    
    @Nullable
    default T decodeJson(@Nonnull final RawJsonReader reader, final ExtraInfo extraInfo) throws IOException {
        System.err.println("decodeJson: " + String.valueOf(this.getClass()));
        final BsonValue bsonValue = RawJsonReader.readBsonValue(reader);
        return this.decode(bsonValue, extraInfo);
    }
    
    default boolean isNullBsonValue(@Nullable final BsonValue bsonValue) {
        return bsonValue == null || bsonValue.isNull();
    }
}
