package pgproto3

import (
	
	
	
	
	

	
)

type Bind struct {
	DestinationPortal    string
	PreparedStatement    string
	ParameterFormatCodes []int16
	Parameters           [][]byte
	ResultFormatCodes    []int16
}

// Frontend identifies this message as sendable by a PostgreSQL frontend.
func (*Bind) () {}

// 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 ( *Bind) ( []byte) error {
	* = Bind{}

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

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

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

	if  > 0 {
		.ParameterFormatCodes = make([]int16, )

		if len([:]) < len(.ParameterFormatCodes)*2 {
			return &invalidMessageFormatErr{messageType: "Bind"}
		}
		for  := 0;  < ; ++ {
			.ParameterFormatCodes[] = int16(binary.BigEndian.Uint16([:]))
			 += 2
		}
	}

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

	if  > 0 {
		.Parameters = make([][]byte, )

		for  := 0;  < ; ++ {
			if len([:]) < 4 {
				return &invalidMessageFormatErr{messageType: "Bind"}
			}

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

			// null
			if  == -1 {
				continue
			}

			if len([:]) <  {
				return &invalidMessageFormatErr{messageType: "Bind"}
			}

			.Parameters[] = [ : +]
			 += 
		}
	}

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

	.ResultFormatCodes = make([]int16, )
	if len([:]) < len(.ResultFormatCodes)*2 {
		return &invalidMessageFormatErr{messageType: "Bind"}
	}
	for  := 0;  < ; ++ {
		.ResultFormatCodes[] = int16(binary.BigEndian.Uint16([:]))
		 += 2
	}

	return nil
}

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

	 = append(, .DestinationPortal...)
	 = append(, 0)
	 = append(, .PreparedStatement...)
	 = append(, 0)

	 = pgio.AppendUint16(, uint16(len(.ParameterFormatCodes)))
	for ,  := range .ParameterFormatCodes {
		 = pgio.AppendInt16(, )
	}

	 = pgio.AppendUint16(, uint16(len(.Parameters)))
	for ,  := range .Parameters {
		if  == nil {
			 = pgio.AppendInt32(, -1)
			continue
		}

		 = pgio.AppendInt32(, int32(len()))
		 = append(, ...)
	}

	 = pgio.AppendUint16(, uint16(len(.ResultFormatCodes)))
	for ,  := range .ResultFormatCodes {
		 = pgio.AppendInt16(, )
	}

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

	return 
}

// MarshalJSON implements encoding/json.Marshaler.
func ( Bind) () ([]byte, error) {
	 := make([]map[string]string, len(.Parameters))
	for ,  := range .Parameters {
		if  == nil {
			continue
		}

		 := true
		if len(.ParameterFormatCodes) == 1 {
			 = .ParameterFormatCodes[0] == 0
		} else if len(.ParameterFormatCodes) > 1 {
			 = .ParameterFormatCodes[] == 0
		}

		if  {
			[] = map[string]string{"text": string()}
		} else {
			[] = map[string]string{"binary": hex.EncodeToString()}
		}
	}

	return json.Marshal(struct {
		                 string
		    string
		    string
		 []int16
		           []map[string]string
		    []int16
	}{
		:                 "Bind",
		:    .DestinationPortal,
		:    .PreparedStatement,
		: .ParameterFormatCodes,
		:           ,
		:    .ResultFormatCodes,
	})
}

// UnmarshalJSON implements encoding/json.Unmarshaler.
func ( *Bind) ( []byte) error {
	// Ignore null, like in the main JSON package.
	if string() == "null" {
		return nil
	}

	var  struct {
		    string
		    string
		 []int16
		           []map[string]string
		    []int16
	}
	 := json.Unmarshal(, &)
	if  != nil {
		return 
	}
	.DestinationPortal = .
	.PreparedStatement = .
	.ParameterFormatCodes = .
	.Parameters = make([][]byte, len(.))
	.ResultFormatCodes = .
	for ,  := range . {
		.Parameters[],  = getValueFromJSON()
		if  != nil {
			return fmt.Errorf("cannot get param %d: %w", , )
		}
	}
	return nil
}