package pgproto3

import (
	
	
	

	
)

const (
	TextFormat   = 0
	BinaryFormat = 1
)

type FieldDescription struct {
	Name                 []byte
	TableOID             uint32
	TableAttributeNumber uint16
	DataTypeOID          uint32
	DataTypeSize         int16
	TypeModifier         int32
	Format               int16
}

// MarshalJSON implements encoding/json.Marshaler.
func ( FieldDescription) () ([]byte, error) {
	return json.Marshal(struct {
		                 string
		             uint32
		 uint16
		          uint32
		         int16
		         int32
		               int16
	}{
		:                 string(.Name),
		:             .TableOID,
		: .TableAttributeNumber,
		:          .DataTypeOID,
		:         .DataTypeSize,
		:         .TypeModifier,
		:               .Format,
	})
}

type RowDescription struct {
	Fields []FieldDescription
}

// Backend identifies this message as sendable by the PostgreSQL backend.
func (*RowDescription) () {}

// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
// type identifier and 4 byte message length.
func ( *RowDescription) ( []byte) error {

	if len() < 2 {
		return &invalidMessageFormatErr{messageType: "RowDescription"}
	}
	 := int(binary.BigEndian.Uint16())
	 := 2

	.Fields = .Fields[0:0]

	for  := 0;  < ; ++ {
		var  FieldDescription

		 := bytes.IndexByte([:], 0)
		if  < 0 {
			return &invalidMessageFormatErr{messageType: "RowDescription"}
		}
		.Name = [ : +]
		 +=  + 1

		// Since buf.Next() doesn't return an error if we hit the end of the buffer
		// check Len ahead of time
		if len([:]) < 18 {
			return &invalidMessageFormatErr{messageType: "RowDescription"}
		}

		.TableOID = binary.BigEndian.Uint32([:])
		 += 4
		.TableAttributeNumber = binary.BigEndian.Uint16([:])
		 += 2
		.DataTypeOID = binary.BigEndian.Uint32([:])
		 += 4
		.DataTypeSize = int16(binary.BigEndian.Uint16([:]))
		 += 2
		.TypeModifier = int32(binary.BigEndian.Uint32([:]))
		 += 4
		.Format = int16(binary.BigEndian.Uint16([:]))
		 += 2

		.Fields = append(.Fields, )
	}

	return nil
}

// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func ( *RowDescription) ( []byte) []byte {
	 = append(, 'T')
	 := len()
	 = pgio.AppendInt32(, -1)

	 = pgio.AppendUint16(, uint16(len(.Fields)))
	for ,  := range .Fields {
		 = append(, .Name...)
		 = append(, 0)

		 = pgio.AppendUint32(, .TableOID)
		 = pgio.AppendUint16(, .TableAttributeNumber)
		 = pgio.AppendUint32(, .DataTypeOID)
		 = pgio.AppendInt16(, .DataTypeSize)
		 = pgio.AppendInt32(, .TypeModifier)
		 = pgio.AppendInt16(, .Format)
	}

	pgio.SetInt32([:], int32(len([:])))

	return 
}

// MarshalJSON implements encoding/json.Marshaler.
func ( RowDescription) () ([]byte, error) {
	return json.Marshal(struct {
		   string
		 []FieldDescription
	}{
		:   "RowDescription",
		: .Fields,
	})
}

// UnmarshalJSON implements encoding/json.Unmarshaler.
func ( *RowDescription) ( []byte) error {
	var  struct {
		 []struct {
			                 string
			             uint32
			 uint16
			          uint32
			         int16
			         int32
			               int16
		}
	}
	if  := json.Unmarshal(, &);  != nil {
		return 
	}
	.Fields = make([]FieldDescription, len(.))
	for ,  := range . {
		.Fields[] = FieldDescription{
			Name:                 []byte(.),
			TableOID:             .,
			TableAttributeNumber: .,
			DataTypeOID:          .,
			DataTypeSize:         .,
			TypeModifier:         .,
			Format:               .,
		}
	}
	return nil
}