package peer

import (
	

	ma 
)

// AddrInfo is a small struct used to pass around a peer with
// a set of addresses (and later, keys?).
type AddrInfo struct {
	ID    ID
	Addrs []ma.Multiaddr
}

var _ fmt.Stringer = AddrInfo{}

func ( AddrInfo) () string {
	return fmt.Sprintf("{%v: %v}", .ID, .Addrs)
}

var ErrInvalidAddr = fmt.Errorf("invalid p2p multiaddr")

// AddrInfosFromP2pAddrs converts a set of Multiaddrs to a set of AddrInfos.
func ( ...ma.Multiaddr) ([]AddrInfo, error) {
	 := make(map[ID][]ma.Multiaddr)
	for ,  := range  {
		,  := SplitAddr()
		if  == "" {
			return nil, ErrInvalidAddr
		}
		if  == nil {
			if ,  := []; ! {
				[] = nil
			}
		} else {
			[] = append([], )
		}
	}
	 := make([]AddrInfo, 0, len())
	for ,  := range  {
		 = append(, AddrInfo{ID: , Addrs: })
	}
	return , nil
}

// SplitAddr splits a p2p Multiaddr into a transport multiaddr and a peer ID.
//
// * Returns a nil transport if the address only contains a /p2p part.
// * Returns an empty peer ID if the address doesn't contain a /p2p part.
func ( ma.Multiaddr) ( ma.Multiaddr,  ID) {
	if  == nil {
		return nil, ""
	}

	,  := ma.SplitLast()
	if  == nil || .Protocol().Code != ma.P_P2P {
		return , ""
	}
	 = ID(.RawValue()) // already validated by the multiaddr library.
	return , 
}

// IDFromP2PAddr extracts the peer ID from a p2p Multiaddr
func ( ma.Multiaddr) (ID, error) {
	if  == nil {
		return "", ErrInvalidAddr
	}
	var  ma.Component
	ma.ForEach(, func( ma.Component) bool {
		 = 
		return true
	})
	if .Protocol().Code != ma.P_P2P {
		return "", ErrInvalidAddr
	}

	 := ID(.RawValue()) // already validated by the multiaddr library.
	return , nil
}

// AddrInfoFromString builds an AddrInfo from the string representation of a Multiaddr
func ( string) (*AddrInfo, error) {
	,  := ma.NewMultiaddr()
	if  != nil {
		return nil, 
	}

	return AddrInfoFromP2pAddr()
}

// AddrInfoFromP2pAddr converts a Multiaddr to an AddrInfo.
func ( ma.Multiaddr) (*AddrInfo, error) {
	,  := SplitAddr()
	if  == "" {
		return nil, ErrInvalidAddr
	}
	 := &AddrInfo{ID: }
	if  != nil {
		.Addrs = []ma.Multiaddr{}
	}
	return , nil
}

// AddrInfoToP2pAddrs converts an AddrInfo to a list of Multiaddrs.
func ( *AddrInfo) ([]ma.Multiaddr, error) {
	,  := ma.NewComponent("p2p", .ID.String())
	if  != nil {
		return nil, 
	}
	if len(.Addrs) == 0 {
		return []ma.Multiaddr{.Multiaddr()}, nil
	}
	 := make([]ma.Multiaddr, 0, len(.Addrs))
	for ,  := range .Addrs {
		 = append(, .Encapsulate())
	}
	return , nil
}

func ( *AddrInfo) () map[string]interface{} {
	return map[string]interface{}{
		"peerID": .ID.String(),
		"addrs":  .Addrs,
	}
}

// AddrInfosToIDs extracts the peer IDs from the passed AddrInfos and returns them in-order.
func ( []AddrInfo) []ID {
	 := make([]ID, len())
	for ,  := range  {
		[] = .ID
	}
	return 
}