package com.emr.controller; /**
 * <p>Title: LogAopAction.java</p>
 * <p>Description: 操作日志Controller</p>
 */

import com.emr.annotation.OptionalLog;
import com.emr.entity.emrLog.Emr_Log;
import com.emr.service.emrLog.LogService;
import com.emr.util.ExceptionPrintUtil;
import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

@Aspect
@Component
public class LogAopAction {
    // 注入service,用来将日志信息保存在数据库
    @Resource
    private LogService logService;

    // 配置接入点，即为所要记录的action操作目录
    @Pointcut("@annotation(com.emr.annotation.OptionalLog)")
    private void controllerAspect() {
    }

    @Around("controllerAspect()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                .getRequest();
        // 拦截的实体类，就是当前正在执行的controller
        Object target = pjp.getTarget();
        // 拦截的方法名称。当前正在执行的方法
        String methodName = pjp.getSignature().getName();
        // 拦截的放参数类型
        Signature sig = pjp.getSignature();
        MethodSignature msig = null;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        Class[] parameterTypes = msig.getMethod().getParameterTypes();

        Object object = null;
        // 获得被拦截的方法
        Method method = null;
        try {
            method = target.getClass().getMethod(methodName, parameterTypes);
        } catch (NoSuchMethodException | SecurityException e1) {
            ExceptionPrintUtil.printException(e1);
            e1.printStackTrace();
        }
        if (null != method) {
            //插入表操作
            insertLog(method,pjp);
        }

        object = pjp.proceed();
        //接受客户端的数据
        Map<String,String[]> map = request.getParameterMap();
         // 解决获取参数乱码
        Map<String,String[]> newmap = new HashMap<String,String[]>();
        for(Map.Entry<String, String[]> entry : map.entrySet()){
            String name = entry.getKey();
            String[] values = entry.getValue();

            if(values==null){
                newmap.put(name, new String[]{});
                continue;
            }
            String[] newvalues = new String[values.length];
            for(int i=0; i<values.length;i++){
                String value = values[i];
                value = new String(value.getBytes("iso8859-1"),request.getCharacterEncoding());
                newvalues[i] = value; //解决乱码后封装到Map中
            }
            newmap.put(name, newvalues);
        }
        return object;
    }

    //对象字段转数据库字段
    private static String propertyToField(String property) {
        if (StringUtils.isEmpty(property)) {
            return "";
        }
        if (property.length() == 1) {
            return property.toLowerCase();
        }

        char[] chars = property.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < chars.length; i++) {
            char c = chars[i];
            if (i == 0) {
                sb.append(StringUtils.lowerCase(CharUtils.toString(c)));
            } else {
                if (CharUtils.isAsciiAlphaUpper(c)) {
                    sb.append("_").append(StringUtils.lowerCase(CharUtils.toString(c)));
                } else {
                    sb.append(c);
                }
            }
        }
        return sb.toString();
    }
    private void insertLog(Method method,ProceedingJoinPoint pjp) {
        //日志实体对象
        Emr_Log logBo = new Emr_Log();
        // 获取方法（此为自定义注解）
        OptionalLog op = method.getAnnotation(OptionalLog.class);
        String module = op.module();
        // 拦截的方法参数
        //判断操作类型
        if (StringUtils.isNoneBlank(module)) {
            Object[] args = pjp.getArgs();
            try {
                if (null != args && StringUtils.isNotBlank(op.fieldName())) {
                    if (("新增".equals(module)) || "修改".equals(module) || "保存".equals(module)) {
                        Object obj = args[0];
                        //通过反射获取值
                        Class c = obj.getClass();
                        // 获取该类的成员变量
                        Field f = c.getDeclaredField(op.fieldName());
                        // 取消语言访问检查
                        f.setAccessible(true);
                        logBo.setRemark(f.get(obj).toString());
                    }
                    if ("删除".equals(module)) {
                        String tableName = op.tableName();
                        String fieldName = op.fieldName();
                        fieldName = propertyToField(fieldName);
                        DefaultParameterNameDiscoverer discover = new DefaultParameterNameDiscoverer();
                        String[] parameterNames = discover.getParameterNames(method);
                        //拼接查询语句
                        StringBuilder sqlWhere = new StringBuilder();
                        if (args.length == 1) {
                            //一个参数如id
                            assert parameterNames != null;
                            sqlWhere.append(" ").append(propertyToField(parameterNames[0])).append(" = '").append(args[0]).append("'");
                        } else {
                            String regexp = "\'";
                            for (int i = 0; i < args.length; i++) {
                                String fieldValue = (String)args[i];
                                fieldValue = fieldValue.replaceAll(regexp, "");
                                if (i != args.length - 1) {
                                    assert parameterNames != null;
                                    sqlWhere.append(" ").append(propertyToField(parameterNames[i])).append(" = '").append(fieldValue).append("' AND ");
                                } else {
                                    sqlWhere.append(" ").append(propertyToField(parameterNames[i])).append(" = '").append(fieldValue).append("'");
                                }
                            }
                        }
                        Map<String, Object> obj = logService.selectObjectByKey(tableName, sqlWhere.toString());
                        if(obj != null){
                            logBo.setRemark(obj.get(fieldName).toString());
                        }
                    }
                }
                // 获取注解的modules 设为操作模块
                logBo.setLogTitle(module);
                // 获取注解的methods 设为执行方法
                logBo.setLogContent(op.methods());
                // 添加到数据库
                logService.insert(logBo);
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException();
                }
        }
    }
}