package ir.iais.utilities.javautils.validators.annotations

import java.util.*
import javax.validation.Constraint
import javax.validation.ConstraintValidator
import javax.validation.ConstraintValidatorContext
import javax.validation.Payload
import kotlin.reflect.KClass

/**
 * Validation annotation to globalValidate that 2 fields have the same value. An array of fields and
 * their matching confirmation fields can be supplied.
 *
 *
 * Example, compare 1 pair of fields: @FieldMatch(first = "password", second = "confirmPassword",
 * message = "The password fields must match")
 *
 *
 * Example, compare more than 1 pair of fields: @FieldMatch.List({ @FieldMatch(first =
 * "password", second = "confirmPassword", message = "The password fields must
 * match"), @FieldMatch(first = "email", second = "confirmEmail", message = "The email fields must
 * match")})
 */
@Target(AnnotationTarget.FIELD)
//@Retention(RUNTIME)
@kotlin.annotation.Retention
//@Repeatable(List::class)
@Repeatable
@Constraint(validatedBy = [RequiredValidator::class])
@MustBeDocumented
annotation class Required(val message: String = NonEmptyValidator.MESSAGE,
                          val groups: Array<KClass<*>> = [],
                          val payload: Array<KClass<Payload>> = []
)

open class RequiredValidator : ConstraintValidator<Required, Any?> {
    
    override fun initialize(constraintAnnotation: Required) {
    }
    
    override fun isValid(value: Any?, context: ConstraintValidatorContext): Boolean = hasValue(value)
    
    private fun hasValue(obj: Any?): Boolean = when (obj) {
        null -> false
        is String -> obj.isNotEmpty()
        is Collection<*> -> obj.isNotEmpty()
        is Optional<*> -> obj.isPresent
        is Enum<*> -> obj.name.toUpperCase() != "UNKNOWN"
        else -> true
    }
    
    companion object {
        
        const val MESSAGE = "error.required"
    }
}