package com.yc.education.aop;


import com.google.zxing.NotFoundException;
import org.apache.ibatis.javassist.*;
import org.apache.ibatis.javassist.bytecode.CodeAttribute;
import org.apache.ibatis.javassist.bytecode.LocalVariableAttribute;
import org.apache.ibatis.javassist.bytecode.MethodInfo;
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * @author YaoShiHang
 * @Date 13:44 2017-11-24
 */
@Component
@Aspect
class LogAop {

    private Logger log = Logger.getLogger(getClass());

    public static final  String  edp="execution(* com.yc.education.service.*.*(..)) || execution(* com.yc.education.service.impl.*.*(..)) ";

    @Around(edp)
    public Object timeAround(ProceedingJoinPoint joinPoint){
        Object obj = null;
        Object [] args=joinPoint.getArgs();
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        long startTime = System.currentTimeMillis();
        try {
            String classType = joinPoint.getTarget().getClass().getName();
            Class<?> clazz = Class.forName(classType);
            String clazzName = clazz.getName();
            String methodName = joinPoint.getSignature().getName(); //获取方法名称
            Object[] argss = joinPoint.getArgs();//参数
            //获取参数名称和值
            Map<String,Object > nameAndArgs = getFieldsName(this.getClass(), clazzName, methodName,args);
            log.info("参数 "+nameAndArgs.toString());
            System.out.println(nameAndArgs.toString());
            obj = joinPoint.proceed(args);
        } catch (Throwable e) {
            log.info("=====异常通知开始=====");
            log.info("异常代码:" + e.getClass().getName());
            log.info("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
            log.error("统计某方法执行耗时环绕通知出错", e);
        }
        // 获取执行的方法名
        long endTime = System.currentTimeMillis();
        String ip = request.getRemoteAddr();
        log.info("*****开始记录日志*****");
        log.info("IP:"+ip+",执行了："+joinPoint.getSignature().getName()+",耗时："+(endTime - startTime)+"ms");
        return obj;
    }

    private Map<String,Object> getFieldsName(Class cls, String clazzName, String methodName, Object[] args) throws NotFoundException, org.apache.ibatis.javassist.NotFoundException {
        Map<String,Object > map=new HashMap<String,Object>();

        ClassPool pool = ClassPool.getDefault();
        //ClassClassPath classPath = new ClassClassPath(this.getClass());
        ClassClassPath classPath = new ClassClassPath(cls);
        pool.insertClassPath(classPath);

        CtClass cc = pool.get(clazzName);
        CtMethod cm = cc.getDeclaredMethod(methodName);
        MethodInfo methodInfo = cm.getMethodInfo();
        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
        if (attr == null) {
            // exception
        }
        // String[] paramNames = new String[cm.getParameterTypes().length];
        int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
        for (int i = 0; i < cm.getParameterTypes().length; i++){
            map.put( attr.variableName(i + pos),args[i]);//paramNames即参数名
        }

        //Map<>
        return map;
    }
}
