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

package io.netty.channel.embedded;

import io.netty.util.concurrent.MockTicker;
import io.netty.util.concurrent.EventExecutorGroup;
import io.netty.channel.ChannelPromise;
import io.netty.util.concurrent.EventExecutor;
import io.netty.channel.DefaultChannelPromise;
import io.netty.channel.ChannelFuture;
import io.netty.channel.Channel;
import io.netty.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import io.netty.util.internal.ObjectUtil;
import io.netty.channel.EventLoopGroup;
import java.util.ArrayDeque;
import java.util.Queue;
import io.netty.util.concurrent.Ticker;
import io.netty.channel.EventLoop;
import io.netty.util.concurrent.AbstractScheduledEventExecutor;

final class EmbeddedEventLoop extends AbstractScheduledEventExecutor implements EventLoop
{
    private final Ticker ticker;
    private final Queue<Runnable> tasks;
    
    EmbeddedEventLoop(final Ticker ticker) {
        this.tasks = new ArrayDeque<Runnable>(2);
        this.ticker = ticker;
    }
    
    @Override
    public EventLoopGroup parent() {
        return (EventLoopGroup)super.parent();
    }
    
    @Override
    public EventLoop next() {
        return (EventLoop)super.next();
    }
    
    @Override
    public void execute(final Runnable command) {
        this.tasks.add(ObjectUtil.checkNotNull(command, "command"));
    }
    
    void runTasks() {
        while (true) {
            final Runnable task = this.tasks.poll();
            if (task == null) {
                break;
            }
            task.run();
        }
    }
    
    boolean hasPendingNormalTasks() {
        return !this.tasks.isEmpty();
    }
    
    long runScheduledTasks() {
        final long time = this.getCurrentTimeNanos();
        while (true) {
            final Runnable task = this.pollScheduledTask(time);
            if (task == null) {
                break;
            }
            task.run();
        }
        return this.nextScheduledTaskNano();
    }
    
    long nextScheduledTask() {
        return this.nextScheduledTaskNano();
    }
    
    @Override
    public Ticker ticker() {
        return this.ticker;
    }
    
    @Override
    protected long getCurrentTimeNanos() {
        return this.ticker.nanoTime();
    }
    
    @Override
    protected void cancelScheduledTasks() {
        super.cancelScheduledTasks();
    }
    
    @Override
    public Future<?> shutdownGracefully(final long quietPeriod, final long timeout, final TimeUnit unit) {
        throw new UnsupportedOperationException();
    }
    
    @Override
    public Future<?> terminationFuture() {
        throw new UnsupportedOperationException();
    }
    
    @Deprecated
    @Override
    public void shutdown() {
        throw new UnsupportedOperationException();
    }
    
    @Override
    public boolean isShuttingDown() {
        return false;
    }
    
    @Override
    public boolean isShutdown() {
        return false;
    }
    
    @Override
    public boolean isTerminated() {
        return false;
    }
    
    @Override
    public boolean awaitTermination(final long timeout, final TimeUnit unit) {
        return false;
    }
    
    @Override
    public ChannelFuture register(final Channel channel) {
        return this.register(new DefaultChannelPromise(channel, this));
    }
    
    @Override
    public ChannelFuture register(final ChannelPromise promise) {
        ObjectUtil.checkNotNull(promise, "promise");
        promise.channel().unsafe().register(this, promise);
        return promise;
    }
    
    @Deprecated
    @Override
    public ChannelFuture register(final Channel channel, final ChannelPromise promise) {
        channel.unsafe().register(this, promise);
        return promise;
    }
    
    @Override
    public boolean inEventLoop() {
        return true;
    }
    
    @Override
    public boolean inEventLoop(final Thread thread) {
        return true;
    }
    
    static final class FreezableTicker implements MockTicker
    {
        private final Ticker unfrozen;
        private long startTime;
        private long frozenTimestamp;
        private boolean timeFrozen;
        
        FreezableTicker() {
            this.unfrozen = Ticker.systemTicker();
        }
        
        @Override
        public void advance(final long amount, final TimeUnit unit) {
            final long nanos = unit.toNanos(amount);
            if (this.timeFrozen) {
                this.frozenTimestamp += nanos;
            }
            else {
                this.startTime -= nanos;
            }
        }
        
        @Override
        public long nanoTime() {
            if (this.timeFrozen) {
                return this.frozenTimestamp;
            }
            return this.unfrozen.nanoTime() - this.startTime;
        }
        
        @Override
        public void sleep(final long delay, final TimeUnit unit) throws InterruptedException {
            throw new UnsupportedOperationException("Sleeping is not supported by the default ticker for EmbeddedEventLoop. Please use a different ticker implementation if you require sleep support.");
        }
        
        public void freezeTime() {
            if (!this.timeFrozen) {
                this.frozenTimestamp = this.nanoTime();
                this.timeFrozen = true;
            }
        }
        
        public void unfreezeTime() {
            if (this.timeFrozen) {
                this.startTime = this.unfrozen.nanoTime() - this.frozenTimestamp;
                this.timeFrozen = false;
            }
        }
    }
}
