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

package io.netty.handler.codec.quic;

import io.netty.util.internal.logging.InternalLoggerFactory;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoop;
import java.net.InetSocketAddress;
import io.netty.util.concurrent.Promise;
import io.netty.util.concurrent.Future;
import org.jetbrains.annotations.Nullable;
import io.netty.util.internal.ObjectUtil;
import java.util.HashMap;
import java.util.LinkedHashMap;
import io.netty.channel.ChannelHandler;
import java.net.SocketAddress;
import io.netty.util.AttributeKey;
import io.netty.channel.ChannelOption;
import java.util.Map;
import io.netty.channel.Channel;
import io.netty.util.internal.logging.InternalLogger;

public final class QuicChannelBootstrap
{
    private static final InternalLogger logger;
    private final Channel parent;
    private final Map<ChannelOption<?>, Object> options;
    private final Map<AttributeKey<?>, Object> attrs;
    private final Map<ChannelOption<?>, Object> streamOptions;
    private final Map<AttributeKey<?>, Object> streamAttrs;
    private SocketAddress local;
    private SocketAddress remote;
    private QuicConnectionAddress connectionAddress;
    private ChannelHandler handler;
    private ChannelHandler streamHandler;
    
    @Deprecated
    public QuicChannelBootstrap(final Channel parent) {
        this.options = new LinkedHashMap<ChannelOption<?>, Object>();
        this.attrs = new HashMap<AttributeKey<?>, Object>();
        this.streamOptions = new LinkedHashMap<ChannelOption<?>, Object>();
        this.streamAttrs = new HashMap<AttributeKey<?>, Object>();
        this.connectionAddress = QuicConnectionAddress.EPHEMERAL;
        Quic.ensureAvailability();
        this.parent = ObjectUtil.checkNotNull(parent, "parent");
    }
    
    public <T> QuicChannelBootstrap option(final ChannelOption<T> option, @Nullable final T value) {
        Quic.updateOptions(this.options, option, value);
        return this;
    }
    
    public <T> QuicChannelBootstrap attr(final AttributeKey<T> key, @Nullable final T value) {
        Quic.updateAttributes(this.attrs, key, value);
        return this;
    }
    
    public QuicChannelBootstrap handler(final ChannelHandler handler) {
        this.handler = ObjectUtil.checkNotNull(handler, "handler");
        return this;
    }
    
    public <T> QuicChannelBootstrap streamOption(final ChannelOption<T> option, @Nullable final T value) {
        Quic.updateOptions(this.streamOptions, option, value);
        return this;
    }
    
    public <T> QuicChannelBootstrap streamAttr(final AttributeKey<T> key, @Nullable final T value) {
        Quic.updateAttributes(this.streamAttrs, key, value);
        return this;
    }
    
    public QuicChannelBootstrap streamHandler(final ChannelHandler streamHandler) {
        this.streamHandler = ObjectUtil.checkNotNull(streamHandler, "streamHandler");
        return this;
    }
    
    public QuicChannelBootstrap localAddress(final SocketAddress local) {
        this.local = ObjectUtil.checkNotNull(local, "local");
        return this;
    }
    
    public QuicChannelBootstrap remoteAddress(final SocketAddress remote) {
        this.remote = ObjectUtil.checkNotNull(remote, "remote");
        return this;
    }
    
    public QuicChannelBootstrap connectionAddress(final QuicConnectionAddress connectionAddress) {
        this.connectionAddress = ObjectUtil.checkNotNull(connectionAddress, "connectionAddress");
        return this;
    }
    
    public Future<QuicChannel> connect() {
        return this.connect(this.parent.eventLoop().newPromise());
    }
    
    public Future<QuicChannel> connect(final Promise<QuicChannel> promise) {
        if (this.handler == null && this.streamHandler == null) {
            throw new IllegalStateException("handler and streamHandler not set");
        }
        SocketAddress local = this.local;
        if (local == null) {
            local = this.parent.localAddress();
        }
        if (local == null) {
            local = new InetSocketAddress(0);
        }
        SocketAddress remote = this.remote;
        if (remote == null) {
            remote = this.parent.remoteAddress();
        }
        if (remote == null) {
            throw new IllegalStateException("remote not set");
        }
        final QuicConnectionAddress address = this.connectionAddress;
        final QuicChannel channel = QuicheQuicChannel.forClient(this.parent, (InetSocketAddress)local, (InetSocketAddress)remote, this.streamHandler, Quic.toOptionsArray(this.streamOptions), Quic.toAttributesArray(this.streamAttrs));
        Quic.setupChannel(channel, Quic.toOptionsArray(this.options), Quic.toAttributesArray(this.attrs), this.handler, QuicChannelBootstrap.logger);
        final EventLoop eventLoop = this.parent.eventLoop();
        eventLoop.register(channel).addListener(future -> {
            final Throwable cause = future.cause();
            if (cause != null) {
                promise.setFailure(cause);
            }
            else {
                channel.connect(address).addListener(f -> {
                    final Throwable error = f.cause();
                    if (error != null) {
                        promise.setFailure(error);
                    }
                    else {
                        promise.setSuccess(channel);
                    }
                });
            }
            return;
        });
        return promise;
    }
    
    static {
        logger = InternalLoggerFactory.getInstance(QuicChannelBootstrap.class);
    }
}
