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

package io.netty.handler.codec.quic;

import java.util.concurrent.TimeUnit;
import org.jetbrains.annotations.Nullable;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import io.netty.util.concurrent.FastThreadLocal;

final class QuicheSendInfo
{
    private static final FastThreadLocal<byte[]> IPV4_ARRAYS;
    private static final FastThreadLocal<byte[]> IPV6_ARRAYS;
    private static final byte[] TIMESPEC_ZEROOUT;
    
    private QuicheSendInfo() {
    }
    
    @Nullable
    static InetSocketAddress getToAddress(final ByteBuffer memory) {
        return getAddress(memory, Quiche.QUICHE_SEND_INFO_OFFSETOF_TO_LEN, Quiche.QUICHE_SEND_INFO_OFFSETOF_TO);
    }
    
    @Nullable
    static InetSocketAddress getFromAddress(final ByteBuffer memory) {
        return getAddress(memory, Quiche.QUICHE_SEND_INFO_OFFSETOF_FROM_LEN, Quiche.QUICHE_SEND_INFO_OFFSETOF_FROM);
    }
    
    @Nullable
    private static InetSocketAddress getAddress(final ByteBuffer memory, final int lenOffset, final int addressOffset) {
        final int position = memory.position();
        try {
            final long len = getLen(memory, position + lenOffset);
            memory.position();
            if (len == Quiche.SIZEOF_SOCKADDR_IN) {
                return SockaddrIn.getIPv4(memory, QuicheSendInfo.IPV4_ARRAYS.get());
            }
            assert len == Quiche.SIZEOF_SOCKADDR_IN6;
            return SockaddrIn.getIPv6(memory, QuicheSendInfo.IPV6_ARRAYS.get(), QuicheSendInfo.IPV4_ARRAYS.get());
        }
        finally {
            memory.position();
        }
    }
    
    private static long getLen(final ByteBuffer memory, final int index) {
        return Quiche.getPrimitiveValue(memory, index, Quiche.SIZEOF_SOCKLEN_T);
    }
    
    static void setSendInfo(final ByteBuffer memory, final InetSocketAddress from, final InetSocketAddress to) {
        final int position = memory.position();
        try {
            setAddress(memory, Quiche.QUICHE_SEND_INFO_OFFSETOF_FROM, Quiche.QUICHE_SEND_INFO_OFFSETOF_FROM_LEN, from);
            setAddress(memory, Quiche.QUICHE_SEND_INFO_OFFSETOF_TO, Quiche.QUICHE_SEND_INFO_OFFSETOF_TO_LEN, to);
            memory.position();
            memory.put(QuicheSendInfo.TIMESPEC_ZEROOUT);
        }
        finally {
            memory.position();
        }
    }
    
    private static void setAddress(final ByteBuffer memory, final int addrOffset, final int lenOffset, final InetSocketAddress addr) {
        final int position = memory.position();
        try {
            memory.position();
            final int len = SockaddrIn.setAddress(memory, addr);
            Quiche.setPrimitiveValue(memory, position + lenOffset, Quiche.SIZEOF_SOCKLEN_T, len);
        }
        finally {
            memory.position();
        }
    }
    
    static long getAtNanos(final ByteBuffer memory) {
        final long sec = Quiche.getPrimitiveValue(memory, Quiche.QUICHE_SEND_INFO_OFFSETOF_AT + Quiche.TIMESPEC_OFFSETOF_TV_SEC, Quiche.SIZEOF_TIME_T);
        final long nsec = Quiche.getPrimitiveValue(memory, Quiche.QUICHE_SEND_INFO_OFFSETOF_AT + Quiche.TIMESPEC_OFFSETOF_TV_SEC, Quiche.SIZEOF_LONG);
        return TimeUnit.SECONDS.toNanos(sec) + nsec;
    }
    
    static boolean isSameAddress(final ByteBuffer memory, final ByteBuffer memory2) {
        return Quiche.isSameAddress(memory, memory2, Quiche.QUICHE_SEND_INFO_OFFSETOF_TO);
    }
    
    static {
        IPV4_ARRAYS = new FastThreadLocal<byte[]>() {
            @Override
            protected byte[] initialValue() {
                return new byte[4];
            }
        };
        IPV6_ARRAYS = new FastThreadLocal<byte[]>() {
            @Override
            protected byte[] initialValue() {
                return new byte[16];
            }
        };
        TIMESPEC_ZEROOUT = new byte[Quiche.SIZEOF_TIMESPEC];
    }
}
