package com.usoftchina.bi.server.aspect;

import com.usoftchina.bi.core.utils.GetTokenDataUtil;
import com.usoftchina.bi.server.model.pojo.annotation.Log;
import com.usoftchina.bi.server.service.common.MessageLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * Log注解处理类,用于记录操作日志(保存/更新/删除)
 * @Author chenwei
 * @Date 2019-04-26
 */
@Aspect
@Component
public class LogAspect {

    private ExpressionParser parser = new SpelExpressionParser();

    private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();

    @Autowired
    private MessageLogService messageLogService;

    @Pointcut("@annotation(com.usoftchina.bi.server.model.pojo.annotation.Log)")
    public void Log(){

    }

    @After(value = "Log()")
    public void writeLog(JoinPoint joinPoint){
        Object[] arguments = joinPoint.getArgs();
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        Log log = method.getAnnotation(Log.class);
        String content = log.value(), token = log.token(), module = log.module(), name = log.name();
        String contentValue = parseSpEL(method, arguments, content, String.class, content);
        String nameValue = parseSpEL(method, arguments, name, String.class, null);
        String tokenValue = parseSpEL(method, arguments, token, String.class, null);
        String methodName = method.getName();
        String username = GetTokenDataUtil.getTokenData(tokenValue).get("name");
        if (methodName.startsWith("save")) {
            // 记录新增日志
            messageLogService.save(module, nameValue, username, contentValue);
        }else if (methodName.startsWith("update")) {
            // 记录更改日志
            messageLogService.update(module, nameValue, username, contentValue);
        }else if (methodName.startsWith("delete")) {
            // 记录删除日志
            messageLogService.delete(module, nameValue, username, contentValue);
        }
    }

    /**
     * 解析SpringEL表达式的值
     * @param method
     * @param arguments
     * @param spel
     * @param Clazz
     * @param defaultResult
     * @param <T>
     * @return
     */
    private <T> T parseSpEL(Method method, Object[] arguments, String spel, Class<T> Clazz, T defaultResult){
        String[] params = discoverer.getParameterNames(method);
        EvaluationContext context = new StandardEvaluationContext();
        for (int i = 0, len = params.length; i < len; i++) {
            context.setVariable(params[i], arguments[i]);
        }
        try {
            Expression expression = parser.parseExpression(spel);
            return expression.getValue(context, Clazz);
        }catch (Exception e) {
            return defaultResult;
        }
    }

}
