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

package io.netty.channel.nio;

import io.netty.util.internal.logging.InternalLoggerFactory;
import io.netty.channel.IoHandler;
import java.nio.channels.Selector;
import java.util.NoSuchElementException;
import java.util.Set;
import io.netty.channel.SingleThreadEventLoop;
import io.netty.channel.Channel;
import java.util.Iterator;
import io.netty.channel.IoOps;
import io.netty.channel.IoHandle;
import java.nio.channels.SelectionKey;
import io.netty.channel.IoRegistration;
import io.netty.util.internal.ObjectUtil;
import java.nio.channels.SelectableChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.Queue;
import io.netty.channel.IoEventLoopGroup;
import io.netty.util.concurrent.RejectedExecutionHandler;
import io.netty.channel.EventLoopTaskQueueFactory;
import io.netty.channel.IoHandlerFactory;
import java.util.concurrent.Executor;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.channel.SingleThreadIoEventLoop;

@Deprecated
public final class NioEventLoop extends SingleThreadIoEventLoop
{
    private static final InternalLogger logger;
    
    NioEventLoop(final NioEventLoopGroup parent, final Executor executor, final IoHandlerFactory ioHandlerFactory, final EventLoopTaskQueueFactory taskQueueFactory, final EventLoopTaskQueueFactory tailTaskQueueFactory, final RejectedExecutionHandler rejectedExecutionHandler) {
        super(parent, executor, ioHandlerFactory, newTaskQueue(taskQueueFactory), newTaskQueue(tailTaskQueueFactory), rejectedExecutionHandler);
    }
    
    private static Queue<Runnable> newTaskQueue(final EventLoopTaskQueueFactory queueFactory) {
        if (queueFactory == null) {
            return SingleThreadIoEventLoop.newTaskQueue0(NioEventLoop.DEFAULT_MAX_PENDING_TASKS);
        }
        return queueFactory.newTaskQueue(NioEventLoop.DEFAULT_MAX_PENDING_TASKS);
    }
    
    public SelectorProvider selectorProvider() {
        return ((NioIoHandler)this.ioHandler()).selectorProvider();
    }
    
    public void register(final SelectableChannel ch, final int interestOps, final NioTask<?> task) {
        ObjectUtil.checkNotNull(ch, "ch");
        if (interestOps == 0) {
            throw new IllegalArgumentException("interestOps must be non-zero.");
        }
        if ((interestOps & ~ch.validOps()) != 0x0) {
            throw new IllegalArgumentException("invalid interestOps: " + interestOps + "(validOps: " + ch.validOps() + ')');
        }
        ObjectUtil.checkNotNull(task, "task");
        if (this.isShutdown()) {
            throw new IllegalStateException("event loop shut down");
        }
        final NioTask<SelectableChannel> nioTask = (NioTask<SelectableChannel>)task;
        if (this.inEventLoop()) {
            this.register0(ch, interestOps, nioTask);
        }
        else {
            try {
                this.submit(new Runnable() {
                    @Override
                    public void run() {
                        NioEventLoop.this.register0(ch, interestOps, nioTask);
                    }
                }).sync();
            }
            catch (final InterruptedException ignore) {
                Thread.currentThread().interrupt();
            }
        }
    }
    
    private void register0(final SelectableChannel ch, final int interestOps, final NioTask<SelectableChannel> task) {
        try {
            final IoRegistration registration = this.register(new NioSelectableChannelIoHandle<SelectableChannel>(ch) {
                @Override
                protected void handle(final SelectableChannel channel, final SelectionKey key) {
                    try {
                        task.channelReady(channel, key);
                    }
                    catch (final Exception e) {
                        NioEventLoop.logger.warn("Unexpected exception while running NioTask.channelReady(...)", e);
                    }
                }
                
                @Override
                protected void deregister(final SelectableChannel channel) {
                    try {
                        task.channelUnregistered(channel, null);
                    }
                    catch (final Exception e) {
                        NioEventLoop.logger.warn("Unexpected exception while running NioTask.channelUnregistered(...)", e);
                    }
                }
            }).get();
            registration.submit(NioIoOps.valueOf(interestOps));
        }
        catch (final Exception e) {
            throw new IllegalStateException(e);
        }
    }
    
    public int getIoRatio() {
        return 0;
    }
    
    @Deprecated
    public void setIoRatio(final int ioRatio) {
        NioEventLoop.logger.debug("NioEventLoop.setIoRatio(int) logic was removed, this is a no-op");
    }
    
    public void rebuildSelector() {
        if (!this.inEventLoop()) {
            this.execute(new Runnable() {
                @Override
                public void run() {
                    ((NioIoHandler)SingleThreadIoEventLoop.this.ioHandler()).rebuildSelector0();
                }
            });
            return;
        }
        ((NioIoHandler)this.ioHandler()).rebuildSelector0();
    }
    
    @Override
    public int registeredChannels() {
        return ((NioIoHandler)this.ioHandler()).numRegistered();
    }
    
    @Override
    public Iterator<Channel> registeredChannelsIterator() {
        assert this.inEventLoop();
        final Set<SelectionKey> keys = ((NioIoHandler)this.ioHandler()).registeredSet();
        if (keys.isEmpty()) {
            return ChannelsReadOnlyIterator.empty();
        }
        return new Iterator<Channel>() {
            final Iterator<SelectionKey> selectionKeyIterator = ObjectUtil.checkNotNull(keys, "selectionKeys").iterator();
            Channel next;
            boolean isDone;
            
            @Override
            public boolean hasNext() {
                if (this.isDone) {
                    return false;
                }
                Channel cur = this.next;
                if (cur == null) {
                    final Channel nextOrDone = this.nextOrDone();
                    this.next = nextOrDone;
                    cur = nextOrDone;
                    return cur != null;
                }
                return true;
            }
            
            @Override
            public Channel next() {
                if (this.isDone) {
                    throw new NoSuchElementException();
                }
                Channel cur = this.next;
                if (cur == null) {
                    cur = this.nextOrDone();
                    if (cur == null) {
                        throw new NoSuchElementException();
                    }
                }
                this.next = this.nextOrDone();
                return cur;
            }
            
            @Override
            public void remove() {
                throw new UnsupportedOperationException("remove");
            }
            
            private Channel nextOrDone() {
                final Iterator<SelectionKey> it = this.selectionKeyIterator;
                while (it.hasNext()) {
                    final SelectionKey key = it.next();
                    if (key.isValid()) {
                        final Object attachment = key.attachment();
                        if (!(attachment instanceof NioIoHandler.DefaultNioRegistration)) {
                            continue;
                        }
                        final NioIoHandle handle = ((NioIoHandler.DefaultNioRegistration)attachment).handle();
                        if (handle instanceof AbstractNioChannel.AbstractNioUnsafe) {
                            return ((AbstractNioChannel.AbstractNioUnsafe)handle).channel();
                        }
                        continue;
                    }
                }
                this.isDone = true;
                return null;
            }
        };
    }
    
    Selector unwrappedSelector() {
        return ((NioIoHandler)this.ioHandler()).unwrappedSelector();
    }
    
    static {
        logger = InternalLoggerFactory.getInstance(NioEventLoop.class);
    }
}
