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

package io.netty.util.internal;

import java.lang.invoke.MethodType;
import java.lang.invoke.MethodHandles;
import io.netty.util.internal.logging.InternalLoggerFactory;
import java.nio.ByteBuffer;
import java.lang.invoke.MethodHandle;
import io.netty.util.internal.logging.InternalLogger;

final class CleanerJava25 implements Cleaner
{
    private static final InternalLogger logger;
    private static final MethodHandle INVOKE_ALLOCATOR;
    
    static boolean isSupported() {
        return CleanerJava25.INVOKE_ALLOCATOR != null;
    }
    
    @Override
    public CleanableDirectBuffer allocate(final int capacity) {
        try {
            return CleanerJava25.INVOKE_ALLOCATOR.invokeExact(capacity);
        }
        catch (final RuntimeException e) {
            throw e;
        }
        catch (final Throwable e2) {
            throw new IllegalStateException("Unexpected allocation exception", e2);
        }
    }
    
    @Override
    public void freeDirectBuffer(final ByteBuffer buffer) {
        throw new UnsupportedOperationException("Cannot clean arbitrary ByteBuffer instances");
    }
    
    static {
        boolean suitableJavaVersion;
        if (System.getProperty("org.graalvm.nativeimage.imagecode") != null) {
            final String v = System.getProperty("java.specification.version");
            try {
                suitableJavaVersion = (Integer.parseInt(v) >= 25);
            }
            catch (final NumberFormatException e) {
                suitableJavaVersion = false;
            }
            logger = null;
        }
        else {
            suitableJavaVersion = (PlatformDependent0.javaVersion() >= 25);
            logger = InternalLoggerFactory.getInstance(CleanerJava25.class);
        }
        MethodHandle method;
        Throwable error;
        if (suitableJavaVersion) {
            try {
                final Class<?> arenaCls = Class.forName("java.lang.foreign.Arena");
                final Class<?> memsegCls = Class.forName("java.lang.foreign.MemorySegment");
                final Class<CleanableDirectBufferImpl> bufCls = CleanableDirectBufferImpl.class;
                final MethodHandles.Lookup lookup = MethodHandles.lookup();
                final MethodHandle ofShared = lookup.findStatic(arenaCls, "ofShared", MethodType.methodType(arenaCls));
                final Object shared = ofShared.invoke();
                ((AutoCloseable)shared).close();
                final MethodHandle allocate = lookup.findVirtual(arenaCls, "allocate", MethodType.methodType(memsegCls, Long.TYPE));
                final MethodHandle asByteBuffer = lookup.findVirtual(memsegCls, "asByteBuffer", MethodType.methodType(ByteBuffer.class));
                final MethodHandle address = lookup.findVirtual(memsegCls, "address", MethodType.methodType(Long.TYPE));
                final MethodHandle bufClsCtor = lookup.findConstructor(bufCls, MethodType.methodType(Void.TYPE, AutoCloseable.class, ByteBuffer.class, Long.TYPE));
                final MethodHandle allocateInt = MethodHandles.explicitCastArguments(allocate, MethodType.methodType(memsegCls, arenaCls, Integer.TYPE));
                final MethodHandle ctorArenaMemsegMemseg = MethodHandles.explicitCastArguments(MethodHandles.filterArguments(bufClsCtor, 1, asByteBuffer, address), MethodType.methodType(bufCls, arenaCls, memsegCls, memsegCls));
                final MethodHandle ctorArenaMemsegNull = MethodHandles.permuteArguments(ctorArenaMemsegMemseg, MethodType.methodType(bufCls, arenaCls, memsegCls, memsegCls), 0, 1, 1);
                final MethodHandle ctorArenaMemseg = MethodHandles.insertArguments(ctorArenaMemsegNull, 2, null);
                final MethodHandle ctorArenaArenaInt = MethodHandles.collectArguments(ctorArenaMemseg, 1, allocateInt);
                final MethodHandle ctorArenaNullInt = MethodHandles.permuteArguments(ctorArenaArenaInt, MethodType.methodType(bufCls, arenaCls, arenaCls, Integer.TYPE), 0, 0, 2);
                final MethodHandle ctorArenaInt = MethodHandles.insertArguments(ctorArenaNullInt, 1, null);
                method = MethodHandles.foldArguments(ctorArenaInt, ofShared);
                error = null;
            }
            catch (final Throwable throwable) {
                method = null;
                error = throwable;
            }
        }
        else {
            method = null;
            error = new UnsupportedOperationException("java.lang.foreign.MemorySegment unavailable");
        }
        if (CleanerJava25.logger != null) {
            if (error == null) {
                CleanerJava25.logger.debug("java.nio.ByteBuffer.cleaner(): available");
            }
            else {
                CleanerJava25.logger.debug("java.nio.ByteBuffer.cleaner(): unavailable", error);
            }
        }
        INVOKE_ALLOCATOR = method;
    }
    
    private static final class CleanableDirectBufferImpl implements CleanableDirectBuffer
    {
        private final AutoCloseable closeable;
        private final ByteBuffer buffer;
        private final long memoryAddress;
        
        CleanableDirectBufferImpl(final AutoCloseable closeable, final ByteBuffer buffer, final long memoryAddress) {
            this.closeable = closeable;
            this.buffer = buffer;
            this.memoryAddress = memoryAddress;
        }
        
        @Override
        public ByteBuffer buffer() {
            return this.buffer;
        }
        
        @Override
        public void clean() {
            try {
                this.closeable.close();
            }
            catch (final RuntimeException e) {
                throw e;
            }
            catch (final Exception e2) {
                throw new IllegalStateException("Unexpected close exception", e2);
            }
        }
        
        @Override
        public boolean hasMemoryAddress() {
            return true;
        }
        
        @Override
        public long memoryAddress() {
            return this.memoryAddress;
        }
    }
}
