package websocket

import (
	
	
	
	

	ma 
	manet 
)

// Addr is an implementation of net.Addr for WebSocket.
type Addr struct {
	*url.URL
}

var _ net.Addr = (*Addr)(nil)

// Network returns the network type for a WebSocket, "websocket".
func ( *Addr) () string {
	return "websocket"
}

// NewAddr creates an Addr with `ws` scheme (insecure).
//
// Deprecated. Use NewAddrWithScheme.
func ( string) *Addr {
	// Older versions of the transport only supported insecure connections (i.e.
	// WS instead of WSS). Assume that is the case here.
	return NewAddrWithScheme(, false)
}

// NewAddrWithScheme creates a new Addr using the given host string. isSecure
// should be true for WSS connections and false for WS.
func ( string,  bool) *Addr {
	 := "ws"
	if  {
		 = "wss"
	}
	return &Addr{
		URL: &url.URL{
			Scheme: ,
			Host:   ,
		},
	}
}

func ( ma.Multiaddr) (net.Addr, error) {
	,  := parseMultiaddr()
	if  != nil {
		return nil, 
	}
	return &Addr{URL: }, nil
}

func ( net.Addr) (ma.Multiaddr, error) {
	,  := .(*Addr)
	if ! {
		return nil, fmt.Errorf("not a websocket address")
	}

	var (
		 ma.Multiaddr
		   error
		  int
		  = .Hostname()
	)

	// Get the port
	if  := .Port();  != "" {
		,  = strconv.Atoi()
		if  != nil {
			return nil, fmt.Errorf("failed to parse port '%q': %s", , )
		}
	} else {
		return nil, fmt.Errorf("invalid port in url: '%q'", .URL)
	}

	// NOTE: Ignoring IPv6 zones...
	// Detect if host is IP address or DNS
	if  := net.ParseIP();  != nil {
		// Assume IP address
		,  = manet.FromNetAddr(&net.TCPAddr{
			IP:   ,
			Port: ,
		})
		if  != nil {
			return nil, 
		}
	} else {
		// Assume DNS name
		,  = ma.NewMultiaddr(fmt.Sprintf("/dns/%s/tcp/%d", , ))
		if  != nil {
			return nil, 
		}
	}

	,  := ma.NewMultiaddr("/" + .Scheme)
	if  != nil {
		return nil, 
	}

	return .Encapsulate(), nil
}

func parseMultiaddr( ma.Multiaddr) (*url.URL, error) {
	,  := parseWebsocketMultiaddr()
	if  != nil {
		return nil, 
	}

	 := "ws"
	if .isWSS {
		 = "wss"
	}

	, ,  := manet.DialArgs(.restMultiaddr)
	if  != nil {
		return nil, 
	}
	switch  {
	case "tcp", "tcp4", "tcp6":
	default:
		return nil, fmt.Errorf("unsupported websocket network %s", )
	}
	return &url.URL{
		Scheme: ,
		Host:   ,
	}, nil
}

type parsedWebsocketMultiaddr struct {
	isWSS bool
	// sni is the SNI value for the TLS handshake, and for setting HTTP Host header
	sni *ma.Component
	// the rest of the multiaddr before the /tls/sni/example.com/ws or /ws or /wss
	restMultiaddr ma.Multiaddr
}

func parseWebsocketMultiaddr( ma.Multiaddr) (parsedWebsocketMultiaddr, error) {
	 := parsedWebsocketMultiaddr{}
	// First check if we have a WSS component. If so we'll canonicalize it into a /tls/ws
	 := .Decapsulate(wssComponent.Multiaddr())
	if !.Equal() {
		 = .Encapsulate(tlsWsAddr)
	}

	// Remove the ws component
	 := .Decapsulate(wsComponent.Multiaddr())
	if .Equal() {
		return , fmt.Errorf("not a websocket multiaddr")
	}

	 := 
	// If this is not a wss then withoutWs is the rest of the multiaddr
	.restMultiaddr = 
	for {
		var  *ma.Component
		,  = ma.SplitLast()
		if  == nil || len() == 0 {
			break
		}

		if .Protocol().Code == ma.P_SNI {
			.sni = 
		} else if .Protocol().Code == ma.P_TLS {
			.isWSS = true
			.restMultiaddr = 
			break
		}
	}

	return , nil
}