package httpbinding

import (
	
	
	
	
	
)

const (
	contentLengthHeader = "Content-Length"
	floatNaN            = "NaN"
	floatInfinity       = "Infinity"
	floatNegInfinity    = "-Infinity"
)

// An Encoder provides encoding of REST URI path, query, and header components
// of an HTTP request. Can also encode a stream as the payload.
//
// Does not support SetFields.
type Encoder struct {
	path, rawPath, pathBuffer []byte

	query  url.Values
	header http.Header
}

// NewEncoder creates a new encoder from the passed in request. All query and
// header values will be added on top of the request's existing values. Overwriting
// duplicate values.
func (,  string,  http.Header) (*Encoder, error) {
	,  := url.ParseQuery()
	if  != nil {
		return nil, fmt.Errorf("failed to parse query string: %w", )
	}

	 := &Encoder{
		path:    []byte(),
		rawPath: []byte(),
		query:   ,
		header:  .Clone(),
	}

	return , nil
}

// Encode returns a REST protocol encoder for encoding HTTP bindings.
//
// Due net/http requiring `Content-Length` to be specified on the http.Request#ContentLength directly. Encode
// will look for whether the header is present, and if so will remove it and set the respective value on http.Request.
//
// Returns any error occurring during encoding.
func ( *Encoder) ( *http.Request) (*http.Request, error) {
	.URL.Path, .URL.RawPath = string(.path), string(.rawPath)
	.URL.RawQuery = .query.Encode()

	// net/http ignores Content-Length header and requires it to be set on http.Request
	if  := .header.Get(contentLengthHeader); len() > 0 {
		,  := strconv.ParseInt(, 10, 64)
		if  != nil {
			return nil, 
		}
		.ContentLength = 
		.header.Del(contentLengthHeader)
	}

	.Header = .header

	return , nil
}

// AddHeader returns a HeaderValue for appending to the given header name
func ( *Encoder) ( string) HeaderValue {
	return newHeaderValue(.header, , true)
}

// SetHeader returns a HeaderValue for setting the given header name
func ( *Encoder) ( string) HeaderValue {
	return newHeaderValue(.header, , false)
}

// Headers returns a Header used for encoding headers with the given prefix
func ( *Encoder) ( string) Headers {
	return Headers{
		header: .header,
		prefix: strings.TrimSpace(),
	}
}

// HasHeader returns if a header with the key specified exists with one or
// more value.
func ( Encoder) ( string) bool {
	return len(.header[]) != 0
}

// SetURI returns a URIValue used for setting the given path key
func ( *Encoder) ( string) URIValue {
	return newURIValue(&.path, &.rawPath, &.pathBuffer, )
}

// SetQuery returns a QueryValue used for setting the given query key
func ( *Encoder) ( string) QueryValue {
	return NewQueryValue(.query, , false)
}

// AddQuery returns a QueryValue used for appending the given query key
func ( *Encoder) ( string) QueryValue {
	return NewQueryValue(.query, , true)
}

// HasQuery returns if a query with the key specified exists with one or
// more values.
func ( *Encoder) ( string) bool {
	return len(.query.Get()) != 0
}