package cn.pluss.platform.aop;


import cn.hutool.core.date.DateUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

/**
 * @author DJH
 */
@Aspect
@Component
public class TrimAspect {

    private static final String PATTERN_COMPILE = "[\\s\\t\\n\\r]*";

    // 定义切点
    // 记录后台接口的操作记录
    // 拦截Controller所在的包
    @Pointcut("execution(* cn.pluss.platform.controller..*.*(..))")
    public void executionService() {
    }

    @Around("executionService()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        // 数据校验注解优先于此AOP执行
        //重点 这里就是获取@RequestBody参数的关键  调试的情况下 可以看到arr变量已经获取到了请求的参数
        Object[] arr = pjp.getArgs();
        for (int i = 0; i < arr.length; ++i) {
            if (arr[i] instanceof HttpServletRequest) {
                // 特殊处理
                HttpServletRequest request = (HttpServletRequest) arr[i];
                Map<String, String[]> m = request.getParameterMap();
                Map<String, String[]> newM = new HashMap<>();
                if (m != null) {
                    for (Map.Entry<String, String[]> entry : m.entrySet()) {
                        String key = entry.getKey();
                        String[] value = entry.getValue();
                        if (value == null) {
                            continue;
                        }
                        for (int j = 0; j < value.length; ++j) {
                            String temp = "";
                            if (value[i] != null) {
                                temp = value[i].replaceAll(PATTERN_COMPILE, "");
                            }
                            value[i] = temp.length() == 0 ? null : temp;
                        }
                        newM.put(key, value);
                    }
                }

                request.setAttribute("The-result-after-removing-the-space", newM);
                arr[i] = request;
            } else {
                if (arr[i] != null) {
                    // 考虑到类里面还有类 这里采用递归的方式处理
                    arr[i] = dfs(arr[i].getClass(), arr[i]);
                }
            }
        }

        // 把 arr 放回去即可改变参数的值
        return pjp.proceed(arr);
    }

    private Object dfs(Class<?> aClass, Object object) throws IllegalAccessException {
        if (object == null) {
            return null;
        }

        // 如果是Java的基本数据类型就不需要继续递归了
        if (isPrimitive(aClass)) {
            if (!(object instanceof String)) {
                return object;
            }

            try {
                DateUtil.parseDate(((String) object));
                return object;
            } catch (Exception e) {
                // 非时间字符串
                String temp = ((String) object).replaceAll(PATTERN_COMPILE, "");
                return temp.length() == 0 ? null : temp;
            }
        }

        // 返回类所有字段
        // 注意： 会返回静态字段
        // 不要在Dto、Vo定义静态属性
        // 没有获取父类属性 可通过 “object.getClass().getSuperclass()” 获取
        for (Field item : object.getClass().getDeclaredFields()) {
            // static 和 final 修饰的字段忽略
            if (Modifier.isStatic(item.getModifiers())) {
                continue;
            }
            // 设置可见性
            item.setAccessible(true);
            // 递归处理
            item.set(object, dfs(item.getType(), item.get(object)));
        }
        return object;
    }

    // 判断是否为Java的基本类型或包装类
    // java.lang.* java.util.* 存放着Java的基本数据类型的包装类和集合类
    // 基本数据类型和包装类是JVM虚拟机运行需要的类，已嵌入到JVM内核
    // 不需要继承ClassLoader 用户自定义的需要
    private boolean isPrimitive(Class<?> aClass) {
        return aClass != null && aClass.getClassLoader() == null;
    }

}
