package arg

import (
	
	
	
	
	

	scalar 
)

var textUnmarshalerType = reflect.TypeOf([]encoding.TextUnmarshaler{}).Elem()

// cardinality tracks how many tokens are expected for a given spec
//   - zero is a boolean, which does to expect any value
//   - one is an ordinary option that will be parsed from a single token
//   - multiple is a slice or map that can accept zero or more tokens
type cardinality int

const (
	zero cardinality = iota
	one
	multiple
	unsupported
)

func ( cardinality) () string {
	switch  {
	case zero:
		return "zero"
	case one:
		return "one"
	case multiple:
		return "multiple"
	case unsupported:
		return "unsupported"
	default:
		return fmt.Sprintf("unknown(%d)", int())
	}
}

// cardinalityOf returns true if the type can be parsed from a string
func cardinalityOf( reflect.Type) (cardinality, error) {
	if scalar.CanParse() {
		if isBoolean() {
			return zero, nil
		}
		return one, nil
	}

	// look inside pointer types
	if .Kind() == reflect.Ptr {
		 = .Elem()
	}

	// look inside slice and map types
	switch .Kind() {
	case reflect.Slice:
		if !scalar.CanParse(.Elem()) {
			return unsupported, fmt.Errorf("cannot parse into %v because %v not supported", , .Elem())
		}
		return multiple, nil
	case reflect.Map:
		if !scalar.CanParse(.Key()) {
			return unsupported, fmt.Errorf("cannot parse into %v because key type %v not supported", , .Elem())
		}
		if !scalar.CanParse(.Elem()) {
			return unsupported, fmt.Errorf("cannot parse into %v because value type %v not supported", , .Elem())
		}
		return multiple, nil
	default:
		return unsupported, fmt.Errorf("cannot parse into %v", )
	}
}

// isBoolean returns true if the type is a boolean or a pointer to a boolean
func isBoolean( reflect.Type) bool {
	switch {
	case isTextUnmarshaler():
		return false
	case .Kind() == reflect.Bool:
		return true
	case .Kind() == reflect.Ptr && .Elem().Kind() == reflect.Bool:
		return true
	default:
		return false
	}
}

// isTextUnmarshaler returns true if the type or its pointer implements encoding.TextUnmarshaler
func isTextUnmarshaler( reflect.Type) bool {
	return .Implements(textUnmarshalerType) || reflect.PtrTo().Implements(textUnmarshalerType)
}

// isExported returns true if the struct field name is exported
func isExported( string) bool {
	,  := utf8.DecodeRuneInString() // returns RuneError for empty string or invalid UTF8
	return unicode.IsLetter() && unicode.IsUpper()
}

// isZero returns true if v contains the zero value for its type
func isZero( reflect.Value) bool {
	 := .Type()
	if .Kind() == reflect.Ptr || .Kind() == reflect.Slice || .Kind() == reflect.Map || .Kind() == reflect.Chan || .Kind() == reflect.Interface {
		return .IsNil()
	}
	if !.Comparable() {
		return false
	}
	return .Interface() == reflect.Zero().Interface()
}