package pgdialect

import (
	
	
	
	
	
	

	
	
)

var (
	driverValuerType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()

	stringType      = reflect.TypeOf((*string)(nil)).Elem()
	sliceStringType = reflect.TypeOf([]string(nil))

	intType      = reflect.TypeOf((*int)(nil)).Elem()
	sliceIntType = reflect.TypeOf([]int(nil))

	int64Type      = reflect.TypeOf((*int64)(nil)).Elem()
	sliceInt64Type = reflect.TypeOf([]int64(nil))

	float64Type      = reflect.TypeOf((*float64)(nil)).Elem()
	sliceFloat64Type = reflect.TypeOf([]float64(nil))
)

func ( reflect.Type) schema.AppenderFunc {
	switch .Kind() {
	case reflect.Uint32:
		return appendUint32ValueAsInt
	case reflect.Uint, reflect.Uint64:
		return appendUint64ValueAsInt
	}
	return nil
}

func ( schema.Formatter,  []byte,  reflect.Value) []byte {
	return strconv.AppendInt(, int64(int32(.Uint())), 10)
}

func ( schema.Formatter,  []byte,  reflect.Value) []byte {
	return strconv.AppendInt(, int64(.Uint()), 10)
}

//------------------------------------------------------------------------------

func ( schema.Formatter,  []byte,  interface{}) []byte {
	switch v := .(type) {
	case int64:
		return strconv.AppendInt(, , 10)
	case float64:
		return dialect.AppendFloat64(, )
	case bool:
		return dialect.AppendBool(, )
	case []byte:
		return dialect.AppendBytes(, )
	case string:
		return arrayAppendString(, )
	case time.Time:
		return dialect.AppendTime(, )
	default:
		 := fmt.Errorf("pgdialect: can't append %T", )
		return dialect.AppendError(, )
	}
}

func ( reflect.Type) schema.AppenderFunc {
	if .Kind() == reflect.String {
		return arrayAppendStringValue
	}
	if .Implements(driverValuerType) {
		return arrayAppendDriverValue
	}
	return schema.Appender(, customAppender)
}

func ( schema.Formatter,  []byte,  reflect.Value) []byte {
	return arrayAppendString(, .String())
}

func ( schema.Formatter,  []byte,  reflect.Value) []byte {
	,  := .Interface().(driver.Valuer).Value()
	if  != nil {
		return dialect.AppendError(, )
	}
	return arrayAppend(, , )
}

//------------------------------------------------------------------------------

func ( reflect.Type) schema.AppenderFunc {
	 := .Kind()

	switch  {
	case reflect.Ptr:
		if  := (.Elem());  != nil {
			return schema.PtrAppender()
		}
	case reflect.Slice, reflect.Array:
		// ok:
	default:
		return nil
	}

	 := .Elem()

	if  == reflect.Slice {
		switch  {
		case stringType:
			return appendStringSliceValue
		case intType:
			return appendIntSliceValue
		case int64Type:
			return appendInt64SliceValue
		case float64Type:
			return appendFloat64SliceValue
		}
	}

	 := arrayElemAppender()
	if  == nil {
		panic(fmt.Errorf("pgdialect: %s is not supported", ))
	}

	return func( schema.Formatter,  []byte,  reflect.Value) []byte {
		 := .Kind()
		switch  {
		case reflect.Ptr, reflect.Slice:
			if .IsNil() {
				return dialect.AppendNull()
			}
		}

		if  == reflect.Ptr {
			 = .Elem()
		}

		 = append(, '\'')

		 = append(, '{')
		for  := 0;  < .Len(); ++ {
			 := .Index()
			 = (, , )
			 = append(, ',')
		}
		if .Len() > 0 {
			[len()-1] = '}' // Replace trailing comma.
		} else {
			 = append(, '}')
		}

		 = append(, '\'')

		return 
	}
}

func ( schema.Formatter,  []byte,  reflect.Value) []byte {
	 := .Convert(sliceStringType).Interface().([]string)
	return appendStringSlice(, )
}

func ( []byte,  []string) []byte {
	if  == nil {
		return dialect.AppendNull()
	}

	 = append(, '\'')

	 = append(, '{')
	for ,  := range  {
		 = arrayAppendString(, )
		 = append(, ',')
	}
	if len() > 0 {
		[len()-1] = '}' // Replace trailing comma.
	} else {
		 = append(, '}')
	}

	 = append(, '\'')

	return 
}

func ( schema.Formatter,  []byte,  reflect.Value) []byte {
	 := .Convert(sliceIntType).Interface().([]int)
	return appendIntSlice(, )
}

func ( []byte,  []int) []byte {
	if  == nil {
		return dialect.AppendNull()
	}

	 = append(, '\'')

	 = append(, '{')
	for ,  := range  {
		 = strconv.AppendInt(, int64(), 10)
		 = append(, ',')
	}
	if len() > 0 {
		[len()-1] = '}' // Replace trailing comma.
	} else {
		 = append(, '}')
	}

	 = append(, '\'')

	return 
}

func ( schema.Formatter,  []byte,  reflect.Value) []byte {
	 := .Convert(sliceInt64Type).Interface().([]int64)
	return appendInt64Slice(, )
}

func ( []byte,  []int64) []byte {
	if  == nil {
		return dialect.AppendNull()
	}

	 = append(, '\'')

	 = append(, '{')
	for ,  := range  {
		 = strconv.AppendInt(, , 10)
		 = append(, ',')
	}
	if len() > 0 {
		[len()-1] = '}' // Replace trailing comma.
	} else {
		 = append(, '}')
	}

	 = append(, '\'')

	return 
}

func ( schema.Formatter,  []byte,  reflect.Value) []byte {
	 := .Convert(sliceFloat64Type).Interface().([]float64)
	return appendFloat64Slice(, )
}

func ( []byte,  []float64) []byte {
	if  == nil {
		return dialect.AppendNull()
	}

	 = append(, '\'')

	 = append(, '{')
	for ,  := range  {
		 = dialect.AppendFloat64(, )
		 = append(, ',')
	}
	if len() > 0 {
		[len()-1] = '}' // Replace trailing comma.
	} else {
		 = append(, '}')
	}

	 = append(, '\'')

	return 
}

//------------------------------------------------------------------------------

func ( []byte,  string) []byte {
	 = append(, '"')
	for ,  := range  {
		switch  {
		case 0:
			// ignore
		case '\'':
			 = append(, "'''"...)
		case '"':
			 = append(, '\\', '"')
		case '\\':
			 = append(, '\\', '\\')
		default:
			if  < utf8.RuneSelf {
				 = append(, byte())
				break
			}
			 := len()
			if cap()- < utf8.UTFMax {
				 = append(, make([]byte, utf8.UTFMax)...)
			}
			 := utf8.EncodeRune([:+utf8.UTFMax], )
			 = [:+]
		}
	}
	 = append(, '"')
	return 
}