package pgtype

import (
	
	
	
	
	
	

	
)

type PathScanner interface {
	ScanPath(v Path) error
}

type PathValuer interface {
	PathValue() (Path, error)
}

type Path struct {
	P      []Vec2
	Closed bool
	Valid  bool
}

func ( *Path) ( Path) error {
	* = 
	return nil
}

func ( Path) () (Path, error) {
	return , nil
}

// Scan implements the database/sql Scanner interface.
func ( *Path) ( any) error {
	if  == nil {
		* = Path{}
		return nil
	}

	switch src := .(type) {
	case string:
		return scanPlanTextAnyToPathScanner{}.Scan([]byte(), )
	}

	return fmt.Errorf("cannot scan %T", )
}

// Value implements the database/sql/driver Valuer interface.
func ( Path) () (driver.Value, error) {
	if !.Valid {
		return nil, nil
	}

	,  := PathCodec{}.PlanEncode(nil, 0, TextFormatCode, ).Encode(, nil)
	if  != nil {
		return nil, 
	}

	return string(), 
}

type PathCodec struct{}

func (PathCodec) ( int16) bool {
	return  == TextFormatCode ||  == BinaryFormatCode
}

func (PathCodec) () int16 {
	return BinaryFormatCode
}

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

	switch  {
	case BinaryFormatCode:
		return encodePlanPathCodecBinary{}
	case TextFormatCode:
		return encodePlanPathCodecText{}
	}

	return nil
}

type encodePlanPathCodecBinary struct{}

func (encodePlanPathCodecBinary) ( any,  []byte) ( []byte,  error) {
	,  := .(PathValuer).PathValue()
	if  != nil {
		return nil, 
	}

	if !.Valid {
		return nil, nil
	}

	var  byte
	if .Closed {
		 = 1
	}
	 = append(, )

	 = pgio.AppendInt32(, int32(len(.P)))

	for ,  := range .P {
		 = pgio.AppendUint64(, math.Float64bits(.X))
		 = pgio.AppendUint64(, math.Float64bits(.Y))
	}

	return , nil
}

type encodePlanPathCodecText struct{}

func (encodePlanPathCodecText) ( any,  []byte) ( []byte,  error) {
	,  := .(PathValuer).PathValue()
	if  != nil {
		return nil, 
	}

	if !.Valid {
		return nil, nil
	}

	var ,  byte
	if .Closed {
		 = '('
		 = ')'
	} else {
		 = '['
		 = ']'
	}
	 = append(, )

	for ,  := range .P {
		if  > 0 {
			 = append(, ',')
		}
		 = append(, fmt.Sprintf(`(%s,%s)`,
			strconv.FormatFloat(.X, 'f', -1, 64),
			strconv.FormatFloat(.Y, 'f', -1, 64),
		)...)
	}

	 = append(, )

	return , nil
}

func (PathCodec) ( *Map,  uint32,  int16,  any) ScanPlan {

	switch  {
	case BinaryFormatCode:
		switch .(type) {
		case PathScanner:
			return scanPlanBinaryPathToPathScanner{}
		}
	case TextFormatCode:
		switch .(type) {
		case PathScanner:
			return scanPlanTextAnyToPathScanner{}
		}
	}

	return nil
}

type scanPlanBinaryPathToPathScanner struct{}

func (scanPlanBinaryPathToPathScanner) ( []byte,  any) error {
	 := ().(PathScanner)

	if  == nil {
		return .ScanPath(Path{})
	}

	if len() < 5 {
		return fmt.Errorf("invalid length for Path: %v", len())
	}

	 := [0] == 1
	 := int(binary.BigEndian.Uint32([1:]))

	 := 5

	if 5+*16 != len() {
		return fmt.Errorf("invalid length for Path with %d points: %v", , len())
	}

	 := make([]Vec2, )
	for  := 0;  < len(); ++ {
		 := binary.BigEndian.Uint64([:])
		 += 8
		 := binary.BigEndian.Uint64([:])
		 += 8
		[] = Vec2{math.Float64frombits(), math.Float64frombits()}
	}

	return .ScanPath(Path{
		P:      ,
		Closed: ,
		Valid:  true,
	})
}

type scanPlanTextAnyToPathScanner struct{}

func (scanPlanTextAnyToPathScanner) ( []byte,  any) error {
	 := ().(PathScanner)

	if  == nil {
		return .ScanPath(Path{})
	}

	if len() < 7 {
		return fmt.Errorf("invalid length for Path: %v", len())
	}

	 := [0] == '('
	 := make([]Vec2, 0)

	 := string([2:])

	for {
		 := strings.IndexByte(, ',')
		,  := strconv.ParseFloat([:], 64)
		if  != nil {
			return 
		}

		 = [+1:]
		 = strings.IndexByte(, ')')

		,  := strconv.ParseFloat([:], 64)
		if  != nil {
			return 
		}

		 = append(, Vec2{, })

		if +3 < len() {
			 = [+3:]
		} else {
			break
		}
	}

	return .ScanPath(Path{P: , Closed: , Valid: true})
}

func ( PathCodec) ( *Map,  uint32,  int16,  []byte) (driver.Value, error) {
	return codecDecodeToTextFormat(, , , , )
}

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

	var  Path
	 := codecScan(, , , , , &)
	if  != nil {
		return nil, 
	}
	return , nil
}