package multiaddr

import (
	
	
	
	
	

	
)

// Component is a single multiaddr Component.
type Component struct {
	// bytes is the raw bytes of the component. It includes the protocol code as
	// varint, possibly the size of the value, and the value.
	bytes         string // string for immutability.
	protocol      *Protocol
	valueStartIdx int // Index of the first byte of the Component's value in the bytes array
}

func ( *Component) () Multiaddr {
	if  == nil {
		return nil
	}
	return []Component{*}
}

func ( *Component) ( Multiaddrer) Multiaddr {
	return .Multiaddr().Encapsulate()
}

func ( *Component) ( Multiaddrer) Multiaddr {
	return .Multiaddr().Decapsulate()
}

func ( *Component) () []byte {
	if  == nil {
		return nil
	}
	return []byte(.bytes)
}

func ( *Component) () ([]byte, error) {
	if  == nil {
		return nil, errNilPtr
	}
	return .Bytes(), nil
}

func ( *Component) ( []byte) error {
	if  == nil {
		return errNilPtr
	}
	, ,  := readComponent()
	if  != nil {
		return 
	}
	* = *
	return nil
}

func ( *Component) () ([]byte, error) {
	if  == nil {
		return nil, errNilPtr
	}
	return []byte(.String()), nil
}

func ( *Component) ( []byte) error {
	if  == nil {
		return errNilPtr
	}

	,  := stringToBytes(string())
	if  != nil {
		return 
	}
	, ,  := readComponent()
	if  != nil {
		return 
	}
	* = *
	return nil
}

func ( *Component) () ([]byte, error) {
	if  == nil {
		return nil, errNilPtr
	}
	,  := .MarshalText()
	if  != nil {
		return nil, 
	}

	return json.Marshal(string())
}

func ( *Component) ( []byte) error {
	if  == nil {
		return errNilPtr
	}

	var  string
	if  := json.Unmarshal(, &);  != nil {
		return 
	}

	return .UnmarshalText([]byte())
}

func ( *Component) ( *Component) bool {
	if  == nil ||  == nil {
		return  == 
	}
	return .bytes == .bytes
}

func ( *Component) ( *Component) int {
	if  == nil &&  == nil {
		return 0
	}
	if  == nil {
		return -1
	}
	if  == nil {
		return 1
	}
	return strings.Compare(.bytes, .bytes)
}

func ( *Component) () []Protocol {
	if  == nil {
		return nil
	}
	if .protocol == nil {
		return nil
	}
	return []Protocol{*.protocol}
}

func ( *Component) ( int) (string, error) {
	if  == nil {
		return "", fmt.Errorf("component is nil")
	}
	if .protocol == nil {
		return "", fmt.Errorf("component has nil protocol")
	}
	if .protocol.Code !=  {
		return "", ErrProtocolNotFound
	}
	return .Value(), nil
}

func ( *Component) () Protocol {
	if  == nil {
		return Protocol{}
	}
	if .protocol == nil {
		return Protocol{}
	}
	return *.protocol
}

func ( *Component) () int {
	if  == nil {
		return 0
	}
	return .Protocol().Code
}

func ( *Component) () []byte {
	if  == nil {
		return nil
	}
	return []byte(.bytes[.valueStartIdx:])
}

func ( *Component) () string {
	if  == nil {
		return ""
	}
	// This Component MUST have been checked by validateComponent when created
	,  := .valueAndErr()
	return 
}

func ( *Component) () (string, error) {
	if  == nil {
		return "", errNilPtr
	}
	if .protocol == nil {
		return "", fmt.Errorf("component has nil protocol")
	}
	if .protocol.Transcoder == nil {
		return "", nil
	}
	,  := .protocol.Transcoder.BytesToString([]byte(.bytes[.valueStartIdx:]))
	if  != nil {
		return "", 
	}
	return , nil
}

func ( *Component) () string {
	if  == nil {
		return "<nil component>"
	}
	var  strings.Builder
	.writeTo(&)
	return .String()
}

// writeTo is an efficient, private function for string-formatting a multiaddr.
// Trust me, we tend to allocate a lot when doing this.
func ( *Component) ( *strings.Builder) {
	if  == nil {
		return
	}
	if .protocol == nil {
		return
	}
	.WriteByte('/')
	.WriteString(.protocol.Name)
	 := .Value()
	if len() == 0 {
		return
	}
	if !(.protocol.Path && [0] == '/') {
		.WriteByte('/')
	}
	.WriteString()
}

// NewComponent constructs a new multiaddr component
func (,  string) (*Component, error) {
	 := ProtocolWithName()
	if .Code == 0 {
		return nil, fmt.Errorf("unsupported protocol: %s", )
	}
	if .Transcoder != nil {
		,  := .Transcoder.StringToBytes()
		if  != nil {
			return nil, 
		}
		return newComponent(, )
	} else if  != "" {
		return nil, fmt.Errorf("protocol %s doesn't take a value", .Name)
	}
	return newComponent(, nil)
}

func newComponent( Protocol,  []byte) (*Component, error) {
	 := protocolPtrByCode[.Code]
	if  == nil {
		 = &
	}

	 := len()
	 += len(.VCode)
	if .Size < 0 {
		 += varint.UvarintSize(uint64(len()))
	}
	 := make([]byte, )
	var  int
	 += copy([:], .VCode)
	if .Size < 0 {
		 += binary.PutUvarint([:], uint64(len()))
	}
	copy([:], )

	// Shouldn't happen
	if len() != +len() {
		return nil, fmt.Errorf("component size mismatch: %d != %d", len(), +len())
	}

	 := &Component{
		bytes:         string(),
		protocol:      ,
		valueStartIdx: ,
	}

	 := validateComponent()
	if  != nil {
		return nil, 
	}
	return , nil
}

// validateComponent MUST be called after creating a non-zero Component.
// It ensures that we will be able to call all methods on Component without
// error.
func validateComponent( *Component) error {
	if  == nil {
		return errNilPtr
	}
	if .protocol == nil {
		return fmt.Errorf("component is missing its protocol")
	}
	if .valueStartIdx > len(.bytes) {
		return fmt.Errorf("component valueStartIdx is greater than the length of the component's bytes")
	}

	if len(.protocol.VCode) == 0 {
		return fmt.Errorf("Component is missing its protocol's VCode field")
	}
	if len(.bytes) < len(.protocol.VCode) {
		return fmt.Errorf("component size mismatch: %d != %d", len(.bytes), len(.protocol.VCode))
	}
	if !bytes.Equal([]byte(.bytes[:len(.protocol.VCode)]), .protocol.VCode) {
		return fmt.Errorf("component's VCode field is invalid: %v != %v", []byte(.bytes[:len(.protocol.VCode)]), .protocol.VCode)
	}
	if .protocol.Size < 0 {
		, ,  := ReadVarintCode([]byte(.bytes[len(.protocol.VCode):]))
		if  != nil {
			return 
		}
		if  != len(.bytes[.valueStartIdx:]) {
			return fmt.Errorf("component value size mismatch: %d != %d", , len(.bytes[.valueStartIdx:]))
		}

		if len(.protocol.VCode)++ != len(.bytes) {
			return fmt.Errorf("component size mismatch: %d != %d", len(.protocol.VCode)++, len(.bytes))
		}
	} else {
		// Fixed size value
		 := .protocol.Size / 8
		if  != len(.bytes[.valueStartIdx:]) {
			return fmt.Errorf("component value size mismatch: %d != %d", , len(.bytes[.valueStartIdx:]))
		}

		if len(.protocol.VCode)+ != len(.bytes) {
			return fmt.Errorf("component size mismatch: %d != %d", len(.protocol.VCode)+, len(.bytes))
		}
	}

	,  := .valueAndErr()
	if  != nil {
		return 

	}
	if .protocol.Transcoder != nil {
		 = .protocol.Transcoder.ValidateBytes([]byte(.bytes[.valueStartIdx:]))
		if  != nil {
			return 
		}
	}
	return nil
}