// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package httptest

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/textproto"
	"strconv"
	"strings"

	"golang.org/x/net/http/httpguts"
)

// ResponseRecorder is an implementation of http.ResponseWriter that
// records its mutations for later inspection in tests.
type ResponseRecorder struct {
	// Code is the HTTP response code set by WriteHeader.
	//
	// Note that if a Handler never calls WriteHeader or Write,
	// this might end up being 0, rather than the implicit
	// http.StatusOK. To get the implicit value, use the Result
	// method.
	Code int

	// HeaderMap contains the headers explicitly set by the Handler.
	// It is an internal detail.
	//
	// Deprecated: HeaderMap exists for historical compatibility
	// and should not be used. To access the headers returned by a handler,
	// use the Response.Header map as returned by the Result method.
	HeaderMap http.Header

	// Body is the buffer to which the Handler's Write calls are sent.
	// If nil, the Writes are silently discarded.
	Body *bytes.Buffer

	// Flushed is whether the Handler called Flush.
	Flushed bool

	result      *http.Response // cache of Result's return value
	snapHeader  http.Header    // snapshot of HeaderMap at first Write
	wroteHeader bool
}

// NewRecorder returns an initialized ResponseRecorder.
func () *ResponseRecorder {
	return &ResponseRecorder{
		HeaderMap: make(http.Header),
		Body:      new(bytes.Buffer),
		Code:      200,
	}
}

// DefaultRemoteAddr is the default remote address to return in RemoteAddr if
// an explicit DefaultRemoteAddr isn't set on ResponseRecorder.
const DefaultRemoteAddr = "1.2.3.4"

// Header implements http.ResponseWriter. It returns the response
// headers to mutate within a handler. To test the headers that were
// written after a handler completes, use the Result method and see
// the returned Response value's Header.
func ( *ResponseRecorder) () http.Header {
	 := .HeaderMap
	if  == nil {
		 = make(http.Header)
		.HeaderMap = 
	}
	return 
}

// writeHeader writes a header if it was not written yet and
// detects Content-Type if needed.
//
// bytes or str are the beginning of the response body.
// We pass both to avoid unnecessarily generate garbage
// in rw.WriteString which was created for performance reasons.
// Non-nil bytes win.
func ( *ResponseRecorder) ( []byte,  string) {
	if .wroteHeader {
		return
	}
	if len() > 512 {
		 = [:512]
	}

	 := .Header()

	,  := ["Content-Type"]
	 := .Get("Transfer-Encoding") != ""
	if ! && ! {
		if  == nil {
			 = []byte()
		}
		.Set("Content-Type", http.DetectContentType())
	}

	.WriteHeader(200)
}

// Write implements http.ResponseWriter. The data in buf is written to
// rw.Body, if not nil.
func ( *ResponseRecorder) ( []byte) (int, error) {
	.writeHeader(, "")
	if .Body != nil {
		.Body.Write()
	}
	return len(), nil
}

// WriteString implements io.StringWriter. The data in str is written
// to rw.Body, if not nil.
func ( *ResponseRecorder) ( string) (int, error) {
	.writeHeader(nil, )
	if .Body != nil {
		.Body.WriteString()
	}
	return len(), nil
}

// WriteHeader implements http.ResponseWriter.
func ( *ResponseRecorder) ( int) {
	if .wroteHeader {
		return
	}
	.Code = 
	.wroteHeader = true
	if .HeaderMap == nil {
		.HeaderMap = make(http.Header)
	}
	.snapHeader = .HeaderMap.Clone()
}

// Flush implements http.Flusher. To test whether Flush was
// called, see rw.Flushed.
func ( *ResponseRecorder) () {
	if !.wroteHeader {
		.WriteHeader(200)
	}
	.Flushed = true
}

// Result returns the response generated by the handler.
//
// The returned Response will have at least its StatusCode,
// Header, Body, and optionally Trailer populated.
// More fields may be populated in the future, so callers should
// not DeepEqual the result in tests.
//
// The Response.Header is a snapshot of the headers at the time of the
// first write call, or at the time of this call, if the handler never
// did a write.
//
// The Response.Body is guaranteed to be non-nil and Body.Read call is
// guaranteed to not return any error other than io.EOF.
//
// Result must only be called after the handler has finished running.
func ( *ResponseRecorder) () *http.Response {
	if .result != nil {
		return .result
	}
	if .snapHeader == nil {
		.snapHeader = .HeaderMap.Clone()
	}
	 := &http.Response{
		Proto:      "HTTP/1.1",
		ProtoMajor: 1,
		ProtoMinor: 1,
		StatusCode: .Code,
		Header:     .snapHeader,
	}
	.result = 
	if .StatusCode == 0 {
		.StatusCode = 200
	}
	.Status = fmt.Sprintf("%03d %s", .StatusCode, http.StatusText(.StatusCode))
	if .Body != nil {
		.Body = ioutil.NopCloser(bytes.NewReader(.Body.Bytes()))
	} else {
		.Body = http.NoBody
	}
	.ContentLength = parseContentLength(.Header.Get("Content-Length"))

	if ,  := .snapHeader["Trailer"];  {
		.Trailer = make(http.Header, len())
		for ,  := range  {
			 = http.CanonicalHeaderKey()
			if !httpguts.ValidTrailerHeader() {
				// Ignore since forbidden by RFC 7230, section 4.1.2.
				continue
			}
			,  := .HeaderMap[]
			if ! {
				continue
			}
			 := make([]string, len())
			copy(, )
			.Trailer[] = 
		}
	}
	for ,  := range .HeaderMap {
		if !strings.HasPrefix(, http.TrailerPrefix) {
			continue
		}
		if .Trailer == nil {
			.Trailer = make(http.Header)
		}
		for ,  := range  {
			.Trailer.Add(strings.TrimPrefix(, http.TrailerPrefix), )
		}
	}
	return 
}

// parseContentLength trims whitespace from s and returns -1 if no value
// is set, or the value if it's >= 0.
//
// This a modified version of same function found in net/http/transfer.go. This
// one just ignores an invalid header.
func parseContentLength( string) int64 {
	 = textproto.TrimString()
	if  == "" {
		return -1
	}
	,  := strconv.ParseUint(, 10, 63)
	if  != nil {
		return -1
	}
	return int64()
}