package cn.myapps.runtime.excutor.async;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import cn.myapps.common.dao.IRuntimeDAO;
import cn.myapps.common.model.ValueObject;
import cn.myapps.runtime.common.dao.WrapConnection;
import cn.myapps.common.util.cache.EhcacheProvider;
import cn.myapps.common.util.cache.IMyCache;
import cn.myapps.common.util.cache.IMyElement;
import cn.myapps.common.util.cache.MyCacheManager;


/**
 * 异步处理器，只有明确知道是安全的情况下，才启用异步处理器提升性能，目前包括：
 * 
 * 1 - DocumentAuthor信息
 * 2 - DocumentLog信息
 * 3 - DocumentHeader
 * 4 - 流程历史 
 * 
 * @author Jarod
 *
 */
@Aspect
@Component
public class RelationHISDAOAspect {
	private Logger logger = LoggerFactory.getLogger(RelationHISDAOAspect.class);

	private final static String CACHE_KEY = "RUNTIME_DAO_CACHE_KEY";

	@Autowired
	private RuntimeDaoCommandDispatch commandExecutor;

	/**
	 * @Description: 定义切入点
	 */
	@Pointcut("(execution(public * cn.myapps.runtime.workflow.storage.runtime.dao.AbstractRelationHISDAO.*(..)))")
	public void pointCut() {
	}
	
	/**
	 * @Description: 环绕通知,环绕增强，相当于MethodInterceptor
	 */
	@Around("pointCut()")
	public Object around(ProceedingJoinPoint pjp) {
		try {
			String methodName = pjp.getSignature().getName();

			if (methodName.equals("getConnection") || methodName.equals("setConnection")) {
				return pjp.proceed();
			}
			
			Object[] args = pjp.getArgs();

//			IRuntimeDAO thisObj = (IRuntimeDAO) pjp.getThis();
			IRuntimeDAO thisObj = (IRuntimeDAO) pjp.getTarget();
			String typeName = thisObj.getClass().getName().split("[$][$]")[0];//处理cglib
			WrapConnection wconn = thisObj.getConnection();

			String signLongString = pjp.getSignature().toString();
			int pos = 	signLongString.lastIndexOf(".");
			String signString = signLongString.substring(pos + 1, signLongString.length());
			logger.debug("MethodInterceptor ARROUND $${}--{}",pjp.getSignature(), signString);
			
			EhcacheProvider provider = (EhcacheProvider) MyCacheManager.getProviderInstance();
			IMyCache iMyCache = provider.getCache(CACHE_KEY);
			if (iMyCache == null) {
				iMyCache = provider.createCache(CACHE_KEY, 50000, false, false, 24 * 60 * 60, 24 * 60 * 60);
			}

			Object o = null;
			ValueObject vo = null;
			String key = null;
			switch (signString) {
			case "create(ValueObject)":// 创建-异步处理
				asyncExecMethod(pjp, methodName, args, typeName, wconn);
				vo = (ValueObject) args[0];
				iMyCache.put(vo.getId(), vo);
				break;
			case "update(ValueObject)":// 更新-异步处理
				asyncExecMethod(pjp, methodName, args, typeName, wconn);
				vo = (ValueObject) args[0];
				iMyCache.put(vo.getId(), vo);
			case "remove(String)":// 移除-异步处理
				asyncExecMethod(pjp, methodName, args, typeName, wconn);
				key = (String) args[0];
				iMyCache.remove(key);
				break;
			case "find(String)":// 创建-异步处理
				key = (String) args[0];
				IMyElement element = iMyCache.get(key);
				o = element == null ? null : element.getValue();
				if (element == null) {
					o = pjp.proceed();
					iMyCache.put(key, o);// 加回缓存
				}
				break;
			case "removeByDocument(String)":
				asyncExecMethod(pjp, methodName, args, typeName, wconn);
				key = (String) args[0];
				iMyCache.remove(key);
				break;
			default://其他方法
				o = pjp.proceed();
				break;
			}
			return o;

		} catch (Throwable e) {
			logger.error(e.getMessage());
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 当线程变量中的groupcommand被初始化后采用异步执行，否则同步执行
	 * @param pjp
	 * @param methodName
	 * @param args
	 * @param typeName
	 * @param wconn
	 * @throws Throwable
	 */
	private void asyncExecMethod(ProceedingJoinPoint pjp, String methodName, Object[] args, String typeName,
			WrapConnection wconn) throws Throwable {
		if (RuntimeDaoCommandDispatch.initialized()) {
			commandExecutor.addToExecGroup(new RuntimeDaoCommand(typeName, methodName, args, wconn.getApplicationId()));					
		}
		else {
			pjp.proceed();
		}
	}

}