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

package io.netty.channel.socket.nio;

import io.netty.util.internal.ObjectUtil;
import java.util.ArrayList;
import io.netty.channel.ChannelOption;
import java.util.Map;
import io.netty.util.NetUtil;
import io.netty.channel.RecvByteBufAllocator;
import io.netty.channel.ServerChannelRecvByteBufAllocator;
import io.netty.channel.DefaultChannelConfig;
import io.netty.util.internal.logging.InternalLoggerFactory;
import io.netty.channel.ChannelOutboundBuffer;
import java.nio.channels.SocketChannel;
import io.netty.util.internal.SocketUtils;
import java.util.List;
import java.net.SocketAddress;
import io.netty.channel.ChannelConfig;
import java.nio.channels.SelectableChannel;
import io.netty.channel.Channel;
import java.io.IOException;
import io.netty.channel.ChannelException;
import io.netty.util.internal.PlatformDependent;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.spi.SelectorProvider;
import io.netty.channel.ChannelMetadata;
import io.netty.util.internal.logging.InternalLogger;
import java.lang.reflect.Method;
import io.netty.channel.ServerChannel;
import io.netty.channel.nio.AbstractNioMessageChannel;

public final class NioServerDomainSocketChannel extends AbstractNioMessageChannel implements ServerChannel
{
    private static final Method OPEN_SERVER_SOCKET_CHANNEL_WITH_FAMILY;
    private static final InternalLogger logger;
    private static final ChannelMetadata METADATA;
    private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER;
    private final NioDomainServerSocketChannelConfig config;
    private volatile boolean bound;
    
    static ServerSocketChannel newChannel(final SelectorProvider provider) {
        if (PlatformDependent.javaVersion() < 16) {
            throw new UnsupportedOperationException("Only supported with Java 16+");
        }
        try {
            final ServerSocketChannel channel = SelectorProviderUtil.newDomainSocketChannel(NioServerDomainSocketChannel.OPEN_SERVER_SOCKET_CHANNEL_WITH_FAMILY, provider);
            if (channel == null) {
                throw new ChannelException("Failed to open a socket.");
            }
            return channel;
        }
        catch (final IOException e) {
            throw new ChannelException("Failed to open a socket.", e);
        }
    }
    
    @Override
    protected ServerSocketChannel javaChannel() {
        return (ServerSocketChannel)super.javaChannel();
    }
    
    public NioServerDomainSocketChannel() {
        this(NioServerDomainSocketChannel.DEFAULT_SELECTOR_PROVIDER);
    }
    
    public NioServerDomainSocketChannel(final SelectorProvider provider) {
        this(newChannel(provider));
    }
    
    public NioServerDomainSocketChannel(final ServerSocketChannel channel) {
        super(null, channel, 16);
        if (PlatformDependent.javaVersion() < 16) {
            throw new UnsupportedOperationException("Only supported with Java 16+");
        }
        this.config = new NioDomainServerSocketChannelConfig(this);
        try {
            this.bound = (channel.getLocalAddress() != null);
        }
        catch (final IOException e) {
            throw new ChannelException(e);
        }
    }
    
    @Override
    public ChannelConfig config() {
        return this.config;
    }
    
    @Override
    public ChannelMetadata metadata() {
        return NioServerDomainSocketChannel.METADATA;
    }
    
    @Override
    public boolean isActive() {
        return this.isOpen() && this.bound;
    }
    
    @Override
    protected void doBind(final SocketAddress localAddress) throws Exception {
        this.javaChannel().bind(localAddress, this.config.getBacklog());
        this.bound = true;
    }
    
    @Override
    protected void doDisconnect() throws Exception {
        throw new UnsupportedOperationException();
    }
    
    @Override
    protected int doReadMessages(final List<Object> buf) throws Exception {
        final SocketChannel ch = SocketUtils.accept(this.javaChannel());
        try {
            if (ch != null) {
                buf.add(new NioDomainSocketChannel(this, ch));
                return 1;
            }
        }
        catch (final Throwable t) {
            NioServerDomainSocketChannel.logger.warn("Failed to create a new channel from an accepted socket.", t);
            try {
                ch.close();
            }
            catch (final Throwable t2) {
                NioServerDomainSocketChannel.logger.warn("Failed to close a socket.", t2);
            }
        }
        return 0;
    }
    
    @Override
    protected boolean doWriteMessage(final Object msg, final ChannelOutboundBuffer in) throws Exception {
        throw new UnsupportedOperationException();
    }
    
    @Override
    protected void doClose() throws Exception {
        final SocketAddress local = this.localAddress();
        try {
            super.doClose();
        }
        finally {
            this.javaChannel().close();
            if (local != null) {
                NioDomainSocketUtil.deleteSocketFile(local);
            }
        }
    }
    
    @Override
    protected SocketAddress localAddress0() {
        try {
            return this.javaChannel().getLocalAddress();
        }
        catch (final Exception ex) {
            return null;
        }
    }
    
    @Override
    protected SocketAddress remoteAddress0() {
        return null;
    }
    
    @Override
    protected boolean closeOnReadError(final Throwable cause) {
        return super.closeOnReadError(cause);
    }
    
    @Override
    protected boolean doConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) throws Exception {
        throw new UnsupportedOperationException();
    }
    
    @Override
    protected void doFinishConnect() throws Exception {
        throw new UnsupportedOperationException();
    }
    
    static {
        OPEN_SERVER_SOCKET_CHANNEL_WITH_FAMILY = SelectorProviderUtil.findOpenMethod("openServerSocketChannel");
        logger = InternalLoggerFactory.getInstance(NioServerDomainSocketChannel.class);
        METADATA = new ChannelMetadata(false, 16);
        DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
    }
    
    private final class NioDomainServerSocketChannelConfig extends DefaultChannelConfig
    {
        private volatile int backlog;
        
        private NioDomainServerSocketChannelConfig(final NioServerDomainSocketChannel channel) {
            super(channel, new ServerChannelRecvByteBufAllocator());
            this.backlog = NetUtil.SOMAXCONN;
        }
        
        @Override
        protected void autoReadCleared() {
            AbstractNioChannel.this.clearReadPending();
        }
        
        @Override
        public Map<ChannelOption<?>, Object> getOptions() {
            final List<ChannelOption<?>> options = new ArrayList<ChannelOption<?>>();
            options.add(ChannelOption.SO_BACKLOG);
            for (final ChannelOption<?> opt : NioChannelOption.getOptions(this.jdkChannel())) {
                options.add(opt);
            }
            return this.getOptions(super.getOptions(), (ChannelOption<?>[])options.toArray(new ChannelOption[0]));
        }
        
        @Override
        public <T> T getOption(final ChannelOption<T> option) {
            if (option == ChannelOption.SO_BACKLOG) {
                return (T)Integer.valueOf(this.getBacklog());
            }
            if (option instanceof NioChannelOption) {
                return NioChannelOption.getOption(this.jdkChannel(), (NioChannelOption<T>)(NioChannelOption)option);
            }
            return super.getOption(option);
        }
        
        @Override
        public <T> boolean setOption(final ChannelOption<T> option, final T value) {
            if (option == ChannelOption.SO_BACKLOG) {
                this.validate(option, value);
                this.setBacklog((int)value);
                return true;
            }
            if (option instanceof NioChannelOption) {
                return NioChannelOption.setOption(this.jdkChannel(), (NioChannelOption)option, value);
            }
            return super.setOption(option, value);
        }
        
        private int getBacklog() {
            return this.backlog;
        }
        
        private NioDomainServerSocketChannelConfig setBacklog(final int backlog) {
            ObjectUtil.checkPositiveOrZero(backlog, "backlog");
            this.backlog = backlog;
            return this;
        }
        
        private ServerSocketChannel jdkChannel() {
            return ((NioServerDomainSocketChannel)this.channel).javaChannel();
        }
    }
}
