// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zap

import (
	

	

	
)

const (
	_oddNumberErrMsg    = "Ignored key without a value."
	_nonStringKeyErrMsg = "Ignored key-value pairs with non-string keys."
	_multipleErrMsg     = "Multiple errors without a key."
)

// A SugaredLogger wraps the base Logger functionality in a slower, but less
// verbose, API. Any Logger can be converted to a SugaredLogger with its Sugar
// method.
//
// Unlike the Logger, the SugaredLogger doesn't insist on structured logging.
// For each log level, it exposes four methods:
//
//   - methods named after the log level for log.Print-style logging
//   - methods ending in "w" for loosely-typed structured logging
//   - methods ending in "f" for log.Printf-style logging
//   - methods ending in "ln" for log.Println-style logging
//
// For example, the methods for InfoLevel are:
//
//	Info(...any)           Print-style logging
//	Infow(...any)          Structured logging (read as "info with")
//	Infof(string, ...any)  Printf-style logging
//	Infoln(...any)         Println-style logging
type SugaredLogger struct {
	base *Logger
}

// Desugar unwraps a SugaredLogger, exposing the original Logger. Desugaring
// is quite inexpensive, so it's reasonable for a single application to use
// both Loggers and SugaredLoggers, converting between them on the boundaries
// of performance-sensitive code.
func ( *SugaredLogger) () *Logger {
	 := .base.clone()
	.callerSkip -= 2
	return 
}

// Named adds a sub-scope to the logger's name. See Logger.Named for details.
func ( *SugaredLogger) ( string) *SugaredLogger {
	return &SugaredLogger{base: .base.Named()}
}

// WithOptions clones the current SugaredLogger, applies the supplied Options,
// and returns the result. It's safe to use concurrently.
func ( *SugaredLogger) ( ...Option) *SugaredLogger {
	 := .base.clone()
	for ,  := range  {
		.apply()
	}
	return &SugaredLogger{base: }
}

// With adds a variadic number of fields to the logging context. It accepts a
// mix of strongly-typed Field objects and loosely-typed key-value pairs. When
// processing pairs, the first element of the pair is used as the field key
// and the second as the field value.
//
// For example,
//
//	 sugaredLogger.With(
//	   "hello", "world",
//	   "failure", errors.New("oh no"),
//	   Stack(),
//	   "count", 42,
//	   "user", User{Name: "alice"},
//	)
//
// is the equivalent of
//
//	unsugared.With(
//	  String("hello", "world"),
//	  String("failure", "oh no"),
//	  Stack(),
//	  Int("count", 42),
//	  Object("user", User{Name: "alice"}),
//	)
//
// Note that the keys in key-value pairs should be strings. In development,
// passing a non-string key panics. In production, the logger is more
// forgiving: a separate error is logged, but the key-value pair is skipped
// and execution continues. Passing an orphaned key triggers similar behavior:
// panics in development and errors in production.
func ( *SugaredLogger) ( ...interface{}) *SugaredLogger {
	return &SugaredLogger{base: .base.With(.sweetenFields()...)}
}

// Level reports the minimum enabled level for this logger.
//
// For NopLoggers, this is [zapcore.InvalidLevel].
func ( *SugaredLogger) () zapcore.Level {
	return zapcore.LevelOf(.base.core)
}

// Debug logs the provided arguments at [DebugLevel].
// Spaces are added between arguments when neither is a string.
func ( *SugaredLogger) ( ...interface{}) {
	.log(DebugLevel, "", , nil)
}

// Info logs the provided arguments at [InfoLevel].
// Spaces are added between arguments when neither is a string.
func ( *SugaredLogger) ( ...interface{}) {
	.log(InfoLevel, "", , nil)
}

// Warn logs the provided arguments at [WarnLevel].
// Spaces are added between arguments when neither is a string.
func ( *SugaredLogger) ( ...interface{}) {
	.log(WarnLevel, "", , nil)
}

// Error logs the provided arguments at [ErrorLevel].
// Spaces are added between arguments when neither is a string.
func ( *SugaredLogger) ( ...interface{}) {
	.log(ErrorLevel, "", , nil)
}

// DPanic logs the provided arguments at [DPanicLevel].
// In development, the logger then panics. (See [DPanicLevel] for details.)
// Spaces are added between arguments when neither is a string.
func ( *SugaredLogger) ( ...interface{}) {
	.log(DPanicLevel, "", , nil)
}

// Panic constructs a message with the provided arguments and panics.
// Spaces are added between arguments when neither is a string.
func ( *SugaredLogger) ( ...interface{}) {
	.log(PanicLevel, "", , nil)
}

// Fatal constructs a message with the provided arguments and calls os.Exit.
// Spaces are added between arguments when neither is a string.
func ( *SugaredLogger) ( ...interface{}) {
	.log(FatalLevel, "", , nil)
}

// Debugf formats the message according to the format specifier
// and logs it at [DebugLevel].
func ( *SugaredLogger) ( string,  ...interface{}) {
	.log(DebugLevel, , , nil)
}

// Infof formats the message according to the format specifier
// and logs it at [InfoLevel].
func ( *SugaredLogger) ( string,  ...interface{}) {
	.log(InfoLevel, , , nil)
}

// Warnf formats the message according to the format specifier
// and logs it at [WarnLevel].
func ( *SugaredLogger) ( string,  ...interface{}) {
	.log(WarnLevel, , , nil)
}

// Errorf formats the message according to the format specifier
// and logs it at [ErrorLevel].
func ( *SugaredLogger) ( string,  ...interface{}) {
	.log(ErrorLevel, , , nil)
}

// DPanicf formats the message according to the format specifier
// and logs it at [DPanicLevel].
// In development, the logger then panics. (See [DPanicLevel] for details.)
func ( *SugaredLogger) ( string,  ...interface{}) {
	.log(DPanicLevel, , , nil)
}

// Panicf formats the message according to the format specifier
// and panics.
func ( *SugaredLogger) ( string,  ...interface{}) {
	.log(PanicLevel, , , nil)
}

// Fatalf formats the message according to the format specifier
// and calls os.Exit.
func ( *SugaredLogger) ( string,  ...interface{}) {
	.log(FatalLevel, , , nil)
}

// Debugw logs a message with some additional context. The variadic key-value
// pairs are treated as they are in With.
//
// When debug-level logging is disabled, this is much faster than
//
//	s.With(keysAndValues).Debug(msg)
func ( *SugaredLogger) ( string,  ...interface{}) {
	.log(DebugLevel, , nil, )
}

// Infow logs a message with some additional context. The variadic key-value
// pairs are treated as they are in With.
func ( *SugaredLogger) ( string,  ...interface{}) {
	.log(InfoLevel, , nil, )
}

// Warnw logs a message with some additional context. The variadic key-value
// pairs are treated as they are in With.
func ( *SugaredLogger) ( string,  ...interface{}) {
	.log(WarnLevel, , nil, )
}

// Errorw logs a message with some additional context. The variadic key-value
// pairs are treated as they are in With.
func ( *SugaredLogger) ( string,  ...interface{}) {
	.log(ErrorLevel, , nil, )
}

// DPanicw logs a message with some additional context. In development, the
// logger then panics. (See DPanicLevel for details.) The variadic key-value
// pairs are treated as they are in With.
func ( *SugaredLogger) ( string,  ...interface{}) {
	.log(DPanicLevel, , nil, )
}

// Panicw logs a message with some additional context, then panics. The
// variadic key-value pairs are treated as they are in With.
func ( *SugaredLogger) ( string,  ...interface{}) {
	.log(PanicLevel, , nil, )
}

// Fatalw logs a message with some additional context, then calls os.Exit. The
// variadic key-value pairs are treated as they are in With.
func ( *SugaredLogger) ( string,  ...interface{}) {
	.log(FatalLevel, , nil, )
}

// Debugln logs a message at [DebugLevel].
// Spaces are always added between arguments.
func ( *SugaredLogger) ( ...interface{}) {
	.logln(DebugLevel, , nil)
}

// Infoln logs a message at [InfoLevel].
// Spaces are always added between arguments.
func ( *SugaredLogger) ( ...interface{}) {
	.logln(InfoLevel, , nil)
}

// Warnln logs a message at [WarnLevel].
// Spaces are always added between arguments.
func ( *SugaredLogger) ( ...interface{}) {
	.logln(WarnLevel, , nil)
}

// Errorln logs a message at [ErrorLevel].
// Spaces are always added between arguments.
func ( *SugaredLogger) ( ...interface{}) {
	.logln(ErrorLevel, , nil)
}

// DPanicln logs a message at [DPanicLevel].
// In development, the logger then panics. (See [DPanicLevel] for details.)
// Spaces are always added between arguments.
func ( *SugaredLogger) ( ...interface{}) {
	.logln(DPanicLevel, , nil)
}

// Panicln logs a message at [PanicLevel] and panics.
// Spaces are always added between arguments.
func ( *SugaredLogger) ( ...interface{}) {
	.logln(PanicLevel, , nil)
}

// Fatalln logs a message at [FatalLevel] and calls os.Exit.
// Spaces are always added between arguments.
func ( *SugaredLogger) ( ...interface{}) {
	.logln(FatalLevel, , nil)
}

// Sync flushes any buffered log entries.
func ( *SugaredLogger) () error {
	return .base.Sync()
}

// log message with Sprint, Sprintf, or neither.
func ( *SugaredLogger) ( zapcore.Level,  string,  []interface{},  []interface{}) {
	// If logging at this level is completely disabled, skip the overhead of
	// string formatting.
	if  < DPanicLevel && !.base.Core().Enabled() {
		return
	}

	 := getMessage(, )
	if  := .base.Check(, );  != nil {
		.Write(.sweetenFields()...)
	}
}

// logln message with Sprintln
func ( *SugaredLogger) ( zapcore.Level,  []interface{},  []interface{}) {
	if  < DPanicLevel && !.base.Core().Enabled() {
		return
	}

	 := getMessageln()
	if  := .base.Check(, );  != nil {
		.Write(.sweetenFields()...)
	}
}

// getMessage format with Sprint, Sprintf, or neither.
func getMessage( string,  []interface{}) string {
	if len() == 0 {
		return 
	}

	if  != "" {
		return fmt.Sprintf(, ...)
	}

	if len() == 1 {
		if ,  := [0].(string);  {
			return 
		}
	}
	return fmt.Sprint(...)
}

// getMessageln format with Sprintln.
func getMessageln( []interface{}) string {
	 := fmt.Sprintln(...)
	return [:len()-1]
}

func ( *SugaredLogger) ( []interface{}) []Field {
	if len() == 0 {
		return nil
	}

	var (
		// Allocate enough space for the worst case; if users pass only structured
		// fields, we shouldn't penalize them with extra allocations.
		    = make([]Field, 0, len())
		   invalidPairs
		 bool
	)

	for  := 0;  < len(); {
		// This is a strongly-typed field. Consume it and move on.
		if ,  := [].(Field);  {
			 = append(, )
			++
			continue
		}

		// If it is an error, consume it and move on.
		if ,  := [].(error);  {
			if ! {
				 = true
				 = append(, Error())
			} else {
				.base.Error(_multipleErrMsg, Error())
			}
			++
			continue
		}

		// Make sure this element isn't a dangling key.
		if  == len()-1 {
			.base.Error(_oddNumberErrMsg, Any("ignored", []))
			break
		}

		// Consume this value and the next, treating them as a key-value pair. If the
		// key isn't a string, add this pair to the slice of invalid pairs.
		,  := [], [+1]
		if ,  := .(string); ! {
			// Subsequent errors are likely, so allocate once up front.
			if cap() == 0 {
				 = make(invalidPairs, 0, len()/2)
			}
			 = append(, invalidPair{, , })
		} else {
			 = append(, Any(, ))
		}
		 += 2
	}

	// If we encountered any invalid key-value pairs, log an error.
	if len() > 0 {
		.base.Error(_nonStringKeyErrMsg, Array("invalid", ))
	}
	return 
}

type invalidPair struct {
	position   int
	key, value interface{}
}

func ( invalidPair) ( zapcore.ObjectEncoder) error {
	.AddInt64("position", int64(.position))
	Any("key", .key).AddTo()
	Any("value", .value).AddTo()
	return nil
}

type invalidPairs []invalidPair

func ( invalidPairs) ( zapcore.ArrayEncoder) error {
	var  error
	for  := range  {
		 = multierr.Append(, .AppendObject([]))
	}
	return 
}