package org.zstack.utils.verify;

import org.zstack.utils.*;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class ParamValidator {
    private static Set<Class<? extends Verifiable>> verifiableClasses = BeanUtils.reflections.getSubTypesOf(Verifiable.class);
    private static Map<Class<? extends Verifiable>, Map<Field, Param>> verifiableParams = verifiableClasses.stream()
            .collect(Collectors.toMap(clz -> clz,
                    clz -> FieldUtils.getAnnotatedFields(Param.class, clz).stream()
                            .collect(Collectors.toMap(field -> field, field -> field.getAnnotation(Param.class)))
            ));

    public static void validate(Verifiable verifiable) throws IllegalAccessException {
        StringBuilder errorSb = new StringBuilder();
        for (Map.Entry<Field, Param> entry : verifiableParams.get(verifiable.getClass()).entrySet()) {
            Field f = entry.getKey();
            Param param = entry.getValue();

            f.setAccessible(true);
            Object value = f.get(verifiable);
            if (param.required() && value == null) {
                errorSb.append(String.format("field[%s] cannot be null.", f.getName()));
            }

            if (value != null && value instanceof String && !param.noTrim()) {
                f.set(verifiable, ((String) value).trim());
            }

            if (value != null && param.numberRange().length > 0 && TypeUtils.isTypeOf(value, Integer.TYPE, Integer.class, Long.TYPE, Long.class)) {
                DebugUtils.Assert(param.numberRange().length == 2, String.format("invalid field[%s], Param.numberRange must have and only have 2 items.", f.getName()));
                long low = param.numberRange()[0];
                long high = param.numberRange()[1];
                long val = ((Number) value).longValue();
                if (val < low || val > high) {
                    errorSb.append(String.format("field[%s] must be in range of [%s, %s].", f.getName(), low, high));
                }
            }

            if (value != null && param.maxLength() != Integer.MAX_VALUE && (value instanceof String)) {
                String str = (String) value;
                if (str.length() > param.maxLength()) {
                    errorSb.append(String.format("field[%s] of message[%s] exceeds max length of string. expected was <= %s, actual was %s.",
                            f.getName(), verifiable.getClass().getName(), param.maxLength(), str.length()));
                }
            }

            if (value != null && param.minLength() != 0 && (value instanceof String)) {
                String str = (String) value;
                if (str.length() < param.minLength()) {
                    errorSb.append(String.format("field[%s] of message[%s] less than the min length of string. expected was >= %s, actual was %s.",
                            f.getName(), verifiable.getClass().getName(), param.minLength(), str.length()));
                }
            }

            if (value != null && value instanceof String && param.resourceType() != Object.class && !StringDSL.isZStackUuid(((String) value).trim())) {
                errorSb.append(String.format("field[%s] is not a valid uuid.", f.getName()));
            }
        }

        if (errorSb.length() != 0) {
            throw new IllegalArgumentException(errorSb.toString());
        }
    }
}

@@ -87,16 +87,67 @@
 .Field;%0A
+import java.util.ArrayList;%0Aimport java.util.List;%0A
 import j
@@ -857,49 +857,45 @@
     
+List%3C
 String
-Builder
+%3E
  error
-Sb
+s
  = new 
-StringBuilder
+ArrayList%3C%3E
 ();%0A
@@ -1231,32 +1231,28 @@
        error
-Sb.appen
+s.ad
 d(String.for
@@ -2013,32 +2013,28 @@
        error
-Sb.appen
+s.ad
 d(String.for
@@ -2365,32 +2365,28 @@
        error
-Sb.appen
+s.ad
 d(String.for
@@ -2834,32 +2834,28 @@
        error
-Sb.appen
+s.ad
 d(String.for
@@ -3276,16 +3276,12 @@
 rror
-Sb.appen
+s.ad
 d(St
@@ -3382,29 +3382,25 @@
 if (
+!
 error
-Sb.length() != 0
+s.isEmpty()
 ) %7B%0A
@@ -3450,25 +3450,31 @@
 ion(
-errorSb.toString(
+String.join(%22 %22, errors
 ));%0A

add space between error Resolves ZSTAC-16134