package com.wechat.global;

import java.lang.reflect.Field;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import com.wechat.common.CommonHelper;

/**
 * log each method for input and output
 * 
 * @author xueh
 */
@Aspect
@Component
public class GlobalLogAspect {

    /**
     * Log
     */
    private static final Log logger = LogFactory.getLog(GlobalLogAspect.class);

    /**
     * CommonHelper
     */
    @Autowired
    private CommonHelper     commonHelper;

    @Pointcut("execution(* com.wechat.controller..*.*(..))" 
            + " || execution(* com.wechat.service..*.*(..))" + " || execution(* com.wechat.dao..*.*(..))")
    public void globalLog() {

    }

    /**
     * executed after return log each method for input and output
     * 
     * @param joinPoint JoinPoint
     * @param returnValue Object
     */
    @AfterReturning(pointcut = "globalLog()", returning = "returnValue")
    public void doAfterReturning(JoinPoint joinPoint, Object returnValue) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes()).getRequest();
//        HttpServletRequest request = WebContext.getInstance().getRequest();
        try {
            logger.info("请求IP:" + commonHelper.getIRealIPAddr(request));

            logger.info("请求时间:" + new Date());
            logger.info("请求方法:"
                    + (joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName() + "()"));

            StringBuilder param = new StringBuilder();
            if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
                for (int i = 0; i < joinPoint.getArgs().length; i++) {
                    Object pObject = joinPoint.getArgs()[i];
                    param.append(getFieldsValues(pObject));
                }
            }
            logger.info("请求参数:" + param);
            logger.info("返回值为:" + getFieldsValues(returnValue));
        }
        catch (Exception e) {
            logger.error(e.getMessage());
        }
    }

    /**
     * only executed when exception
     * 
     * @param joinPoint JoinPoint
     * @param e Exception
     */
    @AfterThrowing(pointcut = "globalLog()", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Exception e) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes()).getRequest();
        try {
            logger.info("请求IP:" + commonHelper.getIRealIPAddr(request));

            logger.info("请求时间:" + new Date());
            logger.info("请求方法:"
                    + (joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName() + "()"));

            StringBuilder param = new StringBuilder();
            if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
                for (int i = 0; i < joinPoint.getArgs().length; i++) {
                    Object pObject = joinPoint.getArgs()[i];
                    param.append(getFieldsValues(pObject));
                }
            }
            logger.info("请求参数:" + param);
            if (e != null) {
                logger.info("出现异常:" + e.getMessage());
            }
        }
        catch (Exception ex) {
            logger.error(e.getMessage());
        }
    }

    /**
     * get the value of each fields of the object
     * 
     * @param pObject Object
     * @return String
     * @throws Exception Exception
     */
    private String getFieldsValues(Object pObject) throws Exception {
        StringBuilder param = new StringBuilder();
        if (pObject != null) {
            if (pObject instanceof String || pObject instanceof Integer || pObject instanceof Long
                    || pObject instanceof JSONArray || pObject instanceof JSONObject) {
                param.append(pObject.toString() + "; ");
            }
            else {
                Class<? extends Object> pClass = (Class<? extends Object>) pObject.getClass();

                //just for BaseOutDto, to get the error code and error message
                Class<? extends Object> superClass = (Class<? extends Object>) pClass.getSuperclass();
                if (superClass != null && superClass.getName().contains("BaseOutDto")) {
                    Field[] fs = superClass.getDeclaredFields();
                    for (int j = 0; j < fs.length; j++) {
                        Field f = fs[j];
                        f.setAccessible(true); //make the fields accessible
                        param.append(f.getName() + ":" + f.get(pObject) + "; ");
                    }
                }

                //get the value of the returned object
                Field[] fs = pClass.getDeclaredFields();
                for (int j = 0; j < fs.length; j++) {
                    Field f = fs[j];
                    f.setAccessible(true); //make the fields accessible
                    param.append(f.getName() + ":" + f.get(pObject) + "; ");
                }
            }
        }
        return param.toString();
    }
}
