package validate

import "reflect"

var (
	// global validators. contains built-in and user custom
	validators map[string]int8
	// global validators func meta information
	validatorMetas map[string]*funcMeta
)

// init: register all built-in validators
func init() {
	validators = make(map[string]int8)
	validatorMetas = make(map[string]*funcMeta)

	for n, fv := range validatorValues {
		validators[n] = validatorTypeBuiltin
		validatorMetas[n] = newFuncMeta(n, true, fv)
	}
}

// some commonly validation rule names.
const (
	RuleRequired = "required"
	RuleOptional = "optional"

	RuleDefault = "default"
	RuleRegexp  = "regexp"
	// RuleSafe means skip validate this field
	RuleSafe  = "safe"
	RuleSafe1 = "-"
)

// validator func reflect.Value map
var validatorValues = map[string]reflect.Value{
	// int value
	"lt":  reflect.ValueOf(Lt),
	"gt":  reflect.ValueOf(Gt),
	"min": reflect.ValueOf(Min),
	"max": reflect.ValueOf(Max),
	// value check
	"enum":     reflect.ValueOf(Enum),
	"notIn":    reflect.ValueOf(NotIn),
	"between":  reflect.ValueOf(Between),
	"regexp":   reflect.ValueOf(Regexp),
	"isEqual":  reflect.ValueOf(IsEqual),
	"intEqual": reflect.ValueOf(IntEqual),
	"notEqual": reflect.ValueOf(NotEqual),
	// contains
	"contains":    reflect.ValueOf(Contains),
	"notContains": reflect.ValueOf(NotContains),
	// string contains
	"stringContains": reflect.ValueOf(StringContains),
	"startsWith":     reflect.ValueOf(StartsWith),
	"endsWith":       reflect.ValueOf(EndsWith),
	// data type check
	"isInt":     reflect.ValueOf(IsInt),
	"isMap":     reflect.ValueOf(IsMap),
	"isUint":    reflect.ValueOf(IsUint),
	"isBool":    reflect.ValueOf(IsBool),
	"isFloat":   reflect.ValueOf(IsFloat),
	"isInts":    reflect.ValueOf(IsInts),
	"isArray":   reflect.ValueOf(IsArray),
	"isSlice":   reflect.ValueOf(IsSlice),
	"isString":  reflect.ValueOf(IsString),
	"isStrings": reflect.ValueOf(IsStrings),
	// length
	"length":       reflect.ValueOf(Length),
	"minLength":    reflect.ValueOf(MinLength),
	"maxLength":    reflect.ValueOf(MaxLength),
	"stringLength": reflect.ValueOf(StringLength),
	// string
	"isIntString": reflect.ValueOf(IsIntString),
	// ip
	"isIP":        reflect.ValueOf(IsIP),
	"isIPv4":      reflect.ValueOf(IsIPv4),
	"isIPv6":      reflect.ValueOf(IsIPv6),
	"isEmail":     reflect.ValueOf(IsEmail),
	"isASCII":     reflect.ValueOf(IsASCII),
	"isAlpha":     reflect.ValueOf(IsAlpha),
	"isAlphaNum":  reflect.ValueOf(IsAlphaNum),
	"isAlphaDash": reflect.ValueOf(IsAlphaDash),
	"isBase64":    reflect.ValueOf(IsBase64),
	"isCIDR":      reflect.ValueOf(IsCIDR),
	"isCIDRv4":    reflect.ValueOf(IsCIDRv4),
	"isCIDRv6":    reflect.ValueOf(IsCIDRv6),
	"isDNSName":   reflect.ValueOf(IsDNSName),
	"isDataURI":   reflect.ValueOf(IsDataURI),
	"isEmpty":     reflect.ValueOf(IsEmpty),
	"isHexColor":  reflect.ValueOf(IsHexColor),
	"isISBN10":    reflect.ValueOf(IsISBN10),
	"isISBN13":    reflect.ValueOf(IsISBN13),
	"isJSON":      reflect.ValueOf(IsJSON),
	"isLatitude":  reflect.ValueOf(IsLatitude),
	"isLongitude": reflect.ValueOf(IsLongitude),
	"isMAC":       reflect.ValueOf(IsMAC),
	"isMultiByte": reflect.ValueOf(IsMultiByte),
	"isNumber":    reflect.ValueOf(IsNumber),
	"isNumeric":   reflect.ValueOf(IsNumeric),
	"isCnMobile":  reflect.ValueOf(IsCnMobile),
	// ---
	"isStringNumber":   reflect.ValueOf(IsStringNumber),
	"hasWhitespace":    reflect.ValueOf(HasWhitespace),
	"isHexadecimal":    reflect.ValueOf(IsHexadecimal),
	"isPrintableASCII": reflect.ValueOf(IsPrintableASCII),
	// ---
	"isRGBColor":  reflect.ValueOf(IsRGBColor),
	"isURL":       reflect.ValueOf(IsURL),
	"isFullURL":   reflect.ValueOf(IsFullURL),
	"isActiveURL": reflect.ValueOf(IsActiveURL),
	"isUUID":      reflect.ValueOf(IsUUID),
	"isUUID3":     reflect.ValueOf(IsUUID3),
	"isUUID4":     reflect.ValueOf(IsUUID4),
	"isUUID5":     reflect.ValueOf(IsUUID5),
	// file system
	"pathExists": reflect.ValueOf(PathExists),
	"isDirPath":  reflect.ValueOf(IsDirPath),
	"isFilePath": reflect.ValueOf(IsFilePath),
	"isUnixPath": reflect.ValueOf(IsUnixPath),
	"isWinPath":  reflect.ValueOf(IsWinPath),
	// date check
	"isDate":     reflect.ValueOf(IsDate),
	"afterDate":  reflect.ValueOf(AfterDate),
	"beforeDate": reflect.ValueOf(BeforeDate),
	// ---
	"afterOrEqualDate":  reflect.ValueOf(AfterOrEqualDate),
	"beforeOrEqualDate": reflect.ValueOf(BeforeOrEqualDate),
}

// define validator alias name mapping
var validatorAliases = map[string]string{
	// alias -> real name
	"in":     "enum",
	"oneof":  "enum",
	"not_in": "notIn",
	"range":  "between",
	// type
	"int":       "isInt",
	"integer":   "isInt",
	"uint":      "isUint",
	"bool":      "isBool",
	"boolean":   "isBool",
	"float":     "isFloat",
	"map":       "isMap",
	"ints":      "isInts", // []int
	"int_slice": "isInts",
	"int_list":  "isInts",
	"str":       "isString",
	"string":    "isString",
	"strings":   "isStrings", // []string
	"str_list":  "isStrings",
	"str_slice": "isStrings",
	"arr":       "isArray",
	"list":      "isArray",
	"array":     "isArray",
	"slice":     "isSlice",
	// val
	"regex":  "regexp",
	"eq":     "isEqual",
	"equal":  "isEqual",
	"equals": "isEqual",
	"intEq":  "intEqual",
	"int_eq": "intEqual",
	"ne":     "notEqual",
	"notEq":  "notEqual",
	"not_eq": "notEqual",
	// int compare
	"lte":          "max",
	"gte":          "min",
	"lessThan":     "lt",
	"less_than":    "lt",
	"greaterThan":  "gt",
	"greater_than": "gt",
	// len
	"len":        "length",
	"leneq":      "length",
	"lenEq":      "length",
	"len_eq":     "length",
	"lengthEq":   "length",
	"length_eq":  "length",
	"minlen":     "minLength",
	"minLen":     "minLength",
	"min_len":    "minLength",
	"min_length": "minLength",
	"maxlen":     "maxLength",
	"maxLen":     "maxLength",
	"max_len":    "maxLength",
	"max_length": "maxLength",
	"minsize":    "minLength",
	"minSize":    "minLength",
	"min_size":   "minLength",
	"maxsize":    "maxLength",
	"maxSize":    "maxLength",
	"max_size":   "maxLength",
	// string rune length
	"strlen":      "stringLength",
	"strLen":      "stringLength",
	"str_len":     "stringLength",
	"strLength":   "stringLength",
	"str_length":  "stringLength",
	"runeLen":     "stringLength",
	"rune_len":    "stringLength",
	"runeLength":  "stringLength",
	"rune_length": "stringLength",
	// string contains
	"string_contains": "stringContains",
	"str_contains":    "stringContains",
	"startWith":       "startsWith",
	"startwith":       "startsWith",
	"start_with":      "startsWith",
	"starts_with":     "startsWith",
	"endwith":         "endsWith",
	"endWith":         "endsWith",
	"end_with":        "endsWith",
	"endswith":        "endsWith",
	"ends_with":       "endsWith",
	// string
	"ip":         "isIP",
	"IP":         "isIP",
	"ipv4":       "isIPv4",
	"IPv4":       "isIPv4",
	"ipv6":       "isIPv6",
	"IPv6":       "isIPv6",
	"email":      "isEmail",
	"intStr":     "isIntString",
	"int_str":    "isIntString",
	"strint":     "isIntString",
	"strInt":     "isIntString",
	"str_int":    "isIntString",
	"intstr":     "isIntString",
	"intString":  "isIntString",
	"int_string": "isIntString",
	// ---
	"stringNum":       "isStringNumber",
	"string_num":      "isStringNumber",
	"strNumber":       "isStringNumber",
	"str_number":      "isStringNumber",
	"strnum":          "isStringNumber",
	"strNum":          "isStringNumber",
	"str_num":         "isStringNumber",
	"stringNumber":    "isStringNumber",
	"string_number":   "isStringNumber",
	"hexadecimal":     "isHexadecimal",
	"hasWhitespace":   "hasWhitespace",
	"has_whitespace":  "hasWhitespace",
	"has_wp":          "hasWhitespace",
	"printableASCII":  "isPrintableASCII",
	"printable_ascii": "isPrintableASCII",
	"printable_ASCII": "isPrintableASCII",
	// ---
	"ascii":      "isASCII",
	"ASCII":      "isASCII",
	"alpha":      "isAlpha",
	"alphaNum":   "isAlphaNum",
	"alpha_num":  "isAlphaNum",
	"alphaDash":  "isAlphaDash",
	"alpha_dash": "isAlphaDash",
	"base64":     "isBase64",
	"cidr":       "isCIDR",
	"CIDR":       "isCIDR",
	"CIDRv4":     "isCIDRv4",
	"cidrv4":     "isCIDRv4",
	"cidr_v4":    "isCIDRv4",
	"cidrv6":     "isCIDRv6",
	"CIDRv6":     "isCIDRv6",
	"cidr_v6":    "isCIDRv6",
	"dnsname":    "isDNSName",
	"dnsName":    "isDNSName",
	"dns_name":   "isDNSName",
	"DNSName":    "isDNSName",
	"datauri":    "isDataURI",
	"dataURI":    "isDataURI",
	"data_URI":   "isDataURI",
	"data_uri":   "isDataURI",
	"empty":      "isEmpty",
	"HEXColor":   "isHexColor",
	"hexcolor":   "isHexColor",
	"hexColor":   "isHexColor",
	"hex_color":  "isHexColor",
	"isbn10":     "isISBN10",
	"ISBN10":     "isISBN10",
	"isbn13":     "isISBN13",
	"ISBN13":     "isISBN13",
	"json":       "isJSON",
	"Json":       "isJSON",
	"JSON":       "isJSON",
	"lat":        "isLatitude",
	"latitude":   "isLatitude",
	"lon":        "isLongitude",
	"longitude":  "isLongitude",
	"mac":        "isMAC",
	"MAC":        "isMAC",
	"multiByte":  "isMultiByte",
	"num":        "isNumber",
	"number":     "isNumber",
	"numeric":    "isNumeric",
	"rgbcolor":   "isRGBColor",
	"rgbColor":   "isRGBColor",
	"rgb_color":  "isRGBColor",
	"RGBColor":   "isRGBColor",
	"RGB_color":  "isRGBColor",
	"url":        "isURL",
	"URL":        "isURL",
	"fullURL":    "isFullURL",
	"fullUrl":    "isFullURL",
	"fullurl":    "isFullURL",
	"full_url":   "isFullURL",
	"activeURL":  "isActiveURL",
	"activeUrl":  "isActiveURL",
	"active_url": "isActiveURL",
	"uuid":       "isUUID",
	"UUID":       "isUUID",
	"uuid3":      "isUUID3",
	"UUID3":      "isUUID3",
	"uuid4":      "isUUID4",
	"UUID4":      "isUUID4",
	"uuid5":      "isUUID5",
	"UUID5":      "isUUID5",
	"cnMobile":   "isCnMobile",
	"cn_mobile":  "isCnMobile",
	// file system
	"path_exists": "pathExists",
	"pathExist":   "pathExists",
	"path_exist":  "pathExists",
	"filePath":    "isFilePath",
	"filepath":    "isFilePath",
	"local_file":  "isFilePath",
	"dirPath":     "isDirPath",
	"local_dir":   "isDirPath",
	"unixPath":    "isUnixPath",
	"unix_path":   "isUnixPath",
	"winPath":     "isWinPath",
	"win_path":    "isWinPath",
	// date
	"date":     "isDate",
	"gtDate":   "afterDate",
	"gt_date":  "afterDate",
	"ltDate":   "beforeDate",
	"lt_date":  "beforeDate",
	"gteDate":  "afterOrEqualDate",
	"gte_date": "afterOrEqualDate",
	"lteDate":  "beforeOrEqualDate",
	"lte_date": "beforeOrEqualDate",
	// uploaded file
	"img":          "isImage",
	"image":        "isImage",
	"upload_image": "isImage",
	"file":         "isFile",
	"upload_file":  "isFile",
	"mime":         "inMimeTypes",
	"mimes":        "inMimeTypes",
	"mimeType":     "inMimeTypes",
	"mime_type":    "inMimeTypes",
	"mimeTypes":    "inMimeTypes",
	"mime_types":   "inMimeTypes",
	// field compare
	"eq_field":  "eqField",
	"ne_field":  "neField",
	"neqField":  "neField",
	"neq_field": "neField",
	"gt_field":  "gtField",
	"gte_field": "gteField",
	"lt_field":  "ltField",
	"lte_field": "lteField",
	// requiredXXX
	"required_if":          "requiredIf",
	"required_unless":      "requiredUnless",
	"required_with":        "requiredWith",
	"required_with_all":    "requiredWithAll",
	"required_without":     "requiredWithout",
	"required_without_all": "requiredWithoutAll",
	// other
	"defaults":     "default",
	"not_contains": "notContains",
}
