package log

import 

// Logger is the fundamental interface for all log operations. Log creates a
// log event from keyvals, a variadic sequence of alternating keys and values.
// Implementations must be safe for concurrent use by multiple goroutines. In
// particular, any implementation of Logger that appends to keyvals or
// modifies or retains any of its elements must make a copy first.
type Logger interface {
	Log(keyvals ...interface{}) error
}

// ErrMissingValue is appended to keyvals slices with odd length to substitute
// the missing value.
var ErrMissingValue = errors.New("(MISSING)")

// With returns a new contextual logger with keyvals prepended to those passed
// to calls to Log. If logger is also a contextual logger created by With,
// WithPrefix, or WithSuffix, keyvals is appended to the existing context.
//
// The returned Logger replaces all value elements (odd indexes) containing a
// Valuer with their generated value for each call to its Log method.
func ( Logger,  ...interface{}) Logger {
	if len() == 0 {
		return 
	}
	 := newContext()
	 := append(.keyvals, ...)
	if len()%2 != 0 {
		 = append(, ErrMissingValue)
	}
	return &context{
		logger: .logger,
		// Limiting the capacity of the stored keyvals ensures that a new
		// backing array is created if the slice must grow in Log or With.
		// Using the extra capacity without copying risks a data race that
		// would violate the Logger interface contract.
		keyvals:    [:len():len()],
		hasValuer:  .hasValuer || containsValuer(),
		sKeyvals:   .sKeyvals,
		sHasValuer: .sHasValuer,
	}
}

// WithPrefix returns a new contextual logger with keyvals prepended to those
// passed to calls to Log. If logger is also a contextual logger created by
// With, WithPrefix, or WithSuffix, keyvals is prepended to the existing context.
//
// The returned Logger replaces all value elements (odd indexes) containing a
// Valuer with their generated value for each call to its Log method.
func ( Logger,  ...interface{}) Logger {
	if len() == 0 {
		return 
	}
	 := newContext()
	// Limiting the capacity of the stored keyvals ensures that a new
	// backing array is created if the slice must grow in Log or With.
	// Using the extra capacity without copying risks a data race that
	// would violate the Logger interface contract.
	 := len(.keyvals) + len()
	if len()%2 != 0 {
		++
	}
	 := make([]interface{}, 0, )
	 = append(, ...)
	if len()%2 != 0 {
		 = append(, ErrMissingValue)
	}
	 = append(, .keyvals...)
	return &context{
		logger:     .logger,
		keyvals:    ,
		hasValuer:  .hasValuer || containsValuer(),
		sKeyvals:   .sKeyvals,
		sHasValuer: .sHasValuer,
	}
}

// WithSuffix returns a new contextual logger with keyvals appended to those
// passed to calls to Log. If logger is also a contextual logger created by
// With, WithPrefix, or WithSuffix, keyvals is appended to the existing context.
//
// The returned Logger replaces all value elements (odd indexes) containing a
// Valuer with their generated value for each call to its Log method.
func ( Logger,  ...interface{}) Logger {
	if len() == 0 {
		return 
	}
	 := newContext()
	// Limiting the capacity of the stored keyvals ensures that a new
	// backing array is created if the slice must grow in Log or With.
	// Using the extra capacity without copying risks a data race that
	// would violate the Logger interface contract.
	 := len(.sKeyvals) + len()
	if len()%2 != 0 {
		++
	}
	 := make([]interface{}, 0, )
	 = append(, ...)
	if len()%2 != 0 {
		 = append(, ErrMissingValue)
	}
	 = append(.sKeyvals, ...)
	return &context{
		logger:     .logger,
		keyvals:    .keyvals,
		hasValuer:  .hasValuer,
		sKeyvals:   ,
		sHasValuer: .sHasValuer || containsValuer(),
	}
}

// context is the Logger implementation returned by With, WithPrefix, and
// WithSuffix. It wraps a Logger and holds keyvals that it includes in all
// log events. Its Log method calls bindValues to generate values for each
// Valuer in the context keyvals.
//
// A context must always have the same number of stack frames between calls to
// its Log method and the eventual binding of Valuers to their value. This
// requirement comes from the functional requirement to allow a context to
// resolve application call site information for a Caller stored in the
// context. To do this we must be able to predict the number of logging
// functions on the stack when bindValues is called.
//
// Two implementation details provide the needed stack depth consistency.
//
//    1. newContext avoids introducing an additional layer when asked to
//       wrap another context.
//    2. With, WithPrefix, and WithSuffix avoid introducing an additional
//       layer by returning a newly constructed context with a merged keyvals
//       rather than simply wrapping the existing context.
type context struct {
	logger     Logger
	keyvals    []interface{}
	sKeyvals   []interface{} // suffixes
	hasValuer  bool
	sHasValuer bool
}

func newContext( Logger) *context {
	if ,  := .(*context);  {
		return 
	}
	return &context{logger: }
}

// Log replaces all value elements (odd indexes) containing a Valuer in the
// stored context with their generated value, appends keyvals, and passes the
// result to the wrapped Logger.
func ( *context) ( ...interface{}) error {
	 := append(.keyvals, ...)
	if len()%2 != 0 {
		 = append(, ErrMissingValue)
	}
	if .hasValuer {
		// If no keyvals were appended above then we must copy l.keyvals so
		// that future log events will reevaluate the stored Valuers.
		if len() == 0 {
			 = append([]interface{}{}, .keyvals...)
		}
		bindValues([:(len(.keyvals))])
	}
	 = append(, .sKeyvals...)
	if .sHasValuer {
		bindValues([len()-len(.sKeyvals):])
	}
	return .logger.Log(...)
}

// LoggerFunc is an adapter to allow use of ordinary functions as Loggers. If
// f is a function with the appropriate signature, LoggerFunc(f) is a Logger
// object that calls f.
type LoggerFunc func(...interface{}) error

// Log implements Logger by calling f(keyvals...).
func ( LoggerFunc) ( ...interface{}) error {
	return (...)
}