package quic

import (
	
	
	
	

	
)

// make it possible to mock connection ID for initial generation in the tests
var generateConnectionIDForInitial = protocol.GenerateConnectionIDForInitial

// DialAddr establishes a new QUIC connection to a server.
// It resolves the address, and then creates a new UDP connection to dial the QUIC server.
// When the QUIC connection is closed, this UDP connection is closed.
// See [Dial] for more details.
func ( context.Context,  string,  *tls.Config,  *Config) (Connection, error) {
	,  := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
	if  != nil {
		return nil, 
	}
	,  := net.ResolveUDPAddr("udp", )
	if  != nil {
		return nil, 
	}
	,  := setupTransport(, , true)
	if  != nil {
		return nil, 
	}
	return .dial(, , , , , false)
}

// DialAddrEarly establishes a new 0-RTT QUIC connection to a server.
// See [DialAddr] for more details.
func ( context.Context,  string,  *tls.Config,  *Config) (EarlyConnection, error) {
	,  := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
	if  != nil {
		return nil, 
	}
	,  := net.ResolveUDPAddr("udp", )
	if  != nil {
		return nil, 
	}
	,  := setupTransport(, , true)
	if  != nil {
		return nil, 
	}
	,  := .dial(, , , , , true)
	if  != nil {
		.Close()
		return nil, 
	}
	return , nil
}

// DialEarly establishes a new 0-RTT QUIC connection to a server using a net.PacketConn.
// See [Dial] for more details.
func ( context.Context,  net.PacketConn,  net.Addr,  *tls.Config,  *Config) (EarlyConnection, error) {
	,  := setupTransport(, , false)
	if  != nil {
		return nil, 
	}
	,  := .DialEarly(, , , )
	if  != nil {
		.Close()
		return nil, 
	}
	return , nil
}

// Dial establishes a new QUIC connection to a server using a net.PacketConn.
// If the PacketConn satisfies the [OOBCapablePacketConn] interface (as a [net.UDPConn] does),
// ECN and packet info support will be enabled. In this case, ReadMsgUDP and WriteMsgUDP
// will be used instead of ReadFrom and WriteTo to read/write packets.
// The tls.Config must define an application protocol (using NextProtos).
//
// This is a convenience function. More advanced use cases should instantiate a [Transport],
// which offers configuration options for a more fine-grained control of the connection establishment,
// including reusing the underlying UDP socket for multiple QUIC connections.
func ( context.Context,  net.PacketConn,  net.Addr,  *tls.Config,  *Config) (Connection, error) {
	,  := setupTransport(, , false)
	if  != nil {
		return nil, 
	}
	,  := .Dial(, , , )
	if  != nil {
		.Close()
		return nil, 
	}
	return , nil
}

func setupTransport( net.PacketConn,  *tls.Config,  bool) (*Transport, error) {
	if  == nil {
		return nil, errors.New("quic: tls.Config not set")
	}
	return &Transport{
		Conn:        ,
		createdConn: ,
		isSingleUse: true,
	}, nil
}