package com.philisense.www.dynamic.druid.aop;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.philisense.www.dynamic.druid.conf.DynamicDataSource;
import com.philisense.www.dynamic.druid.conf.DynamicDataSourceContextHolder;
import com.philisense.www.dynamic.druid.conf.DynamicDruidDataSourceTypeEnum;

import java.lang.reflect.Method;
 
/**
 * 动态数据源AOP切面
 */
@Aspect
@Order(-1)
@Component
public class DynamicDataSourceAspect {
 
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    
    @Autowired
    @Qualifier("dynamicDataSource")
    private DynamicDataSource dynamicDataSource;
        
    
    @Pointcut("!@annotation(com.philisense.www.dynamic.druid.aop.DruidAopDynamicDataSource) " +
            "&& (execution(* com.philisense.www.dao..*.select*(..)) " +
            "|| execution(* com.philisense.www.dao..*.query*(..)) " +
            "|| execution(* com.philisense.www.dao..*.count*(..)) " +
            "|| execution(* com.philisense.www.dao..*.get*(..))) " +
            "|| execution(* org.activiti.engine.impl.persistence.entity.data..*.find*(..))) " +
            "|| execution(* org.activiti.engine.impl.persistence.entity.data..*.get*(..))) " +
            "|| execution(* org.activiti.engine.impl.persistence.entity.data..*.select*(..))) " +
            " ")
    public void readPointcut() {
    	
    }

    @Pointcut("@annotation(com.philisense.www.dynamic.druid.aop.DruidAopDynamicDataSource) " +
            "|| execution(* com.philisense.www.dao..*.delete*(..)) " +
            "|| execution(* com.philisense.www.dao..*.insert*(..)) " +
            "|| execution(* com.philisense.www.dao..*.update*(..)) " +
            "|| execution(* com.philisense.www.dao..*.save*(..)) " +
            "|| execution(* com.philisense.www.dao..*.merge*(..)) " +
            "|| execution(* com.philisense.www.dao..*.remove*(..))"+
            "|| execution(* org.activiti.engine.impl.persistence.entity.data..*.create*(..))) " +
            "|| execution(* org.activiti.engine.impl.persistence.entity.data..*.insert*(..))) " +
            "|| execution(* org.activiti.engine.impl.persistence.entity.data..*.update*(..))) " +
            "|| execution(* org.activiti.engine.impl.persistence.entity.data..*.delete*(..))) " +
            "|| execution(* org.activiti.engine.impl.persistence.entity.data..*.clear*(..))) " +
            "|| execution(* org.activiti.engine.impl.persistence.entity.data..*.reset*(..))) " +
            " ")
    public void writePointcut() {
    	
    }

    @Before("readPointcut()")
    public void beforeRead(JoinPoint point) {    	
        Object target = point.getTarget();
        String method = point.getSignature().getName();
        Class<?> classz = target.getClass();// 获取目标类
        Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
                .getMethod().getParameterTypes();
        try {
            Method m = classz.getMethod(method, parameterTypes);
            //System.err.println("6.method :{}"+m.getName() );
            
        } catch (Exception e) {
            logger.error("get datasource error ",e);
        }
    	DynamicDataSourceContextHolder.setSlaveDataSourceType(dynamicDataSource);
    	
    }

    @Before("writePointcut()")
    public void beforeWrite(JoinPoint point) {
        Object target = point.getTarget();
        String method = point.getSignature().getName();
        Class<?> classz = target.getClass();// 获取目标类
        Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
                .getMethod().getParameterTypes();
        try {
            Method m = classz.getMethod(method, parameterTypes);
            //System.err.println("5.method :{}"+m.getName() );
            if (m != null && m.isAnnotationPresent(DruidAopDynamicDataSource.class)) {
            	DruidAopDynamicDataSource data = m.getAnnotation(DruidAopDynamicDataSource.class);
                //logger.info("method :{},datasource:{}",m.getName() ,data.value());
                DynamicDataSourceContextHolder.setMasterDataSourceType();// 数据源放到当前线程中
            }else if (StringUtils.startsWithAny(method, "delete", "insert", "update", "save", "merge", "remove")) {
            	DynamicDataSourceContextHolder.setMasterDataSourceType();// 数据源放到当前线程中
             }
        } catch (Exception e) {
            logger.error("get datasource error ",e);
            //默认选择master
            DynamicDataSourceContextHolder.setMasterDataSourceType();// 数据源放到当前线程中
        }
    }
    
    @AfterReturning("readPointcut()")
    public void afterReadPointcut(JoinPoint point) {
    	DynamicDataSourceContextHolder.clearDataSourceType();;
    }
    
    @AfterReturning("writePointcut()")
    public void afterWritePointcut(JoinPoint point) {
    	DynamicDataSourceContextHolder.clearDataSourceType();;
    }    
 
}
