package log

import 

// Wither is an optional Logger capability: returning a child Logger with attrs
// permanently attached to every record. Adapters implement it to map onto a
// native mechanism (e.g. zap.Logger.With); With falls back to a wrapper for
// loggers that do not.
type Wither interface {
	With(attrs ...Attr) Logger
}

// Namer is an optional Logger capability: returning a child Logger tagged with a
// name. Adapters implement it to map onto a native mechanism (e.g.
// zap.Logger.Named); Named is a no-op for loggers that do not, since the name is
// advisory.
type Namer interface {
	Named(name string) Logger
}

// With returns a child Logger that attaches attrs to every record. It uses the
// logger's native With when it implements Wither, otherwise it wraps l. With no
// attrs it returns l unchanged.
func ( Logger,  ...Attr) Logger {
	 = OrNop()
	if len() == 0 {
		return 
	}
	if ,  := .(Wither);  {
		return .With(...)
	}
	return &withLogger{l: , attrs: append([]Attr(nil), ...)}
}

// Named returns a child Logger tagged with name. It uses the logger's native
// Named when it implements Namer, otherwise it returns l unchanged (the name is
// advisory for backends without a naming concept). With an empty name it returns
// l unchanged.
func ( Logger,  string) Logger {
	 = OrNop()
	if  == "" {
		return 
	}
	if ,  := .(Namer);  {
		return .Named()
	}
	return 
}

type withLogger struct {
	l     Logger
	attrs []Attr
}

func ( *withLogger) ( context.Context,  Level) bool {
	return .l.Enabled(, )
}

func ( *withLogger) ( context.Context,  Level,  string,  ...Attr) {
	// Prepend the attached attrs; cap the stored slice so append never mutates it.
	 := append(.attrs[:len(.attrs):len(.attrs)], ...)
	.l.Log(, , , ...)
}

// With implements Wither so chained With calls accumulate without re-wrapping.
func ( *withLogger) ( ...Attr) Logger {
	return With(.l, append(.attrs[:len(.attrs):len(.attrs)], ...)...)
}