package pgtype

import (
	
	
	
	
	

	
)

// CompositeIndexGetter is a type accessed by index that can be converted into a PostgreSQL composite.
type CompositeIndexGetter interface {
	// IsNull returns true if the value is SQL NULL.
	IsNull() bool

	// Index returns the element at i.
	Index(i int) any
}

// CompositeIndexScanner is a type accessed by index that can be scanned from a PostgreSQL composite.
type CompositeIndexScanner interface {
	// ScanNull sets the value to SQL NULL.
	ScanNull() error

	// ScanIndex returns a value usable as a scan target for i.
	ScanIndex(i int) any
}

type CompositeCodecField struct {
	Name string
	Type *Type
}

type CompositeCodec struct {
	Fields []CompositeCodecField
}

func ( *CompositeCodec) ( int16) bool {
	for ,  := range .Fields {
		if !.Type.Codec.FormatSupported() {
			return false
		}
	}

	return true
}

func ( *CompositeCodec) () int16 {
	if .FormatSupported(BinaryFormatCode) {
		return BinaryFormatCode
	}
	return TextFormatCode
}

func ( *CompositeCodec) ( *Map,  uint32,  int16,  any) EncodePlan {
	if ,  := .(CompositeIndexGetter); ! {
		return nil
	}

	switch  {
	case BinaryFormatCode:
		return &encodePlanCompositeCodecCompositeIndexGetterToBinary{cc: , m: }
	case TextFormatCode:
		return &encodePlanCompositeCodecCompositeIndexGetterToText{cc: , m: }
	}

	return nil
}

type encodePlanCompositeCodecCompositeIndexGetterToBinary struct {
	cc *CompositeCodec
	m  *Map
}

func ( *encodePlanCompositeCodecCompositeIndexGetterToBinary) ( any,  []byte) ( []byte,  error) {
	 := .(CompositeIndexGetter)

	if .IsNull() {
		return nil, nil
	}

	 := NewCompositeBinaryBuilder(.m, )
	for ,  := range .cc.Fields {
		.AppendValue(.Type.OID, .Index())
	}

	return .Finish()
}

type encodePlanCompositeCodecCompositeIndexGetterToText struct {
	cc *CompositeCodec
	m  *Map
}

func ( *encodePlanCompositeCodecCompositeIndexGetterToText) ( any,  []byte) ( []byte,  error) {
	 := .(CompositeIndexGetter)

	if .IsNull() {
		return nil, nil
	}

	 := NewCompositeTextBuilder(.m, )
	for ,  := range .cc.Fields {
		.AppendValue(.Type.OID, .Index())
	}

	return .Finish()
}

func ( *CompositeCodec) ( *Map,  uint32,  int16,  any) ScanPlan {
	switch  {
	case BinaryFormatCode:
		switch .(type) {
		case CompositeIndexScanner:
			return &scanPlanBinaryCompositeToCompositeIndexScanner{cc: , m: }
		}
	case TextFormatCode:
		switch .(type) {
		case CompositeIndexScanner:
			return &scanPlanTextCompositeToCompositeIndexScanner{cc: , m: }
		}
	}

	return nil
}

type scanPlanBinaryCompositeToCompositeIndexScanner struct {
	cc *CompositeCodec
	m  *Map
}

func ( *scanPlanBinaryCompositeToCompositeIndexScanner) ( []byte,  any) error {
	 := ().(CompositeIndexScanner)

	if  == nil {
		return .ScanNull()
	}

	 := NewCompositeBinaryScanner(.m, )
	for ,  := range .cc.Fields {
		if .Next() {
			 := .ScanIndex()
			if  != nil {
				 := .m.PlanScan(.Type.OID, BinaryFormatCode, )
				if  == nil {
					return fmt.Errorf("unable to encode %v into OID %d in binary format", , .Type.OID)
				}

				 := .Scan(.Bytes(), )
				if  != nil {
					return 
				}
			}
		} else {
			return errors.New("read past end of composite")
		}
	}

	if  := .Err();  != nil {
		return 
	}

	return nil
}

type scanPlanTextCompositeToCompositeIndexScanner struct {
	cc *CompositeCodec
	m  *Map
}

func ( *scanPlanTextCompositeToCompositeIndexScanner) ( []byte,  any) error {
	 := ().(CompositeIndexScanner)

	if  == nil {
		return .ScanNull()
	}

	 := NewCompositeTextScanner(.m, )
	for ,  := range .cc.Fields {
		if .Next() {
			 := .ScanIndex()
			if  != nil {
				 := .m.PlanScan(.Type.OID, TextFormatCode, )
				if  == nil {
					return fmt.Errorf("unable to encode %v into OID %d in text format", , .Type.OID)
				}

				 := .Scan(.Bytes(), )
				if  != nil {
					return 
				}
			}
		} else {
			return errors.New("read past end of composite")
		}
	}

	if  := .Err();  != nil {
		return 
	}

	return nil
}

func ( *CompositeCodec) ( *Map,  uint32,  int16,  []byte) (driver.Value, error) {
	if  == nil {
		return nil, nil
	}

	switch  {
	case TextFormatCode:
		return string(), nil
	case BinaryFormatCode:
		 := make([]byte, len())
		copy(, )
		return , nil
	default:
		return nil, fmt.Errorf("unknown format code %d", )
	}
}

func ( *CompositeCodec) ( *Map,  uint32,  int16,  []byte) (any, error) {
	if  == nil {
		return nil, nil
	}

	switch  {
	case TextFormatCode:
		 := NewCompositeTextScanner(, )
		 := make(map[string]any, len(.Fields))
		for  := 0; .Next() &&  < len(.Fields); ++ {
			var  any
			 := .PlanScan(.Fields[].Type.OID, TextFormatCode, &)
			if  == nil {
				return nil, fmt.Errorf("unable to scan OID %d in text format into %v", .Fields[].Type.OID, )
			}

			 := .Scan(.Bytes(), &)
			if  != nil {
				return nil, 
			}

			[.Fields[].Name] = 
		}

		if  := .Err();  != nil {
			return nil, 
		}

		return , nil
	case BinaryFormatCode:
		 := NewCompositeBinaryScanner(, )
		 := make(map[string]any, len(.Fields))
		for  := 0; .Next() &&  < len(.Fields); ++ {
			var  any
			 := .PlanScan(.OID(), BinaryFormatCode, &)
			if  == nil {
				return nil, fmt.Errorf("unable to scan OID %d in binary format into %v", .OID(), )
			}

			 := .Scan(.Bytes(), &)
			if  != nil {
				return nil, 
			}

			[.Fields[].Name] = 
		}

		if  := .Err();  != nil {
			return nil, 
		}

		return , nil
	default:
		return nil, fmt.Errorf("unknown format code %d", )
	}

}

type CompositeBinaryScanner struct {
	m   *Map
	rp  int
	src []byte

	fieldCount int32
	fieldBytes []byte
	fieldOID   uint32
	err        error
}

// NewCompositeBinaryScanner a scanner over a binary encoded composite balue.
func ( *Map,  []byte) *CompositeBinaryScanner {
	 := 0
	if len([:]) < 4 {
		return &CompositeBinaryScanner{err: fmt.Errorf("Record incomplete %v", )}
	}

	 := int32(binary.BigEndian.Uint32([:]))
	 += 4

	return &CompositeBinaryScanner{
		m:          ,
		rp:         ,
		src:        ,
		fieldCount: ,
	}
}

// Next advances the scanner to the next field. It returns false after the last field is read or an error occurs. After
// Next returns false, the Err method can be called to check if any errors occurred.
func ( *CompositeBinaryScanner) () bool {
	if .err != nil {
		return false
	}

	if .rp == len(.src) {
		return false
	}

	if len(.src[.rp:]) < 8 {
		.err = fmt.Errorf("Record incomplete %v", .src)
		return false
	}
	.fieldOID = binary.BigEndian.Uint32(.src[.rp:])
	.rp += 4

	 := int(int32(binary.BigEndian.Uint32(.src[.rp:])))
	.rp += 4

	if  >= 0 {
		if len(.src[.rp:]) <  {
			.err = fmt.Errorf("Record incomplete rp=%d src=%v", .rp, .src)
			return false
		}
		.fieldBytes = .src[.rp : .rp+]
		.rp += 
	} else {
		.fieldBytes = nil
	}

	return true
}

func ( *CompositeBinaryScanner) () int {
	return int(.fieldCount)
}

// Bytes returns the bytes of the field most recently read by Scan().
func ( *CompositeBinaryScanner) () []byte {
	return .fieldBytes
}

// OID returns the OID of the field most recently read by Scan().
func ( *CompositeBinaryScanner) () uint32 {
	return .fieldOID
}

// Err returns any error encountered by the scanner.
func ( *CompositeBinaryScanner) () error {
	return .err
}

type CompositeTextScanner struct {
	m   *Map
	rp  int
	src []byte

	fieldBytes []byte
	err        error
}

// NewCompositeTextScanner a scanner over a text encoded composite value.
func ( *Map,  []byte) *CompositeTextScanner {
	if len() < 2 {
		return &CompositeTextScanner{err: fmt.Errorf("Record incomplete %v", )}
	}

	if [0] != '(' {
		return &CompositeTextScanner{err: fmt.Errorf("composite text format must start with '('")}
	}

	if [len()-1] != ')' {
		return &CompositeTextScanner{err: fmt.Errorf("composite text format must end with ')'")}
	}

	return &CompositeTextScanner{
		m:   ,
		rp:  1,
		src: ,
	}
}

// Next advances the scanner to the next field. It returns false after the last field is read or an error occurs. After
// Next returns false, the Err method can be called to check if any errors occurred.
func ( *CompositeTextScanner) () bool {
	if .err != nil {
		return false
	}

	if .rp == len(.src) {
		return false
	}

	switch .src[.rp] {
	case ',', ')': // null
		.rp++
		.fieldBytes = nil
		return true
	case '"': // quoted value
		.rp++
		.fieldBytes = make([]byte, 0, 16)
		for {
			 := .src[.rp]

			if  == '"' {
				.rp++
				if .src[.rp] == '"' {
					.fieldBytes = append(.fieldBytes, '"')
					.rp++
				} else {
					break
				}
			} else if  == '\\' {
				.rp++
				.fieldBytes = append(.fieldBytes, .src[.rp])
				.rp++
			} else {
				.fieldBytes = append(.fieldBytes, )
				.rp++
			}
		}
		.rp++
		return true
	default: // unquoted value
		 := .rp
		for {
			 := .src[.rp]
			if  == ',' ||  == ')' {
				break
			}
			.rp++
		}
		.fieldBytes = .src[:.rp]
		.rp++
		return true
	}
}

// Bytes returns the bytes of the field most recently read by Scan().
func ( *CompositeTextScanner) () []byte {
	return .fieldBytes
}

// Err returns any error encountered by the scanner.
func ( *CompositeTextScanner) () error {
	return .err
}

type CompositeBinaryBuilder struct {
	m          *Map
	buf        []byte
	startIdx   int
	fieldCount uint32
	err        error
}

func ( *Map,  []byte) *CompositeBinaryBuilder {
	 := len()
	 = append(, 0, 0, 0, 0) // allocate room for number of fields
	return &CompositeBinaryBuilder{m: , buf: , startIdx: }
}

func ( *CompositeBinaryBuilder) ( uint32,  any) {
	if .err != nil {
		return
	}

	if  == nil {
		.buf = pgio.AppendUint32(.buf, )
		.buf = pgio.AppendInt32(.buf, -1)
		.fieldCount++
		return
	}

	 := .m.PlanEncode(, BinaryFormatCode, )
	if  == nil {
		.err = fmt.Errorf("unable to encode %v into OID %d in binary format", , )
		return
	}

	.buf = pgio.AppendUint32(.buf, )
	 := len(.buf)
	.buf = pgio.AppendInt32(.buf, -1)
	,  := .Encode(, .buf)
	if  != nil {
		.err = 
		return
	}
	if  != nil {
		binary.BigEndian.PutUint32([:], uint32(len()-len(.buf)))
		.buf = 
	}

	.fieldCount++
}

func ( *CompositeBinaryBuilder) () ([]byte, error) {
	if .err != nil {
		return nil, .err
	}

	binary.BigEndian.PutUint32(.buf[.startIdx:], .fieldCount)
	return .buf, nil
}

type CompositeTextBuilder struct {
	m          *Map
	buf        []byte
	startIdx   int
	fieldCount uint32
	err        error
	fieldBuf   [32]byte
}

func ( *Map,  []byte) *CompositeTextBuilder {
	 = append(, '(') // allocate room for number of fields
	return &CompositeTextBuilder{m: , buf: }
}

func ( *CompositeTextBuilder) ( uint32,  any) {
	if .err != nil {
		return
	}

	if  == nil {
		.buf = append(.buf, ',')
		return
	}

	 := .m.PlanEncode(, TextFormatCode, )
	if  == nil {
		.err = fmt.Errorf("unable to encode %v into OID %d in text format", , )
		return
	}

	,  := .Encode(, .fieldBuf[0:0])
	if  != nil {
		.err = 
		return
	}
	if  != nil {
		.buf = append(.buf, quoteCompositeFieldIfNeeded(string())...)
	}

	.buf = append(.buf, ',')
}

func ( *CompositeTextBuilder) () ([]byte, error) {
	if .err != nil {
		return nil, .err
	}

	.buf[len(.buf)-1] = ')'
	return .buf, nil
}

var quoteCompositeReplacer = strings.NewReplacer(`\`, `\\`, `"`, `\"`)

func quoteCompositeField( string) string {
	return `"` + quoteCompositeReplacer.Replace() + `"`
}

func quoteCompositeFieldIfNeeded( string) string {
	if  == "" || [0] == ' ' || [len()-1] == ' ' || strings.ContainsAny(, `(),"\`) {
		return quoteCompositeField()
	}
	return 
}

// CompositeFields represents the values of a composite value. It can be used as an encoding source or as a scan target.
// It cannot scan a NULL, but the composite fields can be NULL.
type CompositeFields []any

func ( CompositeFields) () {}

func ( CompositeFields) () bool {
	return  == nil
}

func ( CompositeFields) ( int) any {
	return []
}

func ( CompositeFields) () error {
	return fmt.Errorf("cannot scan NULL into CompositeFields")
}

func ( CompositeFields) ( int) any {
	return []
}