package rest

import (
	"log"
	"net/http"
	"strings"
)

// DoerFunc satisfies Interface. DoerFuncs are useful for adding
// logging/instrumentation to the http.Client that is used
// within the rest.APIClient.
type DoerFunc func(*http.Request) (*http.Response, error)

// Do is implementation of rest.Doer interface. Calls itself on the
// given http.Request.
func (f DoerFunc) Do(r *http.Request) (*http.Response, error) {
	return f(r)
}

// A Decorator wraps a Doer with extra behavior, and doesnt
// affect the behavior of other instances of the same type.
type Decorator func(Doer) Doer

// Decorate decorates a Doer c with all the given Decorators, in order.
// Core object(Doer instance) that we want to apply layers(Decorator slice) to.
func Decorate(d Doer, ds ...Decorator) Doer {
	decorated := d
	for _, decorate := range ds {
		decorated = decorate(decorated)
	}
	return decorated
}

// Logging returns a Decorator that logs a Doer's requests.
// Dependency injection for the logger instance(inside the closures environment).
func Logging(l *log.Logger) Decorator {
	return func(d Doer) Doer {
		return DoerFunc(func(r *http.Request) (*http.Response, error) {
			userAgent := r.UserAgent()
			escapedUserAgent := strings.Replace(userAgent, "\n", "", -1)
			escapedUserAgent = strings.Replace(escapedUserAgent, "\r", "", -1)
			userURL := r.URL.String()
			escapedURL := strings.Replace(userURL, "\n", "", -1)
			escapedURL = strings.Replace(escapedURL, "\r", "", -1)
			l.Printf("%s: %s %s", escapedUserAgent, r.Method, escapedURL)
			return d.Do(r)
		})
	}
}
