// Copyright 2010 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 proto

import (
	
	
	
	
	
	
	

	
	
	
	
	
)

const wrapTextMarshalV2 = false

// TextMarshaler is a configurable text format marshaler.
type TextMarshaler struct {
	Compact   bool // use compact text format (one line)
	ExpandAny bool // expand google.protobuf.Any messages of known types
}

// Marshal writes the proto text format of m to w.
func ( *TextMarshaler) ( io.Writer,  Message) error {
	,  := .marshal()
	if len() > 0 {
		if ,  := .Write();  != nil {
			return 
		}
	}
	return 
}

// Text returns a proto text formatted string of m.
func ( *TextMarshaler) ( Message) string {
	,  := .marshal()
	return string()
}

func ( *TextMarshaler) ( Message) ([]byte, error) {
	 := MessageReflect()
	if  == nil || !.IsValid() {
		return []byte("<nil>"), nil
	}

	if wrapTextMarshalV2 {
		if ,  := .(encoding.TextMarshaler);  {
			return .MarshalText()
		}

		 := prototext.MarshalOptions{
			AllowPartial: true,
			EmitUnknown:  true,
		}
		if !.Compact {
			.Indent = "  "
		}
		if !.ExpandAny {
			.Resolver = (*protoregistry.Types)(nil)
		}
		return .Marshal(.Interface())
	} else {
		 := &textWriter{
			compact:   .Compact,
			expandAny: .ExpandAny,
			complete:  true,
		}

		if ,  := .(encoding.TextMarshaler);  {
			,  := .MarshalText()
			if  != nil {
				return nil, 
			}
			.Write()
			return .buf, nil
		}

		 := .writeMessage()
		return .buf, 
	}
}

var (
	defaultTextMarshaler = TextMarshaler{}
	compactTextMarshaler = TextMarshaler{Compact: true}
)

// MarshalText writes the proto text format of m to w.
func ( io.Writer,  Message) error { return defaultTextMarshaler.Marshal(, ) }

// MarshalTextString returns a proto text formatted string of m.
func ( Message) string { return defaultTextMarshaler.Text() }

// CompactText writes the compact proto text format of m to w.
func ( io.Writer,  Message) error { return compactTextMarshaler.Marshal(, ) }

// CompactTextString returns a compact proto text formatted string of m.
func ( Message) string { return compactTextMarshaler.Text() }

var (
	newline         = []byte("\n")
	endBraceNewline = []byte("}\n")
	posInf          = []byte("inf")
	negInf          = []byte("-inf")
	nan             = []byte("nan")
)

// textWriter is an io.Writer that tracks its indentation level.
type textWriter struct {
	compact   bool // same as TextMarshaler.Compact
	expandAny bool // same as TextMarshaler.ExpandAny
	complete  bool // whether the current position is a complete line
	indent    int  // indentation level; never negative
	buf       []byte
}

func ( *textWriter) ( []byte) ( int,  error) {
	 := bytes.Count(, newline)
	if  == 0 {
		if !.compact && .complete {
			.writeIndent()
		}
		.buf = append(.buf, ...)
		.complete = false
		return len(), nil
	}

	 := bytes.SplitN(, newline, +1)
	if .compact {
		for ,  := range  {
			if  > 0 {
				.buf = append(.buf, ' ')
				++
			}
			.buf = append(.buf, ...)
			 += len()
		}
		return , nil
	}

	for ,  := range  {
		if .complete {
			.writeIndent()
		}
		.buf = append(.buf, ...)
		 += len()
		if +1 < len() {
			.buf = append(.buf, '\n')
			++
		}
	}
	.complete = len([len()-1]) == 0
	return , nil
}

func ( *textWriter) ( byte) error {
	if .compact &&  == '\n' {
		 = ' '
	}
	if !.compact && .complete {
		.writeIndent()
	}
	.buf = append(.buf, )
	.complete =  == '\n'
	return nil
}

func ( *textWriter) ( protoreflect.FieldDescriptor) {
	if !.compact && .complete {
		.writeIndent()
	}
	.complete = false

	if .Kind() != protoreflect.GroupKind {
		.buf = append(.buf, .Name()...)
		.WriteByte(':')
	} else {
		// Use message type name for group field name.
		.buf = append(.buf, .Message().Name()...)
	}

	if !.compact {
		.WriteByte(' ')
	}
}

func ( string) bool {
	// When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.
	for ,  := range  {
		switch {
		case  == '.' ||  == '/' ||  == '_':
			continue
		case '0' <=  &&  <= '9':
			continue
		case 'A' <=  &&  <= 'Z':
			continue
		case 'a' <=  &&  <= 'z':
			continue
		default:
			return true
		}
	}
	return false
}

// writeProto3Any writes an expanded google.protobuf.Any message.
//
// It returns (false, nil) if sv value can't be unmarshaled (e.g. because
// required messages are not linked in).
//
// It returns (true, error) when sv was written in expanded format or an error
// was encountered.
func ( *textWriter) ( protoreflect.Message) (bool, error) {
	 := .Descriptor()
	 := .Fields().ByName("type_url")
	 := .Fields().ByName("value")

	 := .Get().String()
	,  := protoregistry.GlobalTypes.FindMessageByURL()
	if  != nil {
		return false, nil
	}

	 := .Get().Bytes()
	 := .New()
	if  := proto.Unmarshal(, .Interface());  != nil {
		return false, nil
	}
	.Write([]byte("["))
	if requiresQuotes() {
		.writeQuotedString()
	} else {
		.Write([]byte())
	}
	if .compact {
		.Write([]byte("]:<"))
	} else {
		.Write([]byte("]: <\n"))
		.indent++
	}
	if  := .writeMessage();  != nil {
		return true, 
	}
	if .compact {
		.Write([]byte("> "))
	} else {
		.indent--
		.Write([]byte(">\n"))
	}
	return true, nil
}

func ( *textWriter) ( protoreflect.Message) error {
	 := .Descriptor()
	if .expandAny && .FullName() == "google.protobuf.Any" {
		if ,  := .writeProto3Any();  {
			return 
		}
	}

	 := .Fields()
	for  := 0;  < .Len(); {
		 := .Get()
		if  := .ContainingOneof();  != nil {
			 = .WhichOneof()
			 += .Fields().Len()
		} else {
			++
		}
		if  == nil || !.Has() {
			continue
		}

		switch {
		case .IsList():
			 := .Get().List()
			for  := 0;  < .Len(); ++ {
				.writeName()
				 := .Get()
				if  := .writeSingularValue(, );  != nil {
					return 
				}
				.WriteByte('\n')
			}
		case .IsMap():
			 := .MapKey()
			 := .MapValue()
			 := .Get().Map()

			type  struct{ ,  protoreflect.Value }
			var  []
			.Range(func( protoreflect.MapKey,  protoreflect.Value) bool {
				 = append(, {.Value(), })
				return true
			})
			sort.Slice(, func(,  int) bool {
				switch .Kind() {
				case protoreflect.BoolKind:
					return ![]..Bool() && []..Bool()
				case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
					return []..Int() < []..Int()
				case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
					return []..Uint() < []..Uint()
				case protoreflect.StringKind:
					return []..String() < []..String()
				default:
					panic("invalid kind")
				}
			})
			for ,  := range  {
				.writeName()
				.WriteByte('<')
				if !.compact {
					.WriteByte('\n')
				}
				.indent++
				.writeName()
				if  := .writeSingularValue(., );  != nil {
					return 
				}
				.WriteByte('\n')
				.writeName()
				if  := .writeSingularValue(., );  != nil {
					return 
				}
				.WriteByte('\n')
				.indent--
				.WriteByte('>')
				.WriteByte('\n')
			}
		default:
			.writeName()
			if  := .writeSingularValue(.Get(), );  != nil {
				return 
			}
			.WriteByte('\n')
		}
	}

	if  := .GetUnknown(); len() > 0 {
		.writeUnknownFields()
	}
	return .writeExtensions()
}

func ( *textWriter) ( protoreflect.Value,  protoreflect.FieldDescriptor) error {
	switch .Kind() {
	case protoreflect.FloatKind, protoreflect.DoubleKind:
		switch  := .Float(); {
		case math.IsInf(, +1):
			.Write(posInf)
		case math.IsInf(, -1):
			.Write(negInf)
		case math.IsNaN():
			.Write(nan)
		default:
			fmt.Fprint(, .Interface())
		}
	case protoreflect.StringKind:
		// NOTE: This does not validate UTF-8 for historical reasons.
		.writeQuotedString(string(.String()))
	case protoreflect.BytesKind:
		.writeQuotedString(string(.Bytes()))
	case protoreflect.MessageKind, protoreflect.GroupKind:
		var ,  byte = '<', '>'
		if .Kind() == protoreflect.GroupKind {
			,  = '{', '}'
		}
		.WriteByte()
		if !.compact {
			.WriteByte('\n')
		}
		.indent++
		 := .Message()
		if ,  := .Interface().(encoding.TextMarshaler);  {
			,  := .MarshalText()
			if  != nil {
				return 
			}
			.Write()
		} else {
			.writeMessage()
		}
		.indent--
		.WriteByte()
	case protoreflect.EnumKind:
		if  := .Enum().Values().ByNumber(.Enum());  != nil {
			fmt.Fprint(, .Name())
		} else {
			fmt.Fprint(, .Enum())
		}
	default:
		fmt.Fprint(, .Interface())
	}
	return nil
}

// writeQuotedString writes a quoted string in the protocol buffer text format.
func ( *textWriter) ( string) {
	.WriteByte('"')
	for  := 0;  < len(); ++ {
		switch  := [];  {
		case '\n':
			.buf = append(.buf, `\n`...)
		case '\r':
			.buf = append(.buf, `\r`...)
		case '\t':
			.buf = append(.buf, `\t`...)
		case '"':
			.buf = append(.buf, `\"`...)
		case '\\':
			.buf = append(.buf, `\\`...)
		default:
			if  :=  >= 0x20 &&  < 0x7f;  {
				.buf = append(.buf, )
			} else {
				.buf = append(.buf, fmt.Sprintf(`\%03o`, )...)
			}
		}
	}
	.WriteByte('"')
}

func ( *textWriter) ( []byte) {
	if !.compact {
		fmt.Fprintf(, "/* %d unknown bytes */\n", len())
	}

	for len() > 0 {
		, ,  := protowire.ConsumeTag()
		if  < 0 {
			return
		}
		 = [:]

		if  == protowire.EndGroupType {
			.indent--
			.Write(endBraceNewline)
			continue
		}
		fmt.Fprint(, )
		if  != protowire.StartGroupType {
			.WriteByte(':')
		}
		if !.compact ||  == protowire.StartGroupType {
			.WriteByte(' ')
		}
		switch  {
		case protowire.VarintType:
			,  := protowire.ConsumeVarint()
			if  < 0 {
				return
			}
			 = [:]
			fmt.Fprint(, )
		case protowire.Fixed32Type:
			,  := protowire.ConsumeFixed32()
			if  < 0 {
				return
			}
			 = [:]
			fmt.Fprint(, )
		case protowire.Fixed64Type:
			,  := protowire.ConsumeFixed64()
			if  < 0 {
				return
			}
			 = [:]
			fmt.Fprint(, )
		case protowire.BytesType:
			,  := protowire.ConsumeBytes()
			if  < 0 {
				return
			}
			 = [:]
			fmt.Fprintf(, "%q", )
		case protowire.StartGroupType:
			.WriteByte('{')
			.indent++
		default:
			fmt.Fprintf(, "/* unknown wire type %d */", )
		}
		.WriteByte('\n')
	}
}

// writeExtensions writes all the extensions in m.
func ( *textWriter) ( protoreflect.Message) error {
	 := .Descriptor()
	if .ExtensionRanges().Len() == 0 {
		return nil
	}

	type  struct {
		 protoreflect.FieldDescriptor
		  protoreflect.Value
	}
	var  []
	.Range(func( protoreflect.FieldDescriptor,  protoreflect.Value) bool {
		if .IsExtension() {
			 = append(, {, })
		}
		return true
	})
	sort.Slice(, func(,  int) bool {
		return []..Number() < []..Number()
	})

	for ,  := range  {
		// For message set, use the name of the message as the extension name.
		 := string(..FullName())
		if isMessageSet(..ContainingMessage()) {
			 = strings.TrimSuffix(, ".message_set_extension")
		}

		if !..IsList() {
			if  := .writeSingularExtension(, ., .);  != nil {
				return 
			}
		} else {
			 := ..List()
			for  := 0;  < .Len(); ++ {
				if  := .writeSingularExtension(, .Get(), .);  != nil {
					return 
				}
			}
		}
	}
	return nil
}

func ( *textWriter) ( string,  protoreflect.Value,  protoreflect.FieldDescriptor) error {
	fmt.Fprintf(, "[%s]:", )
	if !.compact {
		.WriteByte(' ')
	}
	if  := .writeSingularValue(, );  != nil {
		return 
	}
	.WriteByte('\n')
	return nil
}

func ( *textWriter) () {
	if !.complete {
		return
	}
	for  := 0;  < .indent*2; ++ {
		.buf = append(.buf, ' ')
	}
	.complete = false
}