/**
 *
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License. See License.txt in the project root for license information.
 *
 */

package com.microsoft.rest;

import com.fasterxml.jackson.annotation.JsonProperty;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

/**
 * ServiceClient is the abstraction for accessing REST operations and their payload data types.
 */
public class Validator {
    public static void validate(Object parameter) throws IllegalArgumentException {
        // Validation of top level payload is done outside
        if (parameter == null) {
            return;
        }

        Field[] fields = FieldUtils.getAllFields(parameter.getClass());
        for (Field field : fields) {
            field.setAccessible(true);
            JsonProperty annotation = field.getAnnotation(JsonProperty.class);
            Object property = null;
            try {
                property = field.get(parameter);
            } catch (IllegalAccessException e) {
                // Ignore inaccessible fields
            }
            if (property == null) {
                if (annotation != null && annotation.required()) {
                    throw new IllegalArgumentException(field.getName() + " is required and cannot be null.");
                }
            } else {
                try {
                    Class propertyType = property.getClass();
                    if (ClassUtils.isAssignable(propertyType, List.class)) {
                        List<?> items = (List<?>)property;
                        for (Object item : items) {
                            Validator.validate(item);
                        }
                    }
                    if (ClassUtils.isAssignable(propertyType, Map.class)) {
                        Map<?, ?> entries = (Map<?, ?>)property;
                        for (Map.Entry<?, ?> entry : entries.entrySet()) {
                            Validator.validate(entry.getKey());
                            Validator.validate(entry.getValue());
                        }
                    }
                    else if (!(ClassUtils.isPrimitiveOrWrapper(propertyType) ||
                            propertyType.isEnum() ||
                            ClassUtils.isAssignable(propertyType, LocalDate.class) ||
                            ClassUtils.isAssignable(propertyType, DateTime.class) ||
                            ClassUtils.isAssignable(propertyType, String.class))) {
                        Validator.validate(property);
                    }
                } catch (IllegalArgumentException ex) {
                    // Build property chain
                    throw new IllegalArgumentException(field.getName() + "." + ex.getMessage());
                }
            }
        }
    }

    public static void validate(Object parameter, ServiceCallback<?> serviceCallback) {
        try {
            validate(parameter);
        } catch (IllegalArgumentException ex) {
            serviceCallback.failure(new ServiceException(ex));
        }
    }
}

@@ -408,16 +408,45 @@
 lDate;%0A%0A
+import javax.xml.ws.Service;%0A
 import j
@@ -469,16 +469,16 @@
 .Field;%0A
-
 import j
@@ -701,31 +701,23 @@
  throws 
-IllegalArgument
+Service
 Exceptio
@@ -1242,37 +1242,38 @@
     
-// Ignore inaccessible fields
+throw new ServiceException(e);
 %0A   
@@ -1408,32 +1408,82 @@
       throw new 
+ServiceException(%0A                            new 
 IllegalArgumentE
@@ -1544,16 +1544,17 @@
  null.%22)
+)
 ;%0A      
@@ -2847,39 +2847,172 @@
 ch (
-IllegalArgumentException ex) %7B%0A
+ServiceException ex) %7B%0A                    IllegalArgumentException cause = (IllegalArgumentException)(ex.getCause());%0A                    if (cause != null) %7B%0A    
     
@@ -3063,32 +3063,36 @@
                 
+    
 throw new Illega
@@ -3081,24 +3081,78 @@
   throw new 
+ServiceException(%0A                                new 
 IllegalArgum
@@ -3188,18 +3188,21 @@
 + %22.%22 + 
+caus
 e
-x
 .getMess
@@ -3203,26 +3203,112 @@
 etMessage())
+)
 ;%0A
+                    %7D else %7B%0A                        throw ex;%0A                    %7D%0A
             
@@ -3496,31 +3496,23 @@
  catch (
-IllegalArgument
+Service
 Exceptio
@@ -3559,33 +3559,11 @@
 ure(
-new ServiceException(
 ex)
-)
 ;%0A  

Unify validator's exception